Question

Normal JCheckbox react directly on user input and sets or unsets the tick. After this the MouseListener is called. What I want to achieve is that the state of the JCheckbox can only be changed by the controller. What are decent way to achieve this?

I tried to add a mouse listener which immediatly add/removes the tick again but this results in flickering.

The only way I found was to overwrite the processMouseEvent method but this is really bad...

EDIT (my current version): This does now work now. Missed to adjust the model before.

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.EventListener;
import javax.swing.JCheckBox;

public class MyJCheckBox extends JCheckBox {
    public MyJCheckBox() {
        MouseListener[] ml = (MouseListener[]) this.getListeners(MouseListener.class);

        for (int i = 0; i < ml.length; i++) {
            this.removeMouseListener(ml[i]);
            this.addMouseListener(new MouseListenerWrapper(ml[i]));
        }

    }

    public void addClickListener(ClickListener listener) {
        listenerList.add(ClickListener.class, listener);
    }

    private class MouseListenerWrapper implements MouseListener {
        MouseListener listener;

        public MouseListenerWrapper(MouseListener listener) {
            this.listener = listener;
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            listener.mouseClicked(e);
        }

        @Override
        public void mousePressed(MouseEvent e) {
            listener.mousePressed(e);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            for(ClickListener listener : listenerList.getListeners(ClickListener.class)) {
                listener.onClick();

                            //Adjust model
                MyJCheckBox.this.getModel().setArmed(false);
                MyJCheckBox.this.getModel().setPressed(false);
            }

        }

        @Override
        public void mouseEntered(MouseEvent e) {
            listener.mouseEntered(e);
        }

        @Override
        public void mouseExited(MouseEvent e) {
            listener.mouseExited(e);
        }
    }
}

interface ClickListener extends EventListener {
    public void onClick();
}
Was it helpful?

Solution

I don't like it when people play with the UI. This will confuse the user and they will think the application is broken if they can't click on the check box.

Anyway, remove the MouseListener from the check box.

MouseListener[] ml = (MouseListener[])checkBox.getListeners(MouseListener.class);

for (int i = 0; i < ml.length; i++)
    checkBox.removeMouseListener( ml[i] );

OTHER TIPS

There is another way to implement the behaviour I would like to have if you overwrite the paint method and change the model according to your needs before you paint it.

import java.awt.Graphics;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;

public class MyJCheckBox extends JCheckBox {
    private boolean change = false;
    private boolean previousState = false;

    @Override
    public void setSelected(boolean selected) {
        if(this.isSelected() != selected) {
            change = true;
    }
        super.setSelected(selected);
    }

    @Override
    public void paint(Graphics g) {
        AbstractButton b = this;
        ButtonModel model = b.getModel();

        boolean changeRequest = false;

        //adjust model state to our needs. A state change
        //is only possible if it was requested by
        //setSelected()

        if(previousState != model.isSelected()) {
            //Revert change if it was not requested by
            //by setSelected()
            if(! change) {
                 changeRequest = true;
                 model.setSelected(previousState);
            }
            //Reset change to false so it can only be changed once
            //To change it again you have to call setSelected() again.
            change = false;
        }

        //Set current state as previous state
        previousState = model.isSelected();

        //paint with adjusted model
        super.paint(g);

        //Inform listener that a change was requested
        if(changeRequest) {
            for(ClickListener listener : listenerList.getListeners(ClickListener.class)) {
            listener.onClick();
            }
        }
    }
}

interface ClickListener extends EventListener {
    public void onClick();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top