Java Swing - 我的 JPanel 正在吃掉我的 JButton

Java Swing - My JPanel is eating my JButton

为了创建我的 GUI,我创建了 JPanel 的多个子类,每个子类都解决了一个特定的布局问题。

第一个是AltBoxLayout_JPanel,灵感来自我之前提出的一个问题的答案(link:):它只是一对JPanels 相互依偎,内部的 BoxLayout 以首选方式分配组件,外部的 BorderLayout 将组件压缩到最小尺寸。

第二个是 Fieldset,灵感来自同名的 HTML 标签:它同样由两个嵌套的 JPanel 组成,最外面的 TitleBorder,在构造函数中给出的内部一个,其目的是在 Fieldset 区域内设置布局。

我分别测试了这两个专用组件,效果不错,对它们很满意。最近我需要同时使用它们:我想要一个 JButton 和一个 JTextArea 显示在另一个之上而不被人为扩展(即在 AltBoxLayout_JPanel 内),并被边框包围(即 Fieldset 中的 AltBoxLayout_JPanel)。由于我所有的组件都已经过测试,所以我确信它会顺利进行。

没有。

不知何故,我的 JButton 不再可见了。我知道它在那里(我检查过)并且我 假设 它包含在 JTextArea 中,但我没有更多信息。下面是我的代码。

任何帮助拯救我的 JButton 的人都将不胜感激!



public class WhosebugQuestion extends JFrame {

    private static final long serialVersionUID = -5644282466098799568L;

    private JPanel contentPanel;
        

    // Display area
        
    private Fieldset fieldset;
    private JButton button;
    private JTextArea jTextArea;
        
    /**
     * Create the frame.
     */
    public WhosebugQuestion() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 300, 140);
        contentPanel = new JPanel();
        contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPanel.setLayout(new BorderLayout(0, 0));
        setContentPane(contentPanel);
        
    // Testing new components
        
    //  JPanel fieldsetLayoutPanel = new JPanel();
    //  BoxLayout fieldsetLayout = new BoxLayout(fieldsetLayoutPanel, BoxLayout.PAGE_AXIS);
    //  fieldsetLayoutPanel.setLayout(fieldsetLayout);
        
        JPanel fieldsetLayoutPanel_2 = new AltBoxLayout_JPanel(BoxLayout.PAGE_AXIS);
        
        this.fieldset               = new Fieldset("Fieldset title", fieldsetLayoutPanel_2, null);
        this.button                 = new JButton("Button text");
        this.jTextArea              = new JTextArea("JTextArea here!");
        this.jTextArea.setRows(5);
        this.jTextArea.setColumns(20);
        this.button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                System.out.println("Action executed: " + arg0.toString());
            }});
            
        fieldset.add(button);
        fieldset.add(jTextArea);
        contentPanel.add(fieldset);

        System.out.println("Analysis of the components of the contentPanel:");
        analyzeLayoutsOfComponentAndSubComponents(contentPanel, 0);
            
        pack();
            
    }

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    WhosebugQuestion frame = new WhosebugQuestion();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /** A method that studies the {@link JPanel} and its sub-{@link JPanel}s, iterating through all the component tree.
     * 
     * @param c
     * @param tab
     */
    public static void analyzeLayoutsOfComponentAndSubComponents(JPanel c, int tab) {
        System.out.println(repeatChar('\t', tab) + c.toString());
        for(int i=0 ; i<c.getComponentCount() ; i++)
            if( c.getComponent(i) instanceof JPanel )
                analyzeLayoutsOfComponentAndSubComponents( (JPanel)c.getComponent(i), tab+1 );
    }
    
    public static String repeatChar(char c, int tab) {
        StringBuffer support = new StringBuffer();
        for(int i=0 ; i<tab ; i++)      support.append(c);
        return support.toString();
    }
    
        
        
    
    
    public class Fieldset extends JPanel {
        
        private static final long serialVersionUID = -1464052286624448783L;
        
        /** The {@link Border} of {@code this} {@link Fieldset}.                */
        private Border border;
        /** The {@link JPanel} responsible for the layout management.           */
        public JPanel layoutPanel;
            
        /** Creates a new {@link Fieldset}. 
         * 
         * @param colorBorder The {@link Color} of the border. If {@code null}, {@code Color.BLACK} is chosen.
         * 
         */
        public Fieldset(String titleFieldset, JPanel panel, Color colorBorder) {
            super();
            
            this.border = new TitledBorder(new LineBorder(colorBorder == null ? Color.BLACK : colorBorder), titleFieldset);
            this.setBorder(border);
            this.layoutPanel = panel;
            
            super.add(layoutPanel);
        }
        
        public Component add(Component component) {
            this.layoutPanel.add(component);
            return component;
        }
            
    }


    public class AltBoxLayout_JPanel extends JPanel {
        
        private static final long serialVersionUID = -8204033141468207723L;
        
        private JPanel layoutPanel;
        
        /** Creates a new {@link AltBoxLayout_JPanel}.
         * 
         * @param axisOrientation A constant from the {@link BoxLayout} class representing the chosen insertion axis.
         */
        public AltBoxLayout_JPanel(int axisOrientation) { 
            // ===== INNER PANEL =====
            this.layoutPanel = new JPanel(); //This is the nested panel
            layoutPanel.setLayout(new BoxLayout(layoutPanel, axisOrientation));
            
            // ===== OUTER PANEL =====
            this.setLayout(new BorderLayout());
            this.add(layoutPanel, BorderLayout.PAGE_START);
        
            System.out.println("Analysis of the components of the AltBoxLayout_JPanel:");
            analyzeLayoutsOfComponentAndSubComponents(this, 0);
        }
        public void add(JComponent component) {
            layoutPanel.add(component);
        }
    }

}

您的 Fieldset class 中的 layoutPanel 似乎将组件堆叠在彼此之上,因为它的默认布局告诉它这样做。 只是开始,尝试在 Fieldset:

的构造函数中为其设置一个简单的 BoxLayout
this.layoutPanel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

您的按钮将可见。所以,完整的构造函数应该是这样的:

public Fieldset(String titleFieldset, JPanel panel, Color colorBorder) {
    super();    
    this.border = new TitledBorder(new LineBorder(colorBorder == null ? Color.BLACK : colorBorder), titleFieldset);
    this.setBorder(border);
    this.layoutPanel = panel;
    this.layoutPanel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
    super.add(layoutPanel);
}