0

I'm trying to extend some Swing components and override methods that interacts with its state (setSelectedIndex of JComboBox, setSelected of JCheckBox, etc). There are problem with JCheckBox. I've override setSelected method, but it seems it does not call when user changes JCheckBox state via UI. I can change JCheckBox state by calling method but it seems that GUI uses another way to change it's state. How can I catch that event in my class? With other classes of Swing everything is alright and all overridden methods working correctly.

public class MyCheckBox extends JCheckBox {
    @Override
    public void setSelected(boolean selected) {
        //Method is not performed when MyCheckBox is clicked
        super.setSelected(selected);
    }
}

UP.: I've made it to have package of components that support 'undo/redo' actions. I just added addUndoableEditListener(UndoableEditListener l) method to all components, so implementations is hidden inside my components. That is why I extend Swing components instead of using action listeners.

user1376983
  • 91
  • 2
  • 7
  • My first question: Why are you extending these components rather than simply using them? – Hovercraft Full Of Eels May 05 '12 at 15:57
  • 1
    Why do you assume that the GUI calls precisely this method to set the value? If you want to launch an action when a change is made, you should be using the appropiate listener. – SJuan76 May 05 '12 at 16:03
  • Myself, I'd extend the AbstractAction that I added to my JCheckBox. – Hovercraft Full Of Eels May 05 '12 at 16:03
  • 1
    Regarding your "UP": I think that's a bad reason for this. If anything you want to extend the Actions that are attached to the components, not extend the view or components themselves since your goal has nothing to do with displaying the component. In short: don't extend the component; it's wrong. – Hovercraft Full Of Eels May 05 '12 at 17:08

3 Answers3

2

IF you want to simply listen to this change - use ItemListener (it will listen even to events that are made by ButtonGroup changes or setSelected method calls):

checkBox.addItemListener ( new ItemListener ()
{
    public void itemStateChanged ( ItemEvent e )
    {
        System.out.println (isSelected ());
    }
} );

Or add an ActionListener if you want to recieve changes only from "UI".

But if you really want to know how checkbox changes the state from "UI"...

JCheckBox is nothing ore than a simple button with proper icon for each state, so we should see JButton events

There is nothing about listening to the mouse in the JButton class - its hidden inside of the current ButtonUI

In the BasicButtonUI class you can find the listener added to it:

protected void installListeners(AbstractButton b) {
    BasicButtonListener listener = createButtonListener(b);
    if(listener != null) {
        b.addMouseListener(listener);
        b.addMouseMotionListener(listener);
        b.addFocusListener(listener);
        b.addPropertyChangeListener(listener);
        b.addChangeListener(listener);
    }
}

In BasicButtonListener on mouse release:

public void mouseReleased(MouseEvent e) {
if (SwingUtilities.isLeftMouseButton(e)) {
    // Support for multiClickThreshhold
        if (shouldDiscardRelease) {
        shouldDiscardRelease = false;
        return;
    }
    AbstractButton b = (AbstractButton) e.getSource();
    ButtonModel model = b.getModel();
    model.setPressed(false);
    model.setArmed(false);
    }
}

So that event is sent to the ButtonModel set inside of the button. To capture it you will have to replace ButtonModel inside of the button/check to your own one:

check.setModel ( new DefaultButtonModel ()
{
    public void setSelected ( boolean b )
    {
        super.setSelected ( b );
    }
} );
Mikle Garin
  • 10,083
  • 37
  • 59
  • Just keep in mind that each Swing component has its own UI class and some/all/none action/mouse/key listeners might be there. That depends only on the component kind and the way it was created by Swing developers. Anyway it is pretty simple to find out anything about it if you append JDK sources to your IDE and look into them when needed. – Mikle Garin May 05 '12 at 16:42
1

You need to add an ActionListener to the checkbox.

Moritz Petersen
  • 12,902
  • 3
  • 38
  • 45
1

Although all the comments are relevant and that there is probably no need for extending those components, I did a quick test to determine what code path is followed when you click the button (just out of curiosity). The following piece of code

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import java.awt.EventQueue;

public class JCheckBoxTest {

  private static JCheckBox createCheckBox(){
    JCheckBox checkBox = new JCheckBox();
    checkBox.setModel( new JToggleButton.ToggleButtonModel(){
      @Override
      public void setSelected( boolean b ) {
        Thread.dumpStack();
        super.setSelected( b );
      }
    });
    return checkBox;
  }

  public static void main( String[] args ) {
    EventQueue.invokeLater( new Runnable() {
      @Override
      public void run() {
        JFrame testFrame = new JFrame( "TestFrame" );
        testFrame.add( createCheckBox() );
        testFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        testFrame.pack();
        testFrame.setVisible( true );
      }
    } );
  }
}

allows to determine the stacktrace when the selected state of the model behind the button is changed. The stacktrace shows the following relevant part

at JCheckBoxTest$1.setSelected(JCheckBoxTest.java:19)
at javax.swing.JToggleButton$ToggleButtonModel.setPressed(JToggleButton.java:289)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6505)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)

so basically the listener directly interacts with the button model.

Robin
  • 36,233
  • 5
  • 47
  • 99