I have a JFrame with JTextFields, JComboBoxes and JLabels. I want to make the button "UPDATE" clickable only if something has been changed(fields) in the window.
1 Answers
I want to make the button "UPDATE" clickable only if something has been changed(fields) in the window.
You'll need to listen for changes in your "fields" (whatever they are supposed to be), and in that listener call setEnabled(true)
or setEnabled(false)
on your JButton of interest -- or better on its Action, depending on the state of your fields. Why is the Action better? You can have several buttons and JMenuItems share the same Action, and by calling the methods on the Actions, you would disable both at the same time.
For example, if the fields are JTextFields, then add a DocumentListener to your fields, and based on the state of the fields in the listener, call the method I've noted above.
If you need more concrete help, then you'll want to provide us with more concrete information and code.
For an example with 5 JTextFields and a JButton, where the JButton is only active if text is present in every JTextField:
package pkg;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
@SuppressWarnings("serial")
public class ButtonActiveTest extends JPanel {
private static final int FIELD_COUNT = 5;
private MyAction myAction = new MyAction("My Button"); // The Action
private JButton myButton = new JButton(myAction); // the button
private JTextField[] textFields = new JTextField[FIELD_COUNT];
public ButtonActiveTest() {
myAction.setEnabled(false); // initially disable button's Action
// create single Doc listener
MyDocumentListener myDocumentListener = new MyDocumentListener();
// create jtext fields in a loop
for (int i = 0; i < textFields.length; i++) {
textFields[i] = new JTextField(5); // create each text field
// add document listener to doc
textFields[i].getDocument().addDocumentListener(myDocumentListener);
// add to gui
add(textFields[i]);
}
add(myButton);
}
private static void createAndShowGui() {
ButtonActiveTest mainPanel = new ButtonActiveTest();
JFrame frame = new JFrame("ButtonActiveTest");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private class MyAction extends AbstractAction {
public MyAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic); // to give button an alt-key hotkey
}
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(ButtonActiveTest.this, "Button Pressed");
}
}
private class MyDocumentListener implements DocumentListener {
@Override
public void changedUpdate(DocumentEvent e) {
checkFields();
}
@Override
public void insertUpdate(DocumentEvent e) {
checkFields();
}
@Override
public void removeUpdate(DocumentEvent e) {
checkFields();
}
// if any changes to any document (any of the above methods called)
// check if all JTextfields have text. If so, activate the action
private void checkFields() {
boolean allFieldsHaveText = true;
for (JTextField jTextField : textFields) {
if (jTextField.getText().trim().isEmpty()) {
allFieldsHaveText = false;
}
}
myAction.setEnabled(allFieldsHaveText);
}
}
}
Showing similar code, but now with a JMenuItem sharing the same Action as the JButton. Note that both the menu item and the button are active/inactive in parallel:
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
@SuppressWarnings("serial")
public class ButtonActiveTest extends JPanel {
private static final int FIELD_COUNT = 5;
private MyAction myAction = new MyAction("Process Data in Fields"); // The Action
private JButton myButton = new JButton(myAction); // the button
private JTextField[] textFields = new JTextField[FIELD_COUNT];
private JMenuBar menuBar = new JMenuBar();
public ButtonActiveTest() {
myAction.setEnabled(false); // initially disable button's Action
// create single Doc listener
MyDocumentListener myDocumentListener = new MyDocumentListener();
// create jtext fields in a loop
for (int i = 0; i < textFields.length; i++) {
textFields[i] = new JTextField(5); // create each text field
// add document listener to doc
textFields[i].getDocument().addDocumentListener(myDocumentListener);
// add to gui
add(textFields[i]);
}
add(myButton);
// create menu item with our action
JMenuItem menuItem = new JMenuItem(myAction);
JMenu menu = new JMenu("Menu");
menu.setMnemonic(KeyEvent.VK_M);
menu.add(menuItem);
menuBar.add(menu);
}
public JMenuBar getMenuBar() {
return menuBar;
}
private static void createAndShowGui() {
ButtonActiveTest mainPanel = new ButtonActiveTest();
JFrame frame = new JFrame("ButtonActiveTest");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setJMenuBar(mainPanel.getMenuBar());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private class MyAction extends AbstractAction {
public MyAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic); // to give button an alt-key hotkey
}
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(ButtonActiveTest.this, "Action Performed!");
}
}
private class MyDocumentListener implements DocumentListener {
@Override
public void changedUpdate(DocumentEvent e) {
checkFields();
}
@Override
public void insertUpdate(DocumentEvent e) {
checkFields();
}
@Override
public void removeUpdate(DocumentEvent e) {
checkFields();
}
// if any changes to any document (any of the above methods called)
// check if all JTextfields have text. If so, activate the action
private void checkFields() {
boolean allFieldsHaveText = true;
for (JTextField jTextField : textFields) {
if (jTextField.getText().trim().isEmpty()) {
allFieldsHaveText = false;
}
}
myAction.setEnabled(allFieldsHaveText);
}
}
}

- 283,665
- 25
- 256
- 373
-
Can't I listen to all the components at once ? The solution you stated makes me add a listener to each and every component. Doesn't it ? – HeXMaN Aug 10 '15 at 16:20
-
1@SainandShinde If you were to do this, you could use the same listener for all of your elements. Meaning that you would simply need to add a `foo.addActionListener(bar);` to your elements. A good example of this is http://stackoverflow.com/questions/5936261/how-to-add-action-listener-that-listens-to-multiple-buttons – Stephen Buttolph Aug 10 '15 at 16:26
-
1@SainandShinde: no big deal, as you could add a single listener to all fields (if JTextFields or all same type of field) in a for loop as I show above (see edit to answer). But again, if you need more concrete help, **please** improve your question by telling us what a "field" is and by showing pertinent code. Your question is a bit shy of important details. – Hovercraft Full Of Eels Aug 10 '15 at 16:28
-
Oh sorry for such abstract question. Running out of time for project submission. Your example has solved my problem. +1 for `putValue(MNEMONIC_KEY, mnemonic);` Going to add this feature right-away. – HeXMaN Aug 10 '15 at 16:37