首页 文章

如何通过单击JButton添加JPanel?

提问于
浏览
5

我正在尝试创建一个小的GUI,它有2个JButton和2个JPanel,每个都有一些绘图动画 . 默认情况下,它必须显示第一个JPanel,并通过单击第二个JButton我想看到我的第二个JPanel . 所以:我创建了JFrame,Panel1和Panel2,在那里我绘制了我的动画,创建了Button1和Button2并添加了ActionListeners . 我还有MainPanel,它有一个字段变量i . 通过更改此“i”我的构造函数将MainPanel添加到Panel1(默认)或Panel2(通过单击JButton2我更改i) . 比我把这个MainPanel添加到我的框架 . 所以我的问题:在类MainPanel中我有refreshMe方法,我应该在那里写什么才能让我的GUI正常工作?谢谢 . 这是我的代码:

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

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GuiTest {

    public static void main(String[] args) {
        JFrame f = new JFrame();
        MainPanel myPanel = new MainPanel();
        f.add(myPanel);
        Button1 button1 = new Button1();
        Button2 button2 = new Button2();
        myPanel.add(button1);
        myPanel.add(button2);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }
}

class MainPanel extends JPanel {
    Panel1 p1 = new Panel1();
    Panel2 p2 = new Panel2();
    public int i = 1;  //this is being changed later by clicking JButton
    // I use this setter later in actionPerformed in order to change i
    public void setI(int i) {
        this.i = i;
    }

    MainPanel() { 
        if (i == 1) {
            this.add(p1);
        }
        if (i == 2) {
            this.add(p2);
        }
    }

    public void refreshMe() {
        // Need some help here:
        // I don't know what should I write, how to make a repaint of myPanel?
        System.out.println("just test, if the method refreshMe working by clicking some button");
    }
}

class Panel1 extends JPanel {

    public Panel1() {
        this.setBackground(Color.BLUE);
        // a lot of drawing stuff going on here
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }
}

class Panel2 extends JPanel {

    public Panel2() {
        this.setBackground(Color.GREEN);
        // a lot of drawing stuff going on here
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

}

class Button1 extends JButton {
    MainPanel someObj1 = new MainPanel();

    Button1() {
        setText("Show Annimation A");
        addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                someObj1.setI(1);
                System.out.println("The variable i is now: " + someObj1.i);
                someObj1.refreshMe();

            }
        });
    }

}

class Button2 extends JButton {
    MainPanel someObj2 = new MainPanel();

    Button2() {
        setText("Show Annimation B");
        addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                someObj2.setI(2);
                System.out.println("The variable i is now: " + someObj2.i);
                someObj2.refreshMe();
            }
        });

    }

}

