Can you create on the fly references to JCheckBox objects? - java

I am not sure how to ask this. The program I am working on is done, but it seems like it has excessive code. Here is part of the code:
chkDef1 = new JCheckBox
if (chkDef1.isSelected()) {
actual = chkDef1.getText();
}
else if (chkDef2.isSelected()) {
actual = chkDef2.getText();
}
else if (chkDef3.isSelected()) {
actual = chkDef3.getText();
}
else {
actual = chkDef4.getText();
}
There are other areas where there is a lot of duplicate code with the chkDef1 - 4 checkboxes. What I would like to do is use a loop in the areas where the code is duplicated and then just use 1 assignment statement.
I've tried :
if(('chkDef' + counter).isSelected())
I've also tried assigning "'chkDef' + counter" to a String variable and then adding isSelected. Unfortunately I keep getting error messages.
I am a novice programmer so I do not know if what I want to do is possible or what it is called. If it is possible an explanation of how would be appreciated.

Simply create a list of checkboxes and iterate through it.
ArrayList<JCheckBox> checkboxes = new ArrayList<JCheckBox>();
//Init your checkboxes array.
for(JCheckbox chkbox :checkboxes)
{
if(chkbox.isSelected())
{
actual = chkbox.getText() ; break;
}
}
Although, there could be a JCheckbox group that does what you want.
Looks like you can use ButtonGroup and get the elements to iterate through it.

You could create an array that contains all the check boxes and then loop through the array...
JCheckBox[] boxes = new JCheckBox[] {chkDef1,chkDef2,chkDef3,chkDef4}
for (JCheckBox box : boxes) {
if (box.isSelected()) {
actual = box.getText();
break; // We don't want to loop unnecessarily
}
}
Equally, you could create a simple method that takes a variable number of arguments...
public String getCheckedItem(JCheckBox... boxes) {
String actual = null;
for (JCheckBox box : boxes) {
if (box.isSelected()) {
actual = box.getText();
break; // We don't want to loop unnecessarily
}
}
return actual;
}
And call it like...
String actual = getCheckItem(chkDef1, chkDef2, chkDef3, chkDef4);
Personally, I'd return the check box, but that's up to you
If you're only interested in maintaining a single selected check box (ie not allowing multiple check boxes to be selected) then you should seriously consider using JRadioButtons and ButtonGroup instead.
Otherwise you could collect ALL the selected checked boxes...
public JCheckBox[] getCheckedItem(JCheckBox... boxes) {
List<JCheckBox> selected = new ArrayList<JCheckBox>(boxes.length);
for (JCheckBox box : boxes) {
if (box.isSelected()) {
selected.add(box);
}
}
return selected.toArray(new JCheckBox[selected.size]);
}

Related

find JButton source in another ArrayList

