JTextField 在静态时在某些页面上消失,而在其他页面上出现

JTextField disappears on some pages when being static, while appearing on others

在编写程序时,我将一些字段设为静态,即 JTextField 对应 E-Number。但是现在这个字段的行为并不像预期的那样,在我的一些页面上它出现了,在其他一些页面上它消失了。 由于我在处理大量静力学方面不是很有经验,因此可能有一个我不理解的概念。

如果您想测试我的程序 (MCVE),我已经创建了一个非常简单但有效的示例。

它首先显示我的概览页面 - E-Number JTextField 丢失。

如果您单击搜索按钮,它会显示跟踪页面 - 显示 E-Number JTextField

两个页面包含 相同 workNumberPanel,我找不到可以解释行为的差异。

那么,为什么 E-Number JTextField 出现在概览页面上,而跟踪页面上却不见了?感谢任何帮助/解释!

MainProgram.java

import java.awt.CardLayout;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;

import net.miginfocom.swing.MigLayout;

public class MainProgram extends JFrame {
    private static final long serialVersionUID = 1L;

    public static JPanel centerPanel = new JPanel();

    public static CardLayout contentCardsLayout = new CardLayout();

    OverviewPage overviewPage = new OverviewPage();
    TrackingPage trackingPage = new TrackingPage();

    public void initialize() {
        createCenterPanel();
    }

    private void createCenterPanel() {
        centerPanel.setLayout(contentCardsLayout);

        overviewPage.setName("overviewPage");
        trackingPage.setName("trackingPage");

        centerPanel.add(overviewPage, "overviewPage");
        centerPanel.add(trackingPage, "trackingPage");

        add(centerPanel, "growx, wrap");
    }

    public MainProgram() {
        setBounds(300, 50, 1200, 900);
        setLayout(new MigLayout());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
                    MainProgram window = new MainProgram();
                        window.setVisible(true);
                        window.initialize();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

OverviewPage.java

import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

public class OverviewPage extends JPanel {
    WorkNumberPanel workNumberPanel = new WorkNumberPanel();

    private static final long serialVersionUID = 1L;

    public OverviewPage() {
        setLayout(new MigLayout());
        add(workNumberPanel, "wrap, growx");
    }
}

TrackingPage.java

import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

public class TrackingPage extends JPanel {
    private static final long serialVersionUID = 1L;

    WorkNumberPanel equipmentNumberPanel = new WorkNumberPanel();

    public TrackingPage(){
        setLayout(new MigLayout("", "grow, fill"));
        add(equipmentNumberPanel, "wrap, growx");
    }
}

WorkNumberPanel.java

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

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import net.miginfocom.swing.MigLayout;

public class WorkNumberPanel extends JPanel {
    private static final long serialVersionUID = 1L;
    private static final Integer TEXTFIELD_LENGTH = 20;

    JPanel mainWorkNumberPanel = new JPanel();

    JLabel lblWorkNumber = new JLabel("E-Nr: ");
    JLabel lblN_Number = new JLabel("N-Nr.: ");
    JLabel lblSNumber = new JLabel("W-Nr.: ");

    public static JTextField txtWorkNumber = new JTextField(TEXTFIELD_LENGTH);
    JTextField txtNNumber = new JTextField(TEXTFIELD_LENGTH);
    JTextField txtSNumber = new JTextField(TEXTFIELD_LENGTH);

    JButton btnSearchEntry = new JButton("Search");

    public WorkNumberPanel() {
        createEquipmentNumberPanel();
        btnSearchEntry.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                MainProgram.contentCardsLayout.show(MainProgram.centerPanel, "trackingPage");
            }
        });
    }

    private void createEquipmentNumberPanel() {
        setLayout(new MigLayout());
        mainWorkNumberPanel.setLayout(new MigLayout("", "[][grow, fill][][grow, fill][][grow, fill][]"));
        mainWorkNumberPanel.add(lblWorkNumber);
        mainWorkNumberPanel.add(txtWorkNumber);
        mainWorkNumberPanel.add(lblN_Number);
        mainWorkNumberPanel.add(txtNNumber);
        mainWorkNumberPanel.add(lblSNumber);
        mainWorkNumberPanel.add(txtSNumber);
        mainWorkNumberPanel.add(btnSearchEntry);

        add(mainWorkNumberPanel, "push, span, growx");
    }
}

可能是因为当您使用此代码创建 "pages" 时

OverviewPage overviewPage = new OverviewPage();
TrackingPage trackingPage = new TrackingPage();

TrackingPage 将是最后一个执行以下行

mainWorkNumberPanel.add(txtWorkNumber);

private void createEquipmentNumberPanel() 中,因此该面板将 "own" JTextField。 UI 组件在任何给定时间只能在一个地方才有意义,否则事情会变得很奇怪:)

你的陈述

Both pages contain the same workNumberPanel and I cant find a difference, that would explain the behaviour.

根本不是真的。当您执行以下行

时,您正在 OverViewPageTrackingPage 中创建一个新的 WorkNumberPanel 实例
WorkNumberPanel equipmentNumberPanel = new WorkNumberPanel();

所以我的建议是,您可以找到另一种实现所需内容的方法,而无需使用静态 JTextField(或任何其他 UI 组件)。

在这里你实例化了一个OverviewPage,然后是一个TrackingPage.

OverviewPage overviewPage = new OverviewPage();
TrackingPage trackingPage = new TrackingPage();

这两个 类 实例化一个 WorkNumberPanel .

WorkNumberPanel 添加静态 JTextField (txtWorkNumber) 到他们的显示面板 (mainWorkNumberPanel).

无法将单个 Component 添加到多个 Container 对象。 这就是您的文本字段所发生的情况,因为它是 static 而不是实例变量。

最后一次添加将获胜,因此文本字段将仅出现在 TrackingPage 中,而不再出现在 OverviewPage 中。

只是不要成功 static

首先你需要了解什么是静态字段。静态字段与对象的特定实例无关。该字段与 class 本身有关。
有很好的解释 here and here.


现在关于你的情况。 JComponent 一次只能添加到一个面板。将它添加到另一个会将其从第一个中删除。

在您的代码中,您正在创建 'WorkingNumberPanel' 的多个实例。执行此操作时,您将文本字段添加到面板,包括 static 文本字段 txtWorkNumber。由于字段 txtWorkNumber 是静态的,因此您要将 同一对象 添加到多个组件,正如我上面提到的,这会将它从之前添加的任何地方删除。

解决此问题的一种可能方法是将 txtWorkNumber 中的值存储在静态变量中并创建一个新实例(非静态)文本字段以添加到面板。