2

I've got an icon, with a checkbox next to it, contained in a panel. The panel has a hover effect, and I want to select the box when the panel is clicked.

I'd like to consume or prevent all events to the checkbox, only selecting it programatically. I'd like the box to appear "enabled" onscreen, while "behind the scenes" it's pretty much non-functional. (Selection would happen from a click in the panel.)

Further, when I mouse enter/exit the checkbox, I'd like nothing to happen. I've got a hover effect on the panel. Right now, I can enter the panel, but then when I enter the box, the panel exits, and looks un-hovered.

So, how can I prevent all mouse-related activities on this checkbox - enter, exit, click, etc. From previous research I recall the buzzwords "consume events", but I can't seem to drum up the appropriate searches to make this happen :)

============

EDIT

enter image description here

This panel (purple) has an icon (hamburger) and a checkbox (UI LAF). I want to hover the panel, not lose the hover when I enter the checkbox, and toggle the checkbox when the (parent) panel is clicked.

casperOne
  • 73,706
  • 19
  • 184
  • 253
Ben
  • 54,723
  • 49
  • 178
  • 224
  • 1
    Might be easier to replace the checkbox with a toggling image. – Sam Dufel Apr 20 '12 at 00:17
  • @SamDufel - was thinking that, but then it introduces non-platform elements into the UI...would like things to be consistent, you know. – Ben Apr 20 '12 at 00:53
  • Have you tried `AWTEvent.consume()`? http://docs.oracle.com/javase/6/docs/api/java/awt/AWTEvent.html#consume() – Michael Brewer-Davis Apr 20 '12 at 02:23
  • Not yet, but it sounds like that's what I'm looking for. Will try soon. – Ben Apr 20 '12 at 03:50
  • I think you should lose the check-box completely and use a [`JToggleButton`](http://stackoverflow.com/a/7360696/418556). Obviously this would need for the images to indicate selection, but reduces the (small) need to associate the check with the image, in a display that might contain 40. In your case, perhaps have that image for selected burger, but leave out the 'rays' for unselected. – Andrew Thompson Apr 20 '12 at 04:53
  • @Andrew Thompson - now we're back to the "toggling image" suggestion...I want to have the intuitive experience of a checkbox. Anyway, may go with a toggling image, after I try these suggestions later. Thanks for the help. You might want to put up another answer for the JToggleButton in case I head that direction, it would be helpful to have something to accept. – Ben Apr 20 '12 at 05:07
  • @SamDufel Did you mean an image with a check, or something more along the lines of what I am suggesting? – Andrew Thompson Apr 20 '12 at 05:30
  • BTW - what if I want ***2*** burgers. And yes, thanks, I'll have fries & a shake with that. ;) – Andrew Thompson Apr 20 '12 at 05:37
  • @AndrewThompson - it's a filter toggle for a table, so this would hide/show all menu items of type "burger". Fries & shake are in the mail. – Ben Apr 21 '12 at 08:03
  • @MichaelBrewer-Davis - thanks, but didn't work (unfortunately, it would be too easy :) ). – Ben Apr 23 '12 at 09:37

5 Answers5

3

Override dispatchEvent() in EventQueue and push() a new instance, which then replaces the old. In your new implementation, invoke super.dispatchEvent() for all events except those related to your checkbox. A related example may be found here, and a complete implementation may be found in Disabled Panel.

Alternatively, use Toolkit.getDefaultToolkit().addAWTEventListener(), as shown here, to elide unwanted events.

Addendum: Also consider this more user friendly alternative that leverages the check box's button model:

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;

/** @see https://stackoverflow.com/a/10238761/230513 */
public class PanelClick extends JPanel {

    JCheckBox jcb = new JCheckBox("Check");
    private boolean selected = jcb.isSelected();

    public PanelClick() {
        this.setPreferredSize(new Dimension(320, 240)); // room to click
        this.add(jcb);
        this.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
                selected = !jcb.isSelected();
                jcb.setSelected(selected);
            }
        });
    }

    private void display() {
        JFrame f = new JFrame("PanelClick");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new PanelClick().display();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
2

Could this serve as a solution?

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;

public class PanelCheckBox {

    private JPanel panel = new JPanel();
    private JCheckBox checkBox = new JCheckBox();
    private JLabel icon = new JLabel(new SquareIcon());

    private void showGui() {
        final JFrame frame = setupGui();

        SwingUtilities.invokeLater(new Runnable() {
            @Override public void run() { 
                frame.setVisible(true);
            }
        });
    }

    private JFrame setupGui() {
        panel.add(icon);
        panel.add(checkBox);
        panel.setOpaque(true);
        JFrame frame = new JFrame("Hello");
        frame.add(panel, BorderLayout.CENTER);

        setupListeners();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 200);
        return frame;
    }

    private void setupListeners() {
        panel.addMouseListener(new MouseAdapter() {
            Color origColor = null;
            Color hoverColor = new Color(200, 180, 180);

            @Override public void mouseEntered(MouseEvent me) {
                if (origColor == null) {
                    origColor = panel.getBackground();
                }
                panel.setBackground(hoverColor);
            }

            @Override public void mouseExited(MouseEvent me) {
                Point location = me.getPoint();

                if (!panel.contains(location)) {
                    panel.setBackground(origColor);
                }
            }

            @Override public void mouseClicked(MouseEvent me) {
                checkBox.doClick();
            }
        });
    }

    public static void main(String[] args) {
        PanelCheckBox thing = new PanelCheckBox();
        thing.showGui();
    }

    static class SquareIcon implements Icon {

        @Override
        public void paintIcon(Component cmpnt, Graphics grphcs,
                              int i, int i1) {
            Color origColor = grphcs.getColor();
            grphcs.setColor(Color.BLUE);
            grphcs.fillRect(0, 0, 25, 25);
            grphcs.setColor(origColor);
        }

        @Override public int getIconWidth() { return 25; }

        @Override public int getIconHeight() { return 25; }
    }
}
black panda
  • 2,842
  • 1
  • 20
  • 28
