I wanted a frame with one TextArea and one Button.
When I press the button, the TextArea should show a food menu of 5 Pizzas, well it shows nothing at all, except for the console which shows
"Exception in thread "AWT-EventQueue-0"
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at de.kvwl.pizza.MainFrame.actionPerformed(MainFrame.java:54)"
In the method windowsStart() the objects exists and are adjustable.
In the actionPerformed()Method the objects are … kind of invisible, not existing?
public void windowStart()
{
MainFrame mFrame = new MainFrame();
PizzaReader2 test = new PizzaReader2();
pPizza = test.csvRead();
System.out.println("\n\n\n" + pPizza.get(0) + "\n\n\n");
f = new JFrame("Textfield");
b = new JButton("Menu");
jt = new JTextArea(10,10);
JPanel pTextArea = new JPanel();
b.addActionListener(mFrame);
pTextArea.add(jt);
pTextArea.add(b);
f.add(pTextArea);
f.setSize(300, 300);
f.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
//jt.setText("TestText");
System.out.println("\n\n\n" + pPizza.get(0) + "\n\n\n");
String s = e.getActionCommand();
if (s.equals("Menu"))
{
System.out.println("Button gedrückt");
//jt.setText("");
for (int i = 0; i < pPizza.size(); i++)
{
jt.append(pPizza.get(i)+"\n");
}
The TextArea should get the value of the ArrayList
Your exception occurs in : at de.kvwl.pizza.MainFrame.actionPerformed(MainFrame.java:54)
This action is linked during windowStart with b.addActionListener(mFrame);.
But What I see is that you pass another instance of MainFrame called mFrame as parameter (as an ActionListener). This mFrame never load the list with
pPizza = test.csvRead();
So in short, you have two instance MainFrame:
one created and use to call windowStart
one created in windowsStart and use to execute actionPerformed.
This last one never load the list of data. Explaining why your list is populated in windowStart but not in actionPerformed, you are actually using two distinct instance MainFrame with two list pPizza.
You can correct this by removing this second instance and use this, the first instance as an ActionListener
b.addActionListener(this);
Related
I am making a Yahtzee type program. It is for my final project in my Java class. I have a it broken up into multiple classes. The part I am having trouble with is between my ScoreSheet class and ScoreControl class.
ScoreSheet uses a method with a loop that adds an array of JButtons and adds action listeners to them. I then add the action listener to the ScoreControl class. However when I reference the array in the ActionPerformed, I don't get any output. Here is my relevant code:
From ScoreSheet: (the (sc) is the name of my ScoreControl)
public void setupUpperButtons(){
for(int i = 0; i<NUM_UPPER_CATEGORIES; i++){
upperCategories[i] = new JButton(upperNames[i]);
upperCategories[i].addActionListener(sc);
upperCategories[i].setFocusPainted(false);
}
When I try to reference a button from the array, (in the ScoreControl class) like so:
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == sheet.upperCategories[0]) {
System.out.println("You have pressed a button");
}
I don't get any output. The print is just to test if it's working, obviously different stuff will go there once I get it to work.
I just noticed that in my ScoreSheet, I have
ScoreControl=sc;
But in the constructor I do not have
sc = new ScoreControl;
But when I add that line in, I get a huge stack of StackOverflow error.
java.lang.StackOverflowError
at sun.applet.AppletSecurity.checkPackageAccess(AppletSecurity.java:281)
at sun.reflect.misc.ReflectUtil.checkPackageAccess(ReflectUtil.java:188)
at javax.swing.UIDefaults.getUIClass(UIDefaults.java:680)
at javax.swing.UIDefaults.getUI(UIDefaults.java:757)
at javax.swing.UIManager.getUI(UIManager.java:1016)
at javax.swing.JPanel.updateUI(JPanel.java:126)
at javax.swing.JPanel.<init>(JPanel.java:86)
at javax.swing.JPanel.<init>(JPanel.java:109)
at javax.swing.JPanel.<init>(JPanel.java:117)
at ScoreSheet.<init>(ScoreSheet.java:33)
at ScoreControl.<init>(ScoreControl.java:16)
at ScoreSheet.<init>(ScoreSheet.java:34)
at ScoreControl.<init>(ScoreControl.java:16)
at ScoreSheet.<init>(ScoreSheet.java:34) (these last two lines repeat many many times)
Here is each constructor:
from ScoreSheet:
public ScoreSheet(){
sc = new ScoreControl();
grid = new GridLayout(0, 1, 10, 3);
setupUpperSection();
setupLowerSection();
setupFields();
setupScorePanel();
setupScoreSheet();
}
From ScoreControl:
public ScoreControl() {
sheet = new ScoreSheet();
}
I am just starting work on my ScoreControl, so other stuff will go in there later but that's how they are currently.
Looks like a simple fix. You just need to pass the ScoreSheet instance to the ScoreControl constructor.
public ScoreSheet(){
sc = new ScoreControl(this);
grid = new GridLayout(0, 1, 10, 3);
setupUpperSection();
setupLowerSection();
setupFields();
setupScorePanel();
setupScoreSheet();
}
public ScoreControl(ScoreSheet _sheet) {
sheet = _sheet;
}
You can also do this in the opposite way ...
public ScoreSheet(ScoreControl _sc){
sc = _sc;
grid = new GridLayout(0, 1, 10, 3);
setupUpperSection();
setupLowerSection();
setupFields();
setupScorePanel();
setupScoreSheet();
}
public ScoreControl() {
sheet = new ScoreSheet(this);
}
But understand that the construction of ScoreControl is not complete while the ScoreSheet is being constructed. If any of the methods called in ScoreControl constructor reference sc, sc.sheet will not yet be initialized, because new ScoreSheet(this) has not yet returned a value.
Since ScoreControl constructor doesn't call any methods, it just stores a reference to ScoreSheet, I prefer the former method.
Here is what I am trying to do: I have a swing gui with two JFrames. The first has a JCheckBox and the second displays some text. Also the second has a javax.swing.Timer that is waiting for the checkbox in the first frame to be clicked. Once it is clicked, some more text is to be displayed. It works if I have only one condition (click the checkbox) and the condition is directly in the if-statement, like this:
javax.swing.Timer timer = new javax.swing.Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ( otherGUI.jCheckBox.isSelected() ){
//add some text to second JFrame
timer.stop();
}
}
});
Now for the twist: This should happen not only once, but multiple times. There is an ArrayList of timers, each with its own text and condition, one starting after the other. My problem is: If I store the conditions as strings in an ArrayList, they seem to be evaluated once at the start of the programme, so the condition from above stays false, even when I click the checkbox. Here is my actual code:
SomeGUI gui = new SomeGUI();
ArrayList<javax.swing.Timer> timer = new ArrayList<javax.swing.Timer>();
ArrayList<String> text = new ArrayList<String>();
ArrayList<String> cond = new ArrayList<String>();
text.add("some text");
cond.add("gui.jCheckBox.isSelected()");
text.add("some more text");
cond.add(new Condition("true"));
//etc.
for ( int i = 0; i < text.size() - 1; i++ ){
int j = i;//not sure why this trick is necessary. i doesn't work later on
timer.add( new javax.swing.Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean bool = false;
try{
bool = Boolean.parseBoolean( cond.get(j) );
}
catch(Exception ex){}
if ( bool ){
addText(p, text.get(j+1));
timer.get(j).stop();
timer.get(j+1).start();
}
}
}));
}
timer.get(0).start();
I already tried an ArrayList<Boolean> for the conditions to the same effect. The code above just represents my present state of trial and error.
I hope that I could make clear what I am trying to achieve. So how can I store boolean expressions in a list/array and have them evaluated in an if-statement again and again at runtime and not only once when the programme is started?
There is no simple "evaluation" of strings in Java. It is possible, but really not "java style". See Convert String to Code
One other option would be that your strings represent method names (which exist on a well known object); then you could use reflection to invoke that method based on the provided string. But also, pretty ugly.
Scenario: I have a series of jbuttons (created at runtime) and each of them has a number in his label. Buttons are created with this code:
for (int i = 1; i <= tablesNumber; i++) {
JButton button = new JButton(Integer.toString(i));
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Orders().setVisible(true);
}
});
jPanel1.add(button);
}
I need to pass to the class Orders the number of the button which fires the event, e.g. if the user clicks on button number 5 I need to pass the value 5 to Orders.
How can I do this?
Thanks.
From your question:
pass to the class Orders the number of the button which fires the event
You could just capture the loop iteration variable i so it can be used inside your anonymous event handler. For the sake of argument I have assumed you want to pass the number into the constructor, but you can use it however you like:
for (int i = 1; i <= tablesNumber; i++) {
final int t = i; // <-- NEW LINE HERE
JButton button = new JButton(Integer.toString(i));
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Orders(t).setVisible(true); // <-- USE t here however you need to
}
});
jPanel1.add(button);
}
Without final int t = i you may get the compiler error "Cannot refer to a non-final variable i inside an inner class defined in a different method". This is because a capture variable (i.e. a variable from an outer scope used inside an anonymous class' method must be final (or effectively final - this behaviour has changed slightly as of SE 8).
For my Java project I am creating buttons from strings stored in an array as such:
public class UserInterface implements ActionListener {
ArrayList<CardButton> currButtonList; // Current list of card buttons used
public void createAndShowGUI(String[] allCards){
//unrelated to question code
//for each String in allCards[]
for(int i=0; i<allCards.length; i++){
//Assign the button names relative to which card has is being created
String name = allCards[i];
CardButton button = new CardButton(name);
//add the button to the CardPanel
button.setFaceDown();
button.setBorderPainted(false);
int width = button.getWidth();
int height = button.getHeight();
button.setSize( new Dimension( width, height ) );
//button.setPreferredSize(new Dimension(150, 150));
CardPanel.add(button);
currButtonList.add(button);
}
}
//rest of creating the Panels, more unrelated to question code
Code complies but:
Exception in thread "main" java.lang.NullPointerException
at memory_game.GameFunction.(GameFunction.java:47)
Which is where I try to assign listeners to each object in the array list.
Am I correct in assuming that the ArrayList is not having the buttons added to it correctly?
If so, why? How can I make this work?
You need to instantiate your ArrayList<CardButton>. This is wrong (because it leaves currButtonList undefined, that is null) -
ArrayList<CardButton> currButtonList; // Current list of card buttons used
Try this instead
// Current list of card buttons used
List<CardButton> currButtonList = new ArrayList<CardButton>();
Or you could add this to your UserInterface constructor(s) -
currButtonList = new ArrayList<CardButton>(); // Instantiate the currButtonList.
Finally, as for your subject line question - you seem to be doing that correctly with these lines -
CardButton button = new CardButton(name); // Create a new CardButton instance.
currButtonList.add(button); // Add it to the list (currButtonList was null, not button)
Are you ever instantiating your ArrayList like
ArrayList<CardButton> currButtonList = new ArrayList<CardButton>();
I don't believe ArrayList is an intrinsic type that will work without instantiating it.
Your arrayList is not initialized, default is NULL. That is why you get null pointer exception when you try to add button to currentButtonList variable.
Initialize your array with empty list as below.
ArrayList<CardButton> currButtonList = new ArrayList<CardButton>(); // Current list of card buttons used
i create grid layout using DesignGridLayout java library (here).
in the sampe if create 3 column layout. using this code :
layout.row().add(new JButton("Button 1")).add(new JButton("Button 2")).add(new JButton("Button 3"));
or using method that return object :
layout.row().add(button()).add(button()).add(button());
...
...
public JButton button() {
return new JButton("Button");
}
The question is, how to create dynamically JButton value? May be name,icon or anything?
I already try my own code like this :
for (int i=0; i<4; i++) {
JButton button = new JButton();
layout.row().add(button).add(button).add(button);
}
it return :
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Do not add the same component twice
My purpose for different value in each component which added in panel is, i want to create gallery that populate
different image, and i load that images using looping, like this :
for(int i=0; i<files.length; i++) {
...
ImageIcon imgSource = new ImageIcon(new File(myPath));
JLabel labelGallery = new JLabel(imgSource);
...
}
Any solution?
Thanks before :)
In your example,
layout.row().add(button).add(button).add(button);
has the effect of attempting to add the same JButton instance to the row repeatedly.
In the example cited,
layout.row().grid().add(button()).add(button());
invokes an auxiliary method, button(), to create a new instance each time it appears:
public static JButton button() {
return new JButton("Button");
}
As mentioned by #trashgod, Swing does not allow to add the same component twice to a panel.
If you want to add several components, created within a loop, to the same row, you can do it as follows:
IRow row = layout.row().grid();
for (int i = 0; i < n; i++) {
JButton button = createButton(i);
row.add(button);
}
That will create only one row with n buttons inside.