Java: Iterate JMenuItem from ArrayList with HashMaps - java

I have a JFrame with a menubar, in which i'd like some dynamic menus, as in, depending on the size of the ArrayList with HashLists. The problem here is that i then got a dynamic amount of JMenuItems, so i need a way to get as much variables as HashLists. In this case i made the name of the variable static, but obviously that's not working on the ActionListener, since all MenuItems will have the same ActionListener.
I'm wondering how to solve this, and how to get a menu with a dynamic amount of menuitems which all have unique actionlisteners.
private ArrayList<HashMap> menuLijst;
.
for (HashMap h : menuLijst) {
String vraag = (String) h.get("vraag");
JMenuItem qMenu = new JMenuItem(vraag);
informatie.add(qMenu);
qMenu.addActionListener(this);
}
Thanks in advance.

Depending on what you want to do in your ActionListener, you can either use this, as you do right now and in the actionPerformed you can then use ((JMenutItem)event.getSource()) to see which menu item has been clicked. Alternatively, you could register as many ActionListeners as there are menus, like this:
for (final HashMap h : menuLijst) {
final String vraag = (String) h.get("vraag");
final JMenuItem qMenu = new JMenuItem(vraag);
informatie.add(qMenu);
qMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
// here event.getSource() is the same as qMenu
System.out.println("Menu "+qMenu+" with label "+vraag+" has been pressed");
System.out.println("HashMap is "+h);
}
});
}
But to me (and also seeing your previous questions), it seems that you are abusing the usage of HashMap instead of using appropriate new objects. I don't know what else is in your HashMap, let's say that you have 3 keys: "vraag", "answer", "grade", you could create the following class:
public class MyClass {
private String vraag;
private String answer;
private int grade;
// And getters and setters here.
}
And have a List<MyClass> instead of List<HashMap>.

I don't see why you want to use a HashMap for your Strings. If you save an ArrayList of Strings, and loop over them to add them all to the menu, you can add actionListeners to all of them, just as you are doing now.
In your ActionListener, check which button is clicked by looping through the ArrayList, and comparing to the name of the clicked button.

Related

Find the index of a Java JButton Array

I am writing a Java program in which I have an array of buttons (not a calculator!) and I'm looking for an efficient way to know which JButton was clicked. From what I know of Java so far, the only way to do it is to have them all in the same ActionListener and then loop through looking for a match.
Another solution I just thought of would be to extend JButton to include a unique ID number variable in the constructor. It seems that should work when the event object is cast to JButton after an instanceof check. Kind of like using VB's Tag property which is assigned to the index number.
Is there a better/more elegant way?
Is there a better/more elegant way?
yes to use (for almost JComponents) the put/getClientProperty, there you can to set endless number of properties, can be multiplied in contrast with setName / setActionCommand / etc
getClientProperty can be used as unique identificator for Swing Action or EventHandler (rather than to use ActionListener)
Links to the Javadocs: putClientProperty(), getClientProperty()
Here is an example from programm I writing last few months.
I have an enum called Position
public enum Position {
BB, SB, BU, CO, MP3, MP2, MP1, EP3, EP2, EP1;
}
and have some JToggleButtons each of them holding ist own Position.
public class PositionButton extends JToggleButton {
private final Position p;
public PositionButton(Position p) {
this.p = p;
setText(p.toString());
setActionCommand(p.toString());
}
public Position getPosition() {
return p;
}
}
This allows you to create Buttons in a Loop and get value direct from button without comparing:
ActionListener positionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
PositionButton b = (PositionButton )e.getSource();
Position p = b.getPosition();
//do something with Position
}
}
for (Position p : Position.values()) {
PositionButton b = new PositionButton (p);
b.addActionListener(positionListener);
}
The way I've done it before was using actionPerformed for different buttons. I like it more compared to some other ways I've seen.
public void actionPerformed(ActionEvent clicking)
{
if (clicking.getSource() == button[0])
// Do this
if (clicking.getSource() == button[1])
// Do something different
}
Since you built an array, you can throw the ID right where that 0 is and that's your unique ID.
Add a separate action listener for each button.

How to Check(Marked as checked) buttons in a program(or a checkbox) from just one Button?

Here is my question.Lets say that somebody made a checkbox in java and he is using it in a GUI interface so that the user can select a variety of options.Then the programmer wants to create a button inside the checkbox so that when the user checks that button all the other options will be checked as well.And when he unchecks that button of course all the other buttons will be unchecked.How is that possible in java?
Example :
o1 = new JCheckBox("Option 1");
o2 = new JCheckBox("Option 2");
o3 = new JCheckBox("Option 3");
All = new JCheckBox("All");
.....
CheckBoxHandler listener = new CheckBoxHandler();
All.addItemListener(listener);
......
Lets assume that the following code is on a class that was created as it implements ItemListener
public class CheckBoxHandler implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{
if (e.getSource()==All)
if (e.getStateChange()==ItemEvent.SELECTED)
{
.... <------ (!!!)Here inside I am currently stack and I do not know how to
add the correct code in order to have all the other buttons checked.
}
}
}
Any help provided is really appreciated :)
Make use of the concept of array.
JCheckBox[] checkboxes = new JCheckBox[10];
When you need to apply some operation to all checkboxes, iterate over the array:
for( JCheckbox cb : checkboxes )
cb.doStuff();
You can call setSelected() on the JCheckbox (inherited from AbstractButton):
...
o1.setSelected(true); // or false
...
As #Juvanis mentions, instead of having three different references for o1, o2 and o3, you should use an array. Then, you can do something like
for( JCheckbox cb : checkboxes ) {
cb.setSelected(true);
}
to set all checkboxes in the array as checked.
CheckBoxes can have ActionListeners. Why not add an ActionListener to all the checkboxes that then checks if the one selected is checked or not and calls setSelected(true) or setSelected(false) on each one?
If you have a known small number of checkboxes (such as the 3 you talked about), you may just want to hard code it. However, if you need to make it modular or have a large number of check boxes, you can always store them in a data structure (as Juvanis said, an array would probably work nicely) and loop it

Referring to a Dynamically Created JButton