2 回答

  • 8

    为了在添加/删除或调整可见容器上的组件后反映更改,在添加/删除或调整组件大小后,在容器实例上调用 revalidate()repaint() .

    虽然这在你的代码中不起作用,但主要的原因是在JButton类中重新创建 MainPanel 的新实例,而实际上2 JButtons 应该共享正在使用的单个实例(你可以将MainPanel实例传递给 JButton 的构造函数,但是除非添加自定义功能,否则你不应该真正扩展 JButton

    class Button2 extends JButton {
        MainPanel someObj2 = new MainPanel();//you create an instance of MainPanel which isnt even showing and than do changes on that, this way you will never see any of the changes
    
        Button2() {
        }
    }
    

    关于您的代码的一些其他建议:

    • 不要不必要地扩展 JButton 类,只需创建 JButton 的实例,就像使用 JFrame 一样,并在 JButton 实例上调用方法 .

    • 别忘了在 Event Dispatch Thread 上创建/操作Swing组件,通过 SwingUtilities.invokeLater(..) 块,阅读here了解更多信息 .

    以下是您修复的代码(以上建议已实施):

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class Test {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    JFrame f = new JFrame();
    
                    final MainPanel myPanel = new MainPanel();
                    f.add(myPanel);
    
                    JButton button1 = new JButton("Show Animation A");
                    JButton button2 = new JButton("Show Animation B");
    
                    button1.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            myPanel.setI(1);
                            System.out.println("The variable i is now: " + myPanel.i);
                            myPanel.refreshMe();
                        }
                    });
                    button2.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            myPanel.setI(2);
                            System.out.println("The variable i is now: " + myPanel.i);
                            myPanel.refreshMe();
                        }
                    });
    
                    myPanel.add(button1);
                    myPanel.add(button2);
                    myPanel.checkPanel();
    
                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
                    f.pack();
                    f.setVisible(true);
                }
            });
        }
    }
    
    class MainPanel extends JPanel {
    
        Panel1 p1 = new Panel1();
        Panel2 p2 = new Panel2();
        public int i = 1;  //this is being changed later by clicking JButton
        // I use this setter later in actionPerformed in order to change i
    
        public void setI(int i) {
            this.i = i;
        }
    
        public void refreshMe() {
            checkPanel();
    
            revalidate();
            repaint();
            // Need some help here:
            // I don't know what should I write, how to make a repaint of myPanel?
            System.out.println("just test, if the method refreshMe working by clicking some button");
        }
    
        public void checkPanel() {
            if (i == 1) {
                this.add(p1);
                this.remove(p2);//or it will remain there as this is default flowlayout
            } else if (i == 2) {
                this.add(p2);
                this.remove(p1);
            }
        }
    }
    
    class Panel1 extends JPanel {
    
        public Panel1() {
            this.setBackground(Color.BLUE);
            // a lot of drawing stuff going on here
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }
    }
    
    class Panel2 extends JPanel {
    
        public Panel2() {
            this.setBackground(Color.GREEN);
            // a lot of drawing stuff going on here
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }
    }
    

    但是,我建议更简单,幸运的是你有两个选择:

    1)使用CardLayout,它允许您在单个 JFrame /容器上的多个组件之间进行切换 .

    这是我做的一个例子:

    enter image description here

    import java.awt.BorderLayout;
    import java.awt.CardLayout;
    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.JPanel;
    import javax.swing.SwingUtilities;
    
    public class Test {
    
        private final static String PANEL1 = "panel 1";
        private final static String PANEL2 = "panel 2";
    
        public Test() {
            initComponents();
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Test();
                }
            });
        }
    
        private void initComponents() {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            JPanel panel1 = new JPanel();
            panel1.add(new JLabel("Panel 1"));
    
            JPanel panel2 = new JPanel();
            panel2.add(new JLabel("Panel 2"));
    
            //Create the panel that contains the "cards".
            final JPanel cards = new JPanel(new CardLayout());
            cards.add(panel1, PANEL1);
            cards.add(panel2, PANEL2);
    
            //create button to allow chnage to next card
            JButton buttonNext = new JButton(">");
            buttonNext.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    CardLayout cl = (CardLayout) (cards.getLayout());//get cards
                    cl.next(cards);
                }
            });
    
            //create button to allow chnage to previous card
            JButton buttonPrev = new JButton("<");
            buttonPrev.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    CardLayout cl = (CardLayout) (cards.getLayout());//get cards
                    cl.previous(cards);
                }
            });
    
            //create panel to hold buttons which will allow switching between cards
            JPanel buttonPanel = new JPanel();
            buttonPanel.add(buttonPrev);
            buttonPanel.add(buttonNext);
    
    
            frame.add(cards);
            frame.add(buttonPanel, BorderLayout.SOUTH);
    
            frame.pack();
            frame.setVisible(true);
        }
    }
    

    2)使用 removeAll() 技术,即调用 frame.getContentPane().removeAll() ,这将删除当前在 JFrame 上的所有组件,然后添加新内容并在 JFrame 实例上调用 revalidate()repaint() (也可能想在其中添加 pack() )以反映更改 . 虽然我推荐 CardLayout .

  • 3

    我想你可以使用 CardLayout 来实现你的功能 . 请参考here

相关问题