1

I'd like the box to appear "enabled" onscreen, while "behind the scenes" it's pretty much non-functional.

I would find it pretty frustrating to repeatedly click a supposedly enabled check-box to see it do ..nothing. Perhaps you should pop a:

JOptionPane.showErrorMessage(checkbox, "Click the panel!"); 
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • +1 for advocating the user's position; see also [*Disabled Panel*](http://tips4java.wordpress.com/2009/08/02/disabled-panel/) for more. – trashgod Apr 20 '12 at 01:18
  • Sorry if I was unclear; the checkbox is IN the panel; so it would be responsive, and definitely appear to be behaving the same way. The only difference would be, the event is triggered using a `setSelect` from when anywhere inside the panel is clicked (icon, padding, or checkbox). – Ben Apr 20 '12 at 01:22
  • `I want to select the box when the panel is clicked.` Not sure how to convey what I mean. Click the panel, the box selects. Click the panel, the box deselects. Same same. Only, the action comes from a listener in the panel, and the box's listeners are non-functional. – Ben Apr 20 '12 at 01:24
  • @trashgod - deleted old answer? Looked good, I wanted to give it a whirl :) – Ben Apr 20 '12 at 01:28
  • @Steve: I've restored the answer for completeness, and added a simpler [implementation](http://stackoverflow.com/a/10238761/230513) that may suffice. I still endorse Andrew's caution. :-) – trashgod Apr 20 '12 at 01:39
  • What is on the rest of the panel? I'm wondering why you don't just add it as the single component at `BorderLayout.CENTER` and add an `ActionListener`. Can you explain to me in terms so simple a user could understand, what feature does this functionality offer? – Andrew Thompson Apr 20 '12 at 01:44
  • There is no "rest of the panel" - that is the panel. There are two components in it: the icon and the box. When I click anywhere in it, the box should be toggled. When I am mousing through it - over the box - a `mouseExited()` event should not be fired. See edited question with pic. But you may be on to something - there may be a completely better way to accomplish the same thing lol. – Ben Apr 20 '12 at 03:49
1

You could override the mouselistener for the checkbox to do nothing:

class MyBox extends JCheckBox {

    @Override
    protected void processMouseEvent(MouseEvent e) {
    //this will prevent all mouse actions 
    }
}

Then just use MyBox instead of checkbox?

Tisho
  • 8,320
  • 6
  • 44
  • 52
Zee
  • 11
  • 1
0

My final solution for this was to use an EmptyBorder on the left side of the checkbox, and BlackPanda's mouse listener solution:

public class CheckboxPanel extends JPanel {
    private final JCheckBox checkBox = new JCheckBox();
    private final Image img;

    public CheckboxPanel (final Image img0) {
        super();
        this.img = img0;

        // Left padding of 20 allows mouseovers on image that trigger the box.
        checkBox.setBorder(new EmptyBorder(0, 20, 0, 0)); 

        add(checkBox);

        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(final MouseEvent me) {
                checkBox.doClick();
            }
        });
    }

    public JCheckBox getCheckBox() {
        return this.checkBox;
    }

    @Override
    protected void paintComponent(final Graphics g) {
        super.paintComponent(g);
        g.drawImage(img, 0, 0, null);
    }
}
Ben
  • 54,723
  • 49
  • 178
  • 224