簡體   English   中英

如何通過單擊JButton添加JPanel?

[英]How to add JPanel by clicking JButton?

我正在嘗試創建一個小的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();
            }
        });

    }

}

為了在添加/刪除或調整可見容器上的組件大小后反映更改,在添加/刪除或調整組件大小后,在容器實例上調用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類,只需像創建JFrame一樣創建一個JButton實例,並在JButton實例上調用方法。

  • 不要忘記在Event Dispatch Thread上創建/操作Swing組件,通過SwingUtilities.invokeLater(..)塊, 在此處閱讀更多內容。

以下是您修復的代碼(以上建議已實施):

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 /容器上的多個組件之間進行切換。

這是我做的一個例子:

在此輸入圖像描述

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上的所有組件,然后添加新內容並調用revalidate()repaint() (也可能想要添加pack()在那里)在JFrame實例上反映變化。 雖然我推薦CardLayout

我想你可以使用CardLayout來實現你的功能。 請參考這里

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM