2

I have some custom JPanels that are used as buttons. This works well 90% of the time, however, sometimes the GUI doesn't respond to a mouse click - the mouseClicked event is not triggered and you have to click again (sometimes even more than once) to actually trigger it.

This behavior appears to be random, though I have the feeling that it occurs more frequently after having moved the frame to another monitor.

Here is the code:

public class EatingMouse extends JFrame implements MouseListener {
    JPanel contentPane;
    int contentPanelWidth, contentPanelHeight;
    int mainTabMarginHeight, mainTabMarginWidth;
    int subTabMarginHeight, subTabMarginWidth;

    Color fontColor = Color.WHITE;
    Color tabBackgroundColor = Color.BLACK;
    Color tabBackgroundHighlightColor = Color.GRAY;
    Color tabBackgroundSelectedColor = Color.LIGHT_GRAY;

    TabPanel firstMainTab;
    TabPanel secondMainTab;
    ArrayList<TabPanel> firstSubTabs;
    ArrayList<TabPanel> secondSubTabs;
    ArrayList<TabPanel> currentSubTabs;

    int clickCounter;


    public EatingMouse() {
        super("Why do you eat mouse clicks?");

        JLayeredPane layeredPane = new JLayeredPane();
        firstMainTab = new TabPanel("First Tab", 18);
        firstMainTab.addMouseListener(this);
        layeredPane.add(firstMainTab, new Integer(100));
        secondMainTab = new TabPanel("Second Tab", 18);
        secondMainTab.addMouseListener(this);
        layeredPane.add(secondMainTab, new Integer(100));
        firstSubTabs = new ArrayList<>();
        secondSubTabs = new ArrayList<>();
        currentSubTabs = new ArrayList<>();

        TabPanel tp = new TabPanel("First First Subtab", 14);
        tp.addMouseListener(this);
        layeredPane.add(tp, new Integer(100));
        firstSubTabs.add(tp);
        tp = new TabPanel("Second First Subtab", 14);
        tp.addMouseListener(this);
        layeredPane.add(tp, new Integer(100));
        firstSubTabs.add(tp);

        tp = new TabPanel("First Second Subtab", 14);
        tp.addMouseListener(this);
        layeredPane.add(tp, new Integer(100));
        secondSubTabs.add(tp);
        tp = new TabPanel("Second Second Subtab", 14);
        tp.addMouseListener(this);
        layeredPane.add(tp, new Integer(100));
        secondSubTabs.add(tp);


        contentPane = new JPanel(new BorderLayout());
        setContentPane(contentPane);
        contentPane.add(layeredPane);

        mainTabMarginWidth = 40;
        mainTabMarginHeight = 8;
        subTabMarginWidth = 20;
        subTabMarginHeight = 10;
        selectTabs(0, 1);

        clickCounter = 0;
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(new Dimension(800, 600));
        setVisible(true);
    }

    public void selectTabs(int mainTab, int subTab) {
        boolean hasChanged = false;

        if((mainTab == 0) && !firstMainTab.isSelected) {
            hasChanged = true;
            firstMainTab.setSelected(true);
            secondMainTab.setSelected(false);
            for(TabPanel tp : currentSubTabs) {
                tp.setSelected(false);
                tp.setVisible(false);
            }
            currentSubTabs = firstSubTabs;
            for(TabPanel tp : currentSubTabs) {
                tp.setVisible(true);
            }
            currentSubTabs.get(subTab).setSelected(true);
        }
        else if((mainTab == 1) && !secondMainTab.isSelected) {
            hasChanged = true;
            firstMainTab.setSelected(false);
            secondMainTab.setSelected(true);
            for(TabPanel tp : currentSubTabs) {
                tp.setSelected(false);
                tp.setVisible(false);
            }
            currentSubTabs = secondSubTabs;
            for(TabPanel tp : currentSubTabs) {
                tp.setVisible(true);
            }
            currentSubTabs.get(subTab).setSelected(true);
        }
        else if((mainTab == 0) && firstMainTab.isSelected) {
            hasChanged = true;
            for(TabPanel tp : currentSubTabs) {
                if(tp != currentSubTabs.get(subTab)) { tp.setSelected(false); }
                else { tp.setSelected(true); }
            }
        }
        else if((mainTab == 1) && secondMainTab.isSelected) {
            hasChanged = true;
            for(TabPanel tp : currentSubTabs) {
                if(tp != currentSubTabs.get(subTab)) { tp.setSelected(false); }
                else { tp.setSelected(true); }
            }
        }
        if(hasChanged) {
            revalidate();
            repaint();
        }
    }


