如何在Java中设置另一个class的Layout?

How to set Layout with another class in Java?

我正在编写一个带有复杂 TabbedPane 的程序,其中包含很多元素。由于我在我的一个 classes 中达到了字节限制,我决定将 class 拆分为 Initialisation/Button 监听器和实际的 GridBagLayout。但是现在我无法让它工作。我的主要 Class 看起来像这样:

public class Main{
JFrame mainFrame = new JFrame("");
JTabbedPane tabpane = new JTabbedPane();
JPanel panelTab1 = new Tab1();
JScrollPane scrollTab2 = new JScrollPane(new Tab2());
JScrollPane scrollTab3 = new JScrollPane(new Tab3());
JPanel panelTab4 = new Tab4();
JMenuBar bar = new MenuBar();


public Main(){
    tabpane.add("Tab1", panelTab1);
    tabpane.add("Tab2", scrollTab2);
    tabpane.add("Tab3", scrollTab3);
    tabpane.add("Tab4", panelTab4);
    mainFrame.getContentPane().add(tabpane);
    mainFrame.setSize(1920,1080);   
    mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    mainFrame.setVisible(true);     
    mainFrame.validate();
    mainFrame.setJMenuBar(bar);

}



public static void main(String[] args)
{

    SwingUtilities.invokeLater(new Runnable(){
        public void run(){
            new Main();
        }
    });


}}

Tab3 是罪魁祸首,所以这是我拆分的两个 classes。

public class Tab3 extends JPanel {
JPanel Annex = new JPanel();
//A Bunch of Labels and Buttons
.
.
.
public Tab3(){
//ActionListeners for the Buttons
this.setLayout(new BorderLayout());
this.add(Annex,BorderLayout.WEST);
this.add(Bsp,BorderLayout.EAST);
}}

所有的GridBagLayout在下面class:

public class Tab3Layout extends Tab3{
    public Tab3Layout(){
        Annex.setLayout(new GridBagLayout());
        GridBagConstraints co1 = new GridBagConstraints();
        co1.gridx = 0;
        co1.gridy = 0;
        co1.anchor = GridBagConstraints.FIRST_LINE_START;
        co1.weighty = 1.0;
        Annex.add(Annex1, co1);
        //and so on...
        }}

现在我的问题是,如何让它工作?现在如果我编译,Tab3 就是空的。如果一切都在一个 class 中,它就会完全按照我想要的方式工作,但代码太长了。在我看来,我在 Tab3 class 中遗漏了一行,但即使经过数小时的修补和搜索,我也不知道如何解决这个问题。我尝试的一切都产生了更多错误。

问题出在继承上。 Tab3Layout 有自己的 Annex JPanel(继承自 Tab3),它正在修改和添加组件,而 Tab3 class 正在插入它的 Annex,它是通过 new JPanel() 初始化的,你什么都不做。 Tab3Layout class 甚至从未触及 Annex 面板,您初始化并添加到 Tab3 .

public class Tab3 extends JPanel {
JPanel Annex = new JPanel(); // <----- this, an empty JPanel
//A Bunch of Labels and Buttons

public Tab3(){
//ActionListeners for the Buttons
this.setLayout(new BorderLayout());
this.add(Annex,BorderLayout.WEST); // <----- is inserted here
this.add(Bsp,BorderLayout.EAST);
}}

如果您删除 new JPanel(),您将得到一个错误,这将说明两个 class 都在 不同的 对象上工作,这恰好发生同名。你需要将你想要出现在Tab3中的所有components/panels传递给Tab3Layout进行修改,然后你可以稍后用getters检索它们。另一种方法是创建 AnnexPanel class,它本身将扩展 JPanel class。它会设置自己的布局、组件等,并能够直接添加。关注 Single Responsibility Principle would be best, if your classes grow in size. If it's 200+ lines of code, you should consider refactoring it. If you will allow your class to grow like 3000+ lines of code, you will have a bad time. Try to forsee where you can create new class/method in early stages of development. See KISS principle .

嗯..我会以不同的方式拆分它们。

我的 Tab3Layout class。 Annex panel是injected via constructor,你可以给它设置一个setter,但是记得在注入前不要调用createAnnex()。反正编译器会让你记住的。

public final class Tab3Layout {

    private JPanel Annex;
    JPanel Annex1; //just to avoid compiler error
    private GridBagLayout gridBagLayout;
    private GridBagConstraints co1;

    public Tab3Layout(JPanel Annex) {
        this.Annex = Annex;
        this.gridBagLayout = new GridBagLayout();
        this.co1 = new GridBagConstraints();
    }

    public void createAnnex() {
        this.Annex.setLayout(gridBagLayout);

        this.co1.gridx = 0;
        this.co1.gridy = 0;
        this.co1.anchor = GridBagConstraints.FIRST_LINE_START;
        this.co1.weighty = 1.0;

        this.Annex.add(Annex1, co1);
    }

    public JPanel getAnnex() {
        return this.Annex;
    }
}

然后是 Tab3 class:

public class Tab3 extends JPanel {

    JPanel Annex;
    Tab3Layout tab3Layout;

    public Tab3() {
        super();
        this.Annex = new JPanel();

        this.tab3Layout = new Tab3Layout(Annex);
        this.tab3Layout.createAnnex();

        this.setLayout(new BorderLayout());
        this.add(tab3Layout.getAnnex(), BorderLayout.WEST);
        this.add(new JPanel(), BorderLayout.EAST);
    }
}

看看我的 GridBagManager 存储库,它可以让您了解如何设置另一个 class 的布局。

您还可以使用 JPanel 扩展 Tab3Layout。并记得使用 GridBagConstraints 设置 anchorfill

Java naming convention.

JPanel Annex = new JPanel();
GridBagConstraints co1 = new GridBagConstraints();

JPanel annexPanel = new JPanel();
GridBagConstraints gridBagConstraints = new GridBagConstraints();

我个人使用 gbc 作为 GridBagConstraints 对象,正如您将在我上面提到的我的回购协议中看到的那样。

编辑: 我认为您应该将您的实现分成几个较小的 classes。那将是专业的方法。重构你的代码。对于初学者,您可以让每个面板都有自己的 class 扩展 JPanel(就像我建议的 AnnexPanel class)。

Edit2:createAnnex()可以returnJPanel类型,减少样板代码,调用如下:

this.add(Tab3Layout.createAnnex(), co1);

而不是

Tab3Layout.createAnnex();
this.add(Tab3Layout.getAnnex(), co1);

如果是单例,甚至可以将 createAnnex() 带入构造函数(假设 class 扩展 JPanel)。