I have a JPanel on which I've dynamically added quite a few JButtons. All of this is working perfectly. Later on in my program execution, I need to refer back to these buttons and pull out the button text. I'm having trouble figuring out how to refer back to them.
When I created each button, I gave it a unique name. Let's say this is the code where I created the button:
public void createButton(Container parent, String btnName) {
JButton btn = new JButton("xyz");
btn.setName(btnName);
btn.addActionListner(new ActionListner() {
//code
}
parent.add(btn);
}
In another method, I'm trying to retrieve the label on the button since it may have changed at run time. Do I need to keep an array of these buttons as they are created? Or is there a way that I can refer back to them directly?
This is what I was working on, but it's stupid. Can anyone suggest a correct approach?
public String getBtnLabel(String btnName) {
JButton btn = (JButton) btnName;
return btn.getText();
}
If the answer is that I just need to create the array and then iterate over it, that's fine. Just looking for other options.
You need to use a Map<String, JButton> so when you create your dynamic buttons you give them some sort of unqiue name:
//somewhere at the top of your class
private final Map<String, JButton> myButtonMap = new HashMap<>();
public void createButton(Container parent, String btnName) {
JButton btn = new JButton("xyz");
btn.setName(btnName);
btn.addActionListner(new ActionListner() {
//code
}
parent.add(btn);
myButtonMap.put(btnName, btn);
}
And then simply get from the map
public String getBtnLabel(String btnName) {
return myButtonMap.get(btnName).getText();
}
This will obviously throw an NPE if the button isn't defined...
Also you will need to delete from your map when you're done with it otherwise you're asking for a memory leak...
I suggest you to use a Map< String, JButton >.
At creation time you put new button into it with buttons.put( name, btn )
In event handler you use JButton btn = buttons.get( name )
Yes you need to keep references to the buttons. An array would be an option, but since arrays are awkward to use, you should prefer a List.
If you have a a reference to the JPanel containing the buttons, you could get them from it. but that is likely to be rather bothersome.
I would recommend keeping a list of your buttons or a reference to them in a map, however you could do this:
for (Component i : parent.getComponents()) {
if (i.getName().equals(btnName)) {
JButton b = (JButton) i;
// do stuff..
}
}
Using the parent component and iterating over the added components.

Help in automatically changing value upon ItemChange in JComboBox

I have a program in which I am using 3 things, a checkbox, a combobox and a textfield. The logic works like this if checkbox is enable then combobox and textfield are enable unless not.
Then set some value in the textfield by mulitplying it with the item in combobox.
From the frame - The value of Final Price is Price * Quantity.
Now the issue when I click purchase everything went fine. But when I change the value from Jcombobox it doesn't automatically change the value in final price and remains to be 1200 as in first case. For the value to be changed I have uncheck and then check the Checkbox.
What could be the problem. I have used ItemListner for both checkbox and combobox.
#Override
public void itemStateChanged(ItemEvent e){
Object get = e.getSource();
int multiplier;
int ftotal;
if (e.getStateChange()==ItemEvent.SELECTED){
if(get==chkbox1){
qntbox1.setEnabled(true);
size1.setEnabled(true);
multiplier = Integer.parseInt(String.valueOf(qntbox1.getSelectedItem()));
ftotal = Integer.parseInt(price1.getText()) * multiplier;
fprice1.setText(String.valueOf(ftotal));}
You have to implement ActionListener for your JComboBox:
private static final String command_cbo1 = "ComboBox1";
// ...
public class YourClass implements ItemListener, ActionListener
{
// ...
public YourClass()
{
// ...
qntbox1.addActionListener(this);
qntbox1.setActionCommand(command_cbo1);
// ...
}
// ...
public void itemStateChanged(ItemEvent e)
{
// ...
}
// ...
public void actionPerformed(ActionEvent e)
{
JComboBox cb = (JComboBox) e.getSource();
String s = (String) cb.getSelectedItem();
if(e.getActionCommand().equals(command_cbo1))
{
fprice1.setText("" + (Integer.parseInt(price1.getText()) * Integer.parseInt(s)));
}
// ...
}
// ...
}
not directly to your question
1/ JCheckBox is totally useless, that will be really needed for final calculation(s)
2/ consider that JComponents for Price and Final Price would be only JFormattedTextField, then you can pretty to forgot for Parse#Whatever
3/ consider that JComponents for Quantity would be only JSpinner, but workaround for Number Instance would be litte bit complicated as for JFormattedTextField example here
4/ for nice output put everything to the JTable
5/ for JComboBox I preferred ItemListener not ActionListener, because your problems isn't with proper Listener but with parsing Numbers correct way
Ok got it working. The ActionListner made it work (JComboBox). I guess using ItemListner for too many components made parsing a little confusing, add to that I used too many clauses in the ItemListner scope. Thanks a lot everyone for helping.
#mKorbel : I'll be using your suggestion asap :) and will check JTable and said components. have to go through them since I haven't used it.
#Eng.Fouad : Thanks man for the help.
Just one issue. When I typecast getSelectedItem() to integer it gives NumberFormatException error (runtime). So I have to first change the object to String and then parseit into integer. Any clue why direct conversion is throwing error ?
Here is the working code for the project.
public void itemStateChanged(ItemEvent e){
Object get = e.getSource();
if (e.getStateChange()==ItemEvent.SELECTED){
if(get==chkbox1){
qntbox1.setEnabled(true);
size1.setEnabled(true);
fprice1.setText(String.valueOf(Integer.parseInt(price1.getText()) * Integer.parseInt(String.valueOf(qntbox1.getSelectedItem()))));
}
#Override
public void actionPerformed (ActionEvent ae)
{
Object toggel = ae.getSource();
String check;
if (toggel == qntbox1)
{
check = (String) qntbox1.getSelectedItem();
fprice1.setText(String.valueOf(Integer.parseInt(price1.getText()) * Integer.parseInt(check)));
}

set focus for all fields

I noticed I can use getName() as part of the trick.
What is java.awt.Component.getName() and setName() used for?
But I don't really have a clue where to start. What type of listener should I use (assuming the textfield / or box is currently blinking / selected)
This is my previous question, and thank you for the help guys.
How do I use requestFocus in a Java JFrame GUI?
I realize that for each component (Textfield) that I am creating, I have to insert a statement like requestFocus (or using transferFocus).
Is it possible to apply this policy to all the fields???
I have several textfields and ComboBox. The problem I hit is that I don't want to write methods for every single field / box.
For example, I write a method like this
private JTextField getFirstNameEntry() {
.... do something
}
because my instructor writes his program like this
private JPanel getJContentPane() {
jContentPane = new JPanel();
jContentPane.setLayout(new java.awt.FlowLayout(FlowLayout.LEADING));
jContentPane.add(makeLabel(" First Name *", 100, 20));
jContentPane.add(getFirstNameEntry(), null);
jContentPane.add(makeLabel(" Middle Initial", 100, 20));
jContentPane.add(getMiddleInitialEntry(), null);
// etc
return jContentPane;
However, to save redundancy (that was my motive at first), say I have a box, I can simply add the following code inside the method above: getJContentPane()
titleBox = new JComboBox(new String[]{"Mr.","Mrs.","Ms.","Dr.","Prof.","Rev."});
jContentPane.add(titleBox);
But doing this, I still need to create a method to do addItemListener
private void setComboBoxFocus() {
titleBox.addItemListener(
new ItemListener(){
public void itemStateChanged(ItemEvent e){
if(e.getStateChange() == ItemEvent.SELECTED)
{
String titleSelected = titleBox.getSelectedItem().toString();
System.out.println(titleSelected);
titleBox.transferFocus();
}
}
});
}
However, this doesn't really save redundancy at all. If I have more than one ComboBox to be added, I would have to write another similar method. In fact, even in the case with one ComboBox (titleBox), I would still end up with writing a method for titleBox.
So my question is: is there a way to write a general method that can call focus to all (maybe one for ComboBox type)?
Thank you and sorry for the long post.
Why not take a JComboBox argument to your setComboBoxFocus() method, which allows you to set that listener to any JComboBox you may have? Like so:
private void setComboBoxFocus(JComboBox box) {
box.addItemListener(
new ItemListener(){
public void itemStateChanged(ItemEvent e){
if(e.getStateChange() == ItemEvent.SELECTED)
{
String titleSelected = box.getSelectedItem().toString();
System.out.println(titleSelected);
box.transferFocus();
}
}
});
}

Categories

Resources