    @Override
    public void paint(Graphics graphics) {
        super.paint(graphics);
        contentPanelWidth = getContentPane().getWidth();
        contentPanelHeight = getContentPane().getHeight();

        int xOffset = 100;
        int yOffset = 100;
        FontMetrics mainTabMetrics = graphics.getFontMetrics(firstMainTab.label.getFont());
        firstMainTab.setBounds(xOffset, yOffset, (mainTabMetrics.stringWidth(firstMainTab.text) + mainTabMarginWidth), (mainTabMetrics.getHeight() + mainTabMarginHeight));
        xOffset += firstMainTab.getBounds().width;
        secondMainTab.setBounds(xOffset, yOffset, (mainTabMetrics.stringWidth(secondMainTab.text) + mainTabMarginWidth), (mainTabMetrics.getHeight() + mainTabMarginHeight));
        FontMetrics subTabMetrics = graphics.getFontMetrics(currentSubTabs.get(0).label.getFont());
        xOffset  = 100;
        yOffset += firstMainTab.getBounds().height;
        for(TabPanel tp : currentSubTabs) {
            tp.setBounds(xOffset, yOffset, (subTabMetrics.stringWidth(tp.text) + subTabMarginWidth), (subTabMetrics.getHeight() + subTabMarginHeight));
            tp.revalidate();
            tp.repaint();
            xOffset += tp.getBounds().width;
        }
    }


    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.println("click " + clickCounter++);
        Object source = e.getSource();
        if(source == firstMainTab && !firstMainTab.isSelected) {
            secondMainTab.setSelected(false);
            if(currentSubTabs.get(1).isSelected) { selectTabs(0, 1); }
            else { selectTabs(0, 0); }
        }
        else if(source == secondMainTab && !secondMainTab.isSelected) {
            if(currentSubTabs.get(1).isSelected) { selectTabs(1, 1); }
            else { selectTabs(1, 0); }
        }
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        Object source = e.getSource();
        if(source == firstMainTab && !firstMainTab.isSelected) { firstMainTab.setBackground(tabBackgroundHighlightColor); }
        else if(source == secondMainTab && !secondMainTab.isSelected) { secondMainTab.setBackground(tabBackgroundHighlightColor); }
        else if(currentSubTabs.contains(source) && !((TabPanel) source).isSelected) {
            ((TabPanel)source).setBackground(tabBackgroundHighlightColor);
        }
    }

    @Override
    public void mouseExited(MouseEvent e) {
        Object source = e.getSource();
        if(source == firstMainTab && !firstMainTab.isSelected) { firstMainTab.setBackground(tabBackgroundColor); }
        else if(source == secondMainTab && !secondMainTab.isSelected) { secondMainTab.setBackground(tabBackgroundColor); }
        else if(currentSubTabs.contains(source) && !((TabPanel) source).isSelected) {
            ((TabPanel)source).setBackground(tabBackgroundColor);
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    public class TabPanel extends JPanel {
        JLabel label;
        String text;
        boolean isSelected;

        public TabPanel(String labelText, int fontSize) {
            super();
            text = labelText;
            isSelected = false;
            setLayout(new GridBagLayout());
            setBackground(tabBackgroundColor);

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.PAGE_START;
            gbc.fill = GridBagConstraints.BOTH;
            gbc.weighty = 0.1;
            gbc.weightx = 0.1;
            gbc.insets = new Insets(0,0,0,0);
            label = new JLabel("<html><div style=\"text-align:center\"> " + text + "</div></html>", SwingConstants.CENTER);
            label.setAlignmentX(JLabel.CENTER_ALIGNMENT);
            label.setForeground(fontColor);
            label.setFont(new Font("Arial", Font.BOLD, fontSize));
            add(label, gbc);
        }


        public void setSelected(boolean selected) {
            isSelected = selected;
            if(selected) { setBackground(tabBackgroundSelectedColor); }
            else { setBackground(tabBackgroundColor); }
        }
        public boolean isSelected() { return isSelected; }

        @Override
        public String toString() {
            return text + " - " + label.getFont().getSize();
        }
    }

    public static void main(String[] args) {
        new EatingMouse();
    }
}

Please note that I have chosen JPanels as buttons because I want to heavily customize them later, which I didn't get to work with extending JButton.

Thank you for your time reading this and of course I would appreciate any leads on why this is happening and what I can do to improve this code.

Markstar
  • 639
  • 9
  • 24
  • 1
    Hi Took your code and executed it: my observation was, that if you move the mouse just by a pixel (or more) the click will not be recognized as click. If moved by one or very few pixels, it "looks" like a click but was not recognized. – SirFartALot May 14 '19 at 10:07
  • 5
    Don't override mouseClicked. Override mousePressed instead. Or better still -- use JButtons and get them to work for you. – Hovercraft Full Of Eels May 14 '19 at 10:22
  • Thanks guys. `mousePressed` seems to have done it. @SirFartALot: Yeah, but why?? @Hovercraft: I wish I knew how to get `JButton` to look like I want to, but somehow I can't manage and I end up with tons of layout problems. :( – Markstar May 14 '19 at 11:00
  • Just do not call `super.paint()` and clear the graphics... – SirFartALot May 14 '19 at 11:23
  • You can only tag one person at a time (single comment), so your tag to @HovercraftFullOfEels didn't notified him. What do you mean with `heavily customize them`? `JButtons` can be customized as well and you need to override their `paintComponent(...)` method and not `paint(...)` (either for buttons or panels) and also not extending `JFrame`. – Frakcool May 14 '19 at 14:54
  • `JButtons`, `JPanels`, `JLabels` are all containers, and you can heavily customize them (even add some elements to them and set their layouts), see [this example](https://stackoverflow.com/questions/42437948/how-can-i-add-an-image-to-a-panel/42446498#42446498) – Frakcool May 14 '19 at 14:59
  • I'm not saying `JButton` can't be customized, I'm saying I'm not skilled enough (yet, hopefully) to do so that I'm satisfied with the result in a reasonable amount of time. – Markstar May 15 '19 at 08:37

0 Answers0