Search code examples
javaswingtabsjtabbedpanemiglayout

Swing - button is blocked by the "tabs row" in a JTabbedPane, where there are no tabs


What I want is like:

enter image description here

But the button must be clickable. Now with my SSCCE, this button cannot be clicked. But if I add the button out of this area, e.g. set the y of the bounds of this button to 0, it's no more behind the JTabbedPane's "tabs row", and thus can be clicked.

So:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;

import net.miginfocom.swing.MigLayout;

public class MigLayoutWithJTabbedPaneButton extends JFrame {
    public MigLayoutWithJTabbedPaneButton() {
        begin();
    }

    private void begin() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel();
        panel.setLayout(null);

        JTabbedPane tabsPane = new JTabbedPane();
        tabsPane.setBounds(20, 20, 300, 400);
        panel.add(tabsPane);


        JLayeredPane tab = new JLayeredPane();
        tab.setLayout(new MigLayout("insets 2 2 2 2, fillx, debug", "[]5[]5[]", "[]5[]"));

        JButton button1 = new JButton("In the grid");
        JButton button2 = new JButton("Out of the grid");
        ActionListener ls = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(MigLayoutWithJTabbedPaneButton.this, "This can be clicked. ");

            }
        };
        button1.addActionListener(ls);
        button2.addActionListener(ls);

        tab.add(button1, "cell 0 0, grow");

        tabsPane.addTab("This is a tab", tab);

        button2.setBounds(200, 20, 80, 20);
        panel.add(button2);
        getContentPane().add(panel);

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

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

            @Override
            public void run() {
                MigLayoutWithJTabbedPaneButton frame = new MigLayoutWithJTabbedPaneButton();

            }

        });
    }
}

Why? it's not the desired behaviour. The "tabs row" should not block any elements if they are at the same height of the tabs, but without any actual tabs in front of them.


Solution

  • My colleague told me the reason.

    It has nothing to do with the layout, but just the order of adding the components. It seems that the Z axis of Java Swing behaves in a nonintuitive way: from the top layer to the bottom layer, meaning that if you add component A first and then component B, A will block B if they are in the same place. I reread the Oracle DOC and am sure that it's not mentioned anywhere!

    So to get the button to work, I must first add the button and then the JTabbedPane, so the blank space of the "tabs row" will be behind the button. How strange. Swing just sucks....