2

我有一个带有 var 的框架,我将该 var 添加到 JPanel,如果我想将相同的 var 添加到另一个 JPanel,它会从第一个 JPanel 中消失。我想给我的问题一个合乎逻辑的解释,谢谢!我想将我的 JLabel 存储在我的两个 jpanels 中。

public class Gui {
    JPanel panel1, panel2;
    JLabel text = new JLabel("some text");
    JFrame frame = new JFrame();

    public Gui {
        panel1 = new JPanel();
        panel1.setLayout(null);
        panel1.add(text);
        panel1.getComponent(0).setBounds(50,50,50,50);
        panel1.setBorder(BorderFactory.createLineBorder(Color.black));
        panel1.setBounds(x,y,w,h);
        // it`s working, the labels it`s visible

        panel2 = new JPanel();
        panel2.setLayout(null);
        panel2.add(text);
        panel2.getComponent(0).setBounds(100,100,50,50);
        panel2.setBorder(BorderFactory.createLineBorder(Color.black));
        panel2.setBounds(x,y,w,h);
        //it`s not working, the label ins`t visible ...

        frame.add(panel1);
        frame.add(panel2);
    }
}
4

3 回答 3

3

免责声明:我正在编辑我的答案以回应 OP 的评论。但是,我仍然不完全确定问题的一些细节。随着更多的澄清,我很乐意编辑我的答案。

答:一种可能的解决方案是创建您正在使用的 Swing 组件的子类。例如,

public class MyPanel extends JPanel {
  private JLabel label = new JLabel("some text");

  public MyPanel() {
    this.add(label);
  }
}

现在您可以创建多个实例MyPanel,每个实例都有自己的 JLabel。然后您可以将这些面板添加到您的框架中。

补充:使用评论中给出的附加信息,我会更进一步,创建一个自定义 JFrame 类:

public class MyFrame extends JFrame {
  private MyPanel panel = new MyPanel();

  public MyFrame() {
    this.add(panel);
  }
}

现在您可以创建多个MyFrame. 如果您想更进一步,您可以向这两个自定义类的构造函数添加参数,以JLabel在每个实例中将文本设置为不同的值MyFrame。我将把细节留给读者作为练习。(当然,如果你卡住了,请询问。)

于 2012-07-23T20:48:04.940 回答
3

就像在其他帖子中讨论的那样。所有 Swing UI 组件(即包括 JLabel)只能有一个父级(即 JPanel)。如果您将其添加到另一个面板,它将自己从先前的父级中删除。这种行为有很好的理由。例如,JPanel 1 可能不使用与 JPanel 2 相同的布局,因此标签必须支持每个 JPanel 中的两个不同位置。使用对象作为组件的全部意义在于提供对对象内部数据的封装,例如(字体、父级中的位置、宽度、高度等)。如果您想要两个视觉元素,只需创建另一个元素。现在这会产生一个问题“如何在所有这些控件之间同步数据?” 这基本上是在讨论如何为您的程序构建合适的 Swing 架构?

您不想做的是使用 Swing 组件模型(即 Jabel、JTextField 等)作为您的数据模型。在阅读了您的问题和代码之后,我相信这就是您正在做的事情。你可能没有意识到。UI 组件应仅用于显示。它们反映了数据模型中的内容。因此,您需要创建一个不涉及 Swing 的模型。无论它如何显示,它都应该为您的问题建模。这意味着你不应该假设它总是 Swing 或 web 等。

这有非常实际的原因。假设您想在一年内重新设计您的 UI。如果您将视图组件和数据模型组合在一起,您几乎必须完全重新开始。即使您不切换技术。假设您正在从 JList 切换到 JTable 或 JTreeTable。如果您不从模型中分割视图,只需简单更改屏幕上的组件类型就绝对是一场噩梦。加上视图显示的东西,但模型可能需要不向用户显示但与正在显示的内容相关联的信息。例如,数据库中行的 ID。如果你把视图和数据模型塞在一起,你必须玩一些小技巧来以奇怪的方式存储这些不可见的信息。让其他人难以理解的事情。

如果你不明白我的意思,你要么在 6 个月内进行第一次重大重新设计,要么现在就省去一些痛苦,试着理解我现在的意思。只需简单的 POJO 就足够了。然后与您的 Swing 组件共享这些 POJO。例如:

MySpecialPanel panel1 = new MySpecialPanel();
MyOtherSPecialPanel panel2 = new MyOtherSpecialPanel();
frame.add( panel1 );
frame.add( panel2 );

...a little while later...

MySpecialPOJO specialPOJO = ...some call to a service...;
panel1.setSpecialPOJO( specialPOJO );
panel2.setSpecialPOJO( specialPOJO );

请注意,我创建了 JPanel 的两个子类,称为 MySpecialPanel 和 MyOtherSpecialPanel。他们在那里创建包含在其中的组件。然后公开一个获取 MySpecialPOJO 类型的数据模型对象的 setter 方法。在这些方法中,我们可能会看到如下内容:

public void setSpecialPOJO( MySpecialPOJO specialPOJO ) {
   this.model = specialPOJO;
   textField1.setText( specialPOJO.getName() );
   textField2.setText( specialPOJO.getDescription() );
   radioButtonGroup.setSelected( specialPOJO.getGender() );
   ....
}

Now you have a way to take a model object, and update the relative UI components that make up that view. Notice it doesn't care about any other external dependencies (ie where it got the object from). It just updates the controls it owns to reflect what's carried by the POJO. Now if you follow these simple rules it makes instantiating your special panels easy. Whether you need only one instance or many instances. Also if you need to move panels within your program it's pretty easy to do that if you reduce your dependencies to just your POJOs. There's a lot more to this, but for now this will get you started. You still have to figure out how to get data out of the UI and back into your POJOs (events!). Controllers, Services, etc.

This might help you as well:

Up-to-date Swing MVC example + Question

于 2012-07-23T21:18:10.733 回答
2

你不能。正如您所注意到的,一个控件一次只能附加到一个窗口,如果您尝试将它附加到另一个窗口,它将从第一个窗口中删除。

建议:

panel2.add(text.clone()); // clone the existing label
panel2.add(new JLabel("some text")); // make a new label from scratch
于 2012-07-23T20:43:00.350 回答