I'm a newbie in Java/JavaFX (I began yesterday evening). I'm building a dynamic GUI (crud) reading off a MySQL database.
I managed to display the data in a table and add a button next to each row.
Since the number of buttons is variable, I want to define only a common eventhandler.
The problem is that whenever I use event.getSource() (it's an ActionEvent) and display it, I get something like "Button[id=0, styleClass=button].
Question 1: Is there any way I could put the id in a variable? I can't get it out of the object.
As far as I know, I have to use the id, since I can't do something like this "if(event.getSource() == somebutton) {...}" since every generated button had the same variable name.
Now, this is the loop (inside a method called make_buttons) that builds the buttons. n_buttons is the number of buttons I want to build.
for(int counter = 0; counter < n_buttons; counter++){
String newtext = new String("btn"+counter);
Button btn = new Button();
btn.setText(newtext);
btn.setId(Integer.toString(counter));
btn.setOnAction(myHandler);
grid.add(btn,0,counter);
}
Note that I'm placing the buttons on a gridpane one on top of the other.
Before that part I have my handler:
final EventHandler<ActionEvent> myHandler = new EventHandler<ActionEvent>(){
public void handle(final ActionEvent event) {
Object new_output = event.getSource();
System.out.println(new_output);
event.consume();
}
};
Question 2: so, how can I differentiate which button fired the event in my particular case?
I know quite a few programming languages (Matlab, R, Python, C, Assembly, etc... but I'm a hobbyist), but it's the first time I'm working with GUI elements (except web languages and ActionScript 3).
In actionscript I could just do something like event.getCurrentTarget and the use it exactly as if it were the object itself to read the id, properties, etc.
I looked everywhere and couldn't find anything (maybe my terminology was a bit approximative...).
If I understand your question correcty, you can simply access the clicked button in you handle method with the following code:
Object source = event.getSource();
if (source instanceof Button) { //should always be true in your example
Button clickedBtn = (Button) source; // that's the button that was clicked
System.out.println(clickedBtn.getId()); // prints the id of the button
}
Related
I have the following code to set up a Button in JavaFX 8:
Button button = new Button("target name");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Button pressed = (Button)event.getSource();
// next target name is the title of the button
handleClick(pressed.getText());
}
});
I would like to pass some information to the handleClick() routine. In this case I have a String that is a "target name" and handleClick() is a method that knows what to do with that. Right now I'm passing that information by making it the name of the Button. Is there a better way? For instance, what if I wanted to pass two pieces of information? Or, what if the info I want to pass is not a String?
The handle() routine only accepts an ActionEvent parameter. I can't find anything in ActionEvent that would help me here.
One idea I had: Maybe I could write my own SmartButton subclass that extends Button, and include in that subclass some additional info that is passed in at the time the SmartButton is constructed (so in the subclass I would only implement an extra constructor and one or more new getters/setters). The handleClick() routine would then have access to that information via getters called on (SmartButton)event.getSource().
This seems like a common UI programming issue. What is the best practice?
Thanks.
In the code snippet you posted, the event handler is only associated with the button created in the first line. Furthermore, since it's an anonymous inner class you know you only have the one instance of that class, and consequently that event handler cannot be associated with any other control. So your code is completely equivalent to
Button button = new Button("target name");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
handleClick(button.getText());
}
});
or, using lambda expressions:
Button button = new Button("target name");
button.setOnAction(event -> handleClick(button.getText()));
You can basically always do this, even if the data needed to handle the button press is not the text in the button. Consider a calculator app (restrict it to integers for simplicity). You would likely have some variable storing the current value displayed:
private int value ;
and then you want a bunch of numeric buttons which "append" their own value to the current value (so if the current value is 1 and you press "2", the current value should be 12, etc):
You would just need
for (int i = 0 ; i <= 9 ; i++) {
Button button = createButton(i);
// place button in UI...
}
with
private Button createButton(int buttonValue) {
Button button = new Button(Integer.toString(buttonValue));
button.setOnAction(e -> value = value * 10 + buttonValue);
return button ;
}
Some variation on this idea will always give you what you need.
I have a check box and when I create an Action script from the Netbeans' design, it creates a function like;
private void jCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {
total=8.99f;
xc = "XCheese";
exTop++;
calculateTotal(total);
updateTextArea();
}
This works perfectly, but I want to set everything to zero when the jCheckBox1 is unchecked, if I uncheck it the way the code is now, no changes appear.
It is an sample of code. Hope it will help you.
private void jCheckBox1ActionPerformed(java.awt.event.ActionEvent evt) {
if(checkBox.isSelected() ){
total=8.99f;
xc = "XCheese";
exTop++;
calculateTotal(total);
updateTextArea();
}else{
// set everything zero here.
}
}
Start by taking a look at How to Use Buttons, Check Boxes, and Radio Buttons
Basically, the ActionListener will be called when ever the check box is selected (checked) or unselected (unchecked). You need to check the state of the check box when ever the method is called.
Take a look at AbstractButton#isSelected which will tell you the (in this case) the checked state of the JCheckBox
So I have this project,
the source code is here.
When you run the project and goto Processing, there is a jcombobox there that is suppose to have an addActionListener.
p_customer_list = new JComboBox<>(customers_name);
pp_customer_list.setPreferredSize(new Dimension(360, 35));
panel_processing_header.add(pp_customer_list);
//pp_customer_list.addActionListener(this);
pp_customer_list.addActionListener (new ActionListener () {
public void actionPerformed(ActionEvent e) {
JComboBox tmpBox = (JComboBox) e.getSource();
int selected = tmpBox.getSelectedIndex();
pp_refresh_data(selected);
}
});
This is what I have so far, its suppose to find the selected index when the value of the combobox changes and pass it to pp_refresh_data() but for some reason it does not run (I tried putting a JOptionPane to see when the code is executed, and its only executed once when the program runs.)
Hard to tell from just a partial code snippet, but do you have 2 combos, one named "p_customer_list" and another named "pp_customer_list"?
This could be your problem. You may be adding the listener to the wrong combo, or you may be adding the wrong combo to your panel, or maybe you don't need two, or maybe...
Again, it's hard to tell from just a snippet.
I have a JCheckBox defined as:
JCheckBox NewCB = new JCheckbox();
NewCB.setSelected(false);
NewCB.setMnemonic(KeyEvent.VK_C);
NewCB.addItemListener(this);
This Check Box is using an ItemLisener:
public void itemStateChanged(ItemEvent e) {
Object source = e.getItemSelectable();
if(source == NewCB) {TEST = "SELECTED"; System.out.println(TEST);}
}
I launch a JFrame when the program starts. If I add this CheckBox to the frame, it works fine. If I open a second JFrame, and add this Check Box to the 2nd frame, and the Object Source no longer works. Is there some other definition I need to make to get the Object source to read the check box name for any open frames?
First of all, you can't add a component to more than one parent; I'm not sure that's your problem though.
The thing you're calling the "name" of the checkbox isn't a property of the checkbox, but rather a property of a variable that points to the checkbox. The difference is important, because there could be many such variables. The checkbox doesn't know anything about the variables that point to it.
Given that, how do we solve the problem? You can set the "action command" of the checkbox, and then check that:
NewCB.setActionCommand("Fred");
// ...
if ("Fred".equals(((JCheckBox) source).getActionCommand())))
// ...
I have a JButton which launches a JFileChooser. However the JFileChooser often takes a few seconds to come up, during which time the user might think that nothing is happening. I tried to make the button become disabled until the JFileChooser is finished with, but the disabling of the button doesn't even happen until the JFileChooser is loaded. Is there something I can do?
My code:
public void actionPerformed(ActionEvent e) {
System.err.println("clicked");
((JButton) e.getSource()).setEnabled(false);
System.err.println("set");
JFileChooser b = new JFileChooser("C:\\");
b.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int res = b.showOpenDialog((Component) e.getSource());
if (res == JFileChooser.APPROVE_OPTION) {
try {
//Blah
}
catch (Exception err) {
JDialog j = new JDialog(window, "An error occured:\n" + err.getMessage());
}
}
((JButton) e.getSource()).setEnabled(true);
}
Move these lines..
JFileChooser b = new JFileChooser("C:\\");
b.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
..from the action performed method to the constructor of the action listener, change them to..
b = new JFileChooser("C:\\");
b.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
..then declare..
private JFileChooser b;
..as a class attribute (so it is visible to the action performed method).
You might also want to give it a better name.
The chooser will be constructed when the class is created, and be ready for use when needed. This has the added benefit that the chooser will remember the position, size, path & file display type, the subsequent times the user activates the button.
Yet another strategy is to declare the chooser as a class attribute, don't instantiate it in the constructor, but check in the action performed if it is null, and if so, create and configure it.
Continued..
I might want to do something a bit slower like this at some point, that doesn't quite deserve its own thread.
With the last strategy I outlined, I was considering adding something that I will add now.
..Continued
..Of course, that last method will give exactly the same problem you describe, but just once when the user 1st clicks the button. For that situation, you should probably be looking to pop a JOptionPane with an indeterminate JProgressBar from inside a SwingWorker.
Obviously, a SwingWorker creates a new Thread, but OTOH, Thread objects in Java are cheap. There are a number of them running for any app. with a GUI. A couple more will not hurt.