I am trying to build a GUI application that will let the user to choose product by clicking the button. I hold products in an ArrayList and then use this ArrayList and for loop to create proper number of JButtons. When user clicks the button price of that product should appear in the TextField.
My problem is: how to find out which button was clicked? If I was using Array of Buttons (JButton button[] = new JButton[3]) I would find it in the loop:
if (target.equals(button[i]))...
But I can't figure out how to find it when I use ArrayList of products to create buttons. Any help would be well appreciated. Here's my code (I tried many approaches so I only post the one I started with - it finds only the last item in the ArrayList).
public void addStuff() {
stuffList.add(new Stuff("Lemon Haze", 15.00));
stuffList.add(new Stuff("OG Kush", 16.00));
stuffList.add(new Stuff("Strawberry Cough", 18.00));
for (int i = 0; i < stuffList.size(); i++) {
stuffButton = new JButton();
stuffPanel.add(stuffButton);
stuffButton.setText(stuffList.get(i).getName());
stuffButton.addActionListener(this);
}
}
public void actionPerformed(ActionEvent e) {
Object target = e.getSource();
for (int i = 0; i < stuffList.size(); i++) {
if (target == stuffButton) {
subtotalTextF.setText(stuffList.get(i).getPrice() + "");
}
}
}
Create a specific class for your ActionListener, and give it a reference to your Stuff - this way you can create a specific instance for each button that automatically links back to the correct instance of Stuff, without trying to search on the fly:
stuffButton.addActionListener(new StuffListener(stuffList.get(i));
...
private class StuffListener implements ActionListener {
private final Stuff myStuff;
public StuffListener(Stuff stuff) {
this.myStuff = stuff;
}
public void actionPerformed(ActionEvent e) {
subtotalTextF.setText(String.valueOf(myStuff.getPrice()));
}
}
Note that you can accomplish this with a bit less code using lambdas, but figured this is the clearest way to explain the logic, which is the same either way.
On a side note, based on the code you've posted, the reason it's only getting the last button is because you're comparing to stuffButton, which is not changed from the last instance after your initialization loop is done.

Problems with array changing elements

I am trying to change elements in an array to the word "empty" with a Jbutton and also add names through a Jtextfield if the in the selected position in the array says empty. For some reason I cant get it to work. here is the code don't know if I am missing something or I am just completely wrong
move = new JButton("Add Tennant");
window.add(move);
moveIn.addActionListener(this);
Tennant = new JTextField(FIELD_WIDTH);
nTennant.setText("Enter new name") ;
window.add(Tennant);
Tennant.addActionListener(this);
evict = new JButton("Evict");
window.add(evict);
moveIn.addActionListener(this);
different method:
if(e.getSource() == move)
{
if (occupant[selectedApartment].equals("empty"))
{
occupant[selectedApartment] = Tennant.getText();
}
}
if(e.getSource() == evict)
{
if(!occupant[selectedApartment].equals("Empty"))
{
occupant[selectedApartment] = "Empty";
}
}
The first thing that jumps out at me is you use occupant[selectedApartment] = "Empty"; to set an apartment empty, but use if (occupant[selectedApartment].equals("empty")) to test if an apartment is empty
"Empty" != "empty"
You could change
if (occupant[selectedApartment].equals("empty"))
to
if (occupant[selectedApartment].equals("Empty"))
or use
if (occupant[selectedApartment].equalsIgnoreCase("empty"))
or change
occupant[selectedApartment] = "Empty";
to
occupant[selectedApartment] = "empty";

Boolean expression should be evaluated at runtime in a timer, reacting to changes in the swing gui

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.

Get text from JRadioButton that isn't part of a ButtonGroup

My program is a GUI. I have this method where when a button is clicked. It populates the next screen with JRadioButtons dynamically.
private void setExamButtonActionPerformed(java.awt.event.ActionEvent evt)
{
if(evt.getActionCommand().equals("Set Exam"))
{
CardLayout cL = (CardLayout)cardPanels.getLayout();
cL.show(cardPanels, "setExamPanel");
}
try
{
//InputStream code
String theMessage = myObject.getMessage();
String delims = "(?=(0*([0-9]{1,2}|100)))";
String[] questions = theMessage.split(delims);
System.out.println(Arrays.toString(questions));
for (int j = 1; j < questions.length; j++)
{
settingQuestionBoxes = new JCheckBox(questions[j]);
settingQuestionTextField = new JTextField("");
jPanel1.add(settingQuestionBoxes);
jPanel1.add(settingQuestionTextField);
jPanel1.revalidate();
jPanel1.repaint();
}
//close streams and socket code
}
catch(Exception e)
{
System.out.println(e);
}
}
Then I have this other method from another screen where the data that is populated from the previous method goes to.
private void setExamQuestionButtonActionPerformed(java.awt.event.ActionEvent evt)
{
if(evt.getActionCommand().equals("Set Exam Question"))
{
ArrayList<JToggleButton> settingQuestionBoxes = new ArrayList<JToggleButton>();
for(JToggleButton questions: settingQuestionBoxes)
{
if(questions.isSelected())
{
System.out.println(questions.getActionCommand());
}
}
CardLayout cL = (CardLayout)cardPanels.getLayout();
cL.show(cardPanels, "instructorPanel");
}
}
So basically when i call this System.out.println(questions.getActionCommand()) I'm trying to see the text from the JRadiobutton that was clicked on.
Right now when I run the program and select a button. Nothing happens.
Put the buttons into a List<JToggleButton> such as an ArrayList<JToggleButton> and then iterate through the list when the information is needed.
for (JToggleButton btn : myButtonList) {
if (btn.isSelected() {
String actionCommand = btn.getActionCommand();
// use the actionCommand here
}
}
Note that JToggleButton is the parent class for JRadioButton and using it would allow you to add JRadioButtons, JCheckBoxes, and JToggleButtons to the list. Since your JRadioButton is not part of a ButtonGroup, perhaps you should be using a JCheckBox instead.
Edit
You now have posted this code, stating it doesn't work:
// Section (A)
ArrayList<JToggleButton> settingQuestionButton = new ArrayList<JToggleButton>();
// Section (B)
for(JToggleButton questions: settingQuestionButon)
{
if(questions.isSelected())
{
System.out.println(questions.getActionCommand());
}
}
Is this code, both (A) and (B), all together in your program? If so, it would make sense that it doesn't work. You should have (A) in a constructor or some set up method. You should follow (A) with code that creates your JRadioButtons or JCheckBoxes, that sets their actionCommand String, that places them in the GUI, and that adds them to the ArrayList.
The part (B) code, the enhanced for loop would need to be in code that is called in response to an event, perhaps in a JButton or radio button's ActionListener.
Please check out this information and fill us in on the details. Please consider creating and posting an sscce illustrating your problem for us.
Edit 2
Your code is confusing in that you appear to have two completely variables of different types with the exact same name, and you appear to be assuming that this will give the variable magical properties that will allow it to know what it's "twin" might be doing. Java doesn't work that way, and in fact variable names are not nearly all that important or smart to allow them any such functionality. Rather your code must be smart.
I'm assuming that more than one of your JCheckBoxes will be checked, and that you want to check which ones are checked at some point in your program. If so, then in your class you should have a List or ArrayList field, something like
private List<JToggleButton> questionsList = new ArrayList<JToggleButton>();
This way this field will available throughout the class.
Then where you create your JCheckBoxes, you add them to this list:
private void setExamButtonActionPerformed(java.awt.event.ActionEvent evt)
{
if(evt.getActionCommand().equals("Set Exam"))
{
CardLayout cL = (CardLayout)cardPanels.getLayout();
cL.show(cardPanels, "setExamPanel");
}
try
{
String theMessage = myObject.getMessage();
String delims = "(?=(0*([0-9]{1,2}|100)))";
String[] questions = theMessage.split(delims);
for (int j = 1; j < questions.length; j++)
{
settingQuestionBox = new JCheckBox(questions[j]); // *** renamed to make more sense
settingQuestionBox.setActionCommand(questions[j]); // **** add actionCommand String
questionsList.add(settingQuestionBox); // ****** add JCheckBox to List
settingQuestionTextField = new JTextField("");
jPanel1.add(settingQuestionBox);
jPanel1.add(settingQuestionTextField);
jPanel1.revalidate();
jPanel1.repaint();
}
//close streams and socket code
}
catch(Exception e)
{
// System.out.println(e);
e.printStackTrace(); // ***** more informative
}
}
Then elsewhere in your code
setExamQuestionButtonActionPerformed(java.awt.event.ActionEvent evt)
{
if(evt.getActionCommand().equals("Set Exam Question"))
{
// ArrayList<JToggleButton> settingQuestionBoxes = new ArrayList<JToggleButton>();
for(JToggleButton questions: questionsList)
{
if(questions.isSelected())
{
System.out.println(questions.getActionCommand());
}
}
CardLayout cL = (CardLayout)cardPanels.getLayout();
cL.show(cardPanels, "instructorPanel");
}
}
And of course you'll need to take care that the ActionListener is added to a button

Help implementing JComboBox[] Listener

1) In the following method (actionListener) a user select a grade (e.g. A-F) from a JComboBox.
2) There are multiple JComboBoxes, and each selection made gets stored into a single String[] array.
PROBLEM:
Here is the dilemma, if a user goes back and changes a selection made from a random JComboBox the previous grade selection does not get replaced in the array, however the new selection made gets stored at the next array index.
How can I make the program replace the previous grade selection and not just add the new selection?
relevant variables:
int counter;
private JComboBox[] gradeField;
//grade.userGrades[] is array of grades taken from selected combo boxes
Action Listener anonymous class:
gradeField[counter].addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox)holder;
String theGrade = (String)tempGradeBox.getSelectedItem();
grade.userGrades[grade.getNext()] = theGrade;
grade.updateNext();
}
});
Thanks in advance for any help.
I save the grade in an array and increment the index,
Well you should not be incrementing the index. This assumes that the user selects the grades from the combo box in a sequential order. As you have discovered users can often work randomly.
Instead you need to know which combo box has been changed and then update the appropriate entry in your array.
Or a different solution might be to update your array at the end. So maybe you have a "Process Results" button. Then you can sequentually loop through all the combo boxes to get the selected value.
Update the user grade being at the same index as the combo box:
final int index = counter;
gradeField[counter].addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox)holder;
String theGrade = (String)tempGradeBox.getSelectedItem();
grade.userGrades[index] = theGrade;
}
});
Here's another variation of JB Nizet's answer:
class OuterClass
{
...
gradeField[counter].addActionListener( new GradeSettingActionListener( counter ) );
...
class GradeSettingActionListener implements ActionListener
{
// -- Doesn't have to be final here (it does in JB's answer), but I like to be restrictive.
private final int index;
public GradeSettingActionListener( int index )
{
this.index = index;
}
#Override
public void actionPerformed( ActionEvent e )
{
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox) holder;
String theGrade = (String) tempGradeBox.getSelectedItem();
grade.userGrades[index] = theGrade;
}
}
}
This approach removes the anonymous class by adding an inner class. The inner class will still have access to grade. You don't gain much here unless there's a chance you'll be splitting out the inner class later.
Of course, camickr's suggestion to process all the grades at once may also be valid, depending on other requirements (i.e., whether additional processing is done after the grades are stored in the array, which seems likely).

Categories