I am Swing novice. I made a small app using JTree, JCheckBox, JList and JButton. I am using the associated model classes to store the presentation state. Works fine, except for the JButton. I'd like to update the button's text according to a property of my model. Basically, it will change from log in/to log off whether the user is currently logged in. Unfortunatly, I can't find a setText method in the ButtonModel interface. Can anybody tell me how to do this ?
Thanks. PW.
For a JButton you can use an Action as your model. The Action interface defines keys which are used by the JButton to retrieve its state from the Action, including one for the text: Action.NAME
If you look at the source code, the constructor with the Action (or simply the setAction method) uses more information from the Action then what can be retrieved from a ButtonModel. Same for other constructors, e.g.
public JButton(String text, Icon icon) {
// Create the model
setModel(new DefaultButtonModel());
// initialize
init(text, icon);
}
So it seems that you are correct in your assessment that the ButtonModel does not contain all information used to visualize a typical JButton
Related
It might be confusing for some to answer this but I will try to put my question in the best way. I am working with jdbc and gui. Basically I want to display (in buttons format) the particular data received from my sql database. I could get the data correctly and put it to my array of buttons as their names. In other words, I have an ArrayList of buttons with different names/texts received from my database. Thus i really need to make an arraylist of buttons since data are dynamically populated. My problem is, I am so confused of how am going to create an actionListener to each button. Everytime each button is clicked, it must show the values associated with its name. I don't know how am i supposed to pass at least the names of the buttons to my actionListener method (or action Event Handler). If you find it confusing, here is the code for my buttons.
todayTaskButton.add(new JButton(taskForToday.get(i)));
todayTaskButton.get(i).setPreferredSize(new Dimension(300,75));
todayTaskButton.get(i).setBackground(Color.GRAY);
todayTaskButton.get(i).setFont(new Font("Century Gothic",Font.PLAIN,30));
todayTaskButton.get(i).setForeground(Color.WHITE);
todayTaskButton.get(i).setFocusable(false);
Thank you so much
You don't need to pass the name of the button to the ActionListener. It is automatically detected. You just need to implement the method actionPerformed(ActionEvent) in you class.
Then add the listener to the button :
todayTaskButton.get(i).addActionListener(this);
In your actionPerformed method, you can do:
JButton b = (JButton) e.getSource();
String text = b.getText();
Honestly there are so many ways you might achieve this, the problem is picking the right one for you...
You could...
Create a anonymous class for each button, each time your create them
todayTaskButton.get(i).addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...
}
});
While this can work, it can make the code really messy, you also still need a way to map the action back to the button in some way, which can be done using the actionCommand property or using the source property if you don't mind iterating through the list of available buttons
You could...
Create a purpose build class which implements ActionListener for each button, which possibly takes some kind of reference to the data
todayTaskButton.get(i).addActionListener(new TodayActionListener(taskForToday.get(i)));
This is a little more focused, as you don't really care about the button, as you have the "today" value for the listener, so all the normally repeated code could be isolated into a single class and you would simply pass in the "variable" element
You could...
Take full advantage of the Action API and make individual, self contained actions for each button...
public class TaskAction extends AbstractAction {
public TodayAction(String task) {
putValue(NAME, task);
}
#Override
public void actionPerformed(ActionEvent e) {
// Specific action for task
}
}
Then you could simply use
todayTaskButton.add(new JButton(new TaskAction(taskForToday.get(i))));
While this is similar to the previous option, the Action is a self contained unit of work and has a number of properties which the JButton can use to configure it self. The Action can also be re-used for JMenuItems and key bindings, making it incredibly flexible
Have a closer look at How to Use Actions for more details
I always use one ActionListenr for a button, but I find that one component can be assigned multiple action listeners. How we can do that and what is use of it
Thanks in advance
c.addActionListener(actionlistener1);
c.addActionListener(actionlistener2);
It is useful if you need to do several actions that are not necessarily correlated. For example, changing the background color of a button vs appending the action in a Logger vs informing the controller that the button have been pressed, etc...
This allows to be modular: each actionListener can handle a very specific task for a group of components. For example, you can write a default actionListener for all your buttons, and a specific one for a group of buttons that have the same behaviour.
Finally, some objects already have listeners when you instantiate them (JButton have a default FocusListener, JScrollPane a default MouseWheelListener, etc). This allow you to add other behaviours to your components, without overriding previous ones.
How we can do that
That's the easy part, create multiple instance of ActionListeners and use addActionListener. One would assume that they are all different...
and what is use of it
That's a harder question. One could assume that you would use multiple listeners when you want to apply newer logic to the process but not extend from the existing functionality...
Let's say you have a login form. You have a "Login" button. You write an ActionListener to gather the required details and validate them.
Later on, you decide that the button should be disabled during that process. Normally, you would add that functionality to the original code, but for what ever reason (it's not your code etc), you can't.
You could create another ActionListener whose sole purpose was to disable the button when it was pressed.
As an example...
We currently have a focus problem with a JTable/JTextEditor in java swing. The JTable has a custom cell editor which is a JTextField.
The issue is when a cell is being edited and contains invalid data, and the user clicks on a JButton, the text field will stop editing and the JButton actionPerformed (clicked) is called. The JTable#setValueAt handles validation so if the data in the JTextField is invalid, the underlying TableModel is not updated.
Ideally, we do not want to let the JButton click occur. Focus should remain with the JTable or the JTextField.
Clicking the button will perform a submit action and close the frame the table is in. As the validation in the TableModel#setValueAt does not update the value, it submits the old value.
Can this be done? I am still fairly new to Swing so I am not aware what to check.
Unfortunately, our code is not straight forward. The UI is constructed from XML in such a way that the button knows nothing about anything else on a form (this is code I have inherited).
In .net you could stop a control losing focus by handling a Validating event and setting a cancel flag. Is there a similar mechanism with Java.
Validating the input after editing has concluded, in setValueAt(), may be inconveniently late. The editor itself can preclude navigation for invalid values, as shown in this example that links to the corresponding tutorial section.
For valid values, you can make the table commit when losing focus:
table.putClientProperty("terminateEditOnFocusLost", true);
Can you try using inputverifier on the editor component, i.e. text field?
When the focus is lost from a component, the lost focus method is called (more reference in http://docs.oracle.com/javase/tutorial/uiswing/events/focuslistener.html). Therefore, you may call the validation method when you lose the focus.
If you do not need to be aware of the specific field being edited, you can also perform validation inside your button and prevent the submission if it is not sucessful.
I'd achieved a similar functionality by overriding the stopCellEditing method in my JTable's CellEditor.
#Override
public boolean stopCellEditing() {
String s = (String) getCellEditorValue();
if (s != null) {
if (!testYourValue()) {
Toolkit.getDefaultToolkit().beep();
return false;
}
}
return super.stopCellEditing();
}
I created a simple app in Netbeans, it contains a few textfields for user input and a button, I've associated an action with the button through the Netbeans interface but I decided to define the action in the App and not the View so as to follow some notion of MVC.
The action works fine, I can print out the console every time the button is clicked.
But in order to do what I want, I need the values included in the jTextFields!
How to do this? This is the code in TestApp.java:
#Action
public void ClickedOnButton() {
System.out.println("Clicked ok");
System.out.println("Will now attempt to read notes.ini");
ReadNotesFile();
}
And this is the code in TestView.java:
javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(tpa_fixer.TPA_FixerApp.class).getContext().getActionMap(TPA_FixerView.class, this);
jButton1.setAction(actionMap.get("ClickedOnButton")); // NOI18N
What have you tried, and how doesn't it work? The standard way to get a JTextField to display text is to call setText() on it. Have you tried doing this?
Also,
Have you gone through the Swing tutorial about these concepts including using text components, JButtons, and ActionListeners?
Are you seeing any errors in these attempts? If so, post them here.
Is your "control" class, the one with the listener code, separate from your "view" or GUI class? If so, does control have a valid reference to view?
Edit
You state:
I don't want to set the text in the jTextFields, I want to get the values out of them and use it in the method that gets run when I click on the button. I can't see how to do this unless I can pass arguments somehow within the body of the action definition in the View class.
What I've done in this situation, where I need to extract information out of gui fields for manipulation in other classes:
You can give each field an associated public getText() method and then call these methods using the control's reference to the view object. For instance say view has a nameField JTextField, then I'd give it a getNameFieldText() method that returns nameField.getText();.
If you had many such fields, then it may be more efficient to use just one getText method but allow it a parameter to let you choose which field to extract text from. To make this work efficiently, I've sometimes given my GUI a HashMap and then have control pass in the String key that allows the getText method to obtain the correct JTextfield, get its text and return it. I often use the same Strings used as JLabels associated with the JTextField as my key Strings.
I have one Mediator.java which do all the functions. And there is RecordGenerationJPanel.java to save the information of a record.NewApplicationJPanel.java is main screen and when I click jbtnGenerate in it, it will show RecordGenerationJPanel and do the showGern method in Mediator class.
All the methods have done by another developer and I have asked to make a new class which will function like showGern method. New showGern class should do some combo box disabled and it also include new text field. But it will be invoked only a checkbox in main screen(NewApplicationJPanel) is checked. Otherwise, it will call the original showGern Method.
Do I need to create another RecordGenerationJPanel? Or, can I do it in same RecordGenerationJPanel? If it's same, how should I do to show different enabling or disabling and hiding some text field according to condition.
Usually, if RecordGenerationJPanel and the requested new class share some attributes and methods, those attributes and methods should be in one class and used by both. So if theres's a future change requirement of a bug fix that affects those common parts, you just have to do it once and both panels benefit from the single fix.
In your case, I'd really copy the existing RecordGenerationJPanel to a new class and modify it to meet you requirements.
If it works, you can start a refactoring and extract the common parts to a new class.
You can add new "checkbox" (as described in your question) to old JPanel. And show/Hide/enable/disable components based on state of checkbox. Also which method to call depends on state of this checkbox.
You can enable/disable components by implementing ActionListener and attaching it to Checkbox.
JCheckBox cb1 = new JCheckBox("Check Box 1")
cb1.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
//enable disable components if checkbox is selected
//enable disable components if checkbox is not selected
}
});
Hope this helps.