简体   繁体   English

Java Swing编程结构:听众应该是几乎所有Swing组件的源吗?

[英]Java Swing programming structure: are listeners supposed to be the source of almost all Swing components?

My question boils down to this: is it standard structure in Swing programming to give listeners control over new components (eg a new JPanel) for display and input, and to give that new component's listeners control over new components for display and input, and so on to infinity? 我的问题可以归结为:它是Swing编程中的标准结构,它允许侦听器控制新组件(例如新的JPanel)以进行显示和输入,并使新组件的侦听器控制新组件以进行显示和输入,等等到无穷大? Or does Java need to revert back to some sort of unifying class that ties all Swing components together in a procedural order? 或者Java是否需要恢复到某种统一类,它将所有Swing组件按程序顺序连接在一起?

At present, in my application that uses one JFrame only, in my listeners, my initial JFrame object is being passed as a parameter to all my JPanels so their listeners can call removeall() to clear the frame for a new JPanel. 目前,在我的应用程序中仅使用一个JFrame,在我的侦听器中,我的初始JFrame对象作为参数传递给我的所有JPanel,因此他们的侦听器可以调用removeall()来清除新JPanel的帧。 For example, short code as follows 例如,短代码如下

public class MainFrame {
  JFrame jfrm;
  public MainFrame() {
    jfrm = new JFrame("Main Frame");
    JPanel mainPanel = new MainPanel(jfrm);
  }
}

public class MainPanel extends JPanel {
  public MainPanel(final JFrame mainFrame) {
    JButton example = new JButton("Example");
    example.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent le) {
            mainFrame.removeall();
            JPanel 2ndPanel = new 2ndPanel(mainFrame);
            mainFrame.add(2ndPanel);
            mainFrame.validate();
        }
    });
  }
}

Is this the right structure - where it's the listeners that generate the new panels and not some unifying class? 这是正确的结构 - 在哪里产生新面板的听众而不是一些统一的类? But if that's the case, how does Java's compiler ever get to mainFrame.validate() if there's a cascading infinity of listeners? 但是,如果是这样的话,如果有一个层叠无限的侦听器,Java的编译器如何获得mainFrame.validate()? I'm an old-school procedural programmer trying to program a Swing application in Java, and I reckon I might not have grasped the basic concepts of Swing programming. 我是一个老派程序程序员,试图用Java编写Swing应用程序,我想我可能没有掌握Swing编程的基本概念。 Look forward to any helpful answers, and thanks in advance! 期待任何有用的答案,并提前感谢!

I wouldn't do it like that. 我不会那样做。 The Observer pattern is used in Swing to send notifications, usually as a result of an user action. Observer模式在Swing中用于发送通知,通常是用户操作的结果。

Take your example: The user 'clicks' on the button because he wants a new panel in MainFrame. 举个例子:用户“点击”按钮,因为他想要一个MainFrame中的新面板。 But the button doesn't know what to do with a click. 但按钮不知道如何处理点击。 All he can do is notify event listeners , that it has been selected. 他所能做的只是通知事件监听器 ,它已被选中。

So we need some component that is interested in notifications. 所以我们需要一些对通知感兴趣的组件。 This component can register a listener with the button and receive notifications. 该组件可以使用按钮注册侦听器并接收通知。 The listener is this other components 'ear' (or it's 'eye'). 听众是其他组件的“耳朵”(或者是“眼睛”)。 But an ear (or eye) will not take action. 但耳朵(或眼睛)不会采取行动。 It is just the other components sensor. 它只是其他组件传感器。

Which takes us back to the main question: who wants to be informed, if the button is clicked and who has to take action. 这将我们带回到主要问题: 想要被告知,是否点击按钮以及必须采取行动。 This is a major design question. 这是一个主要的设计问题。 It's definitly not the listener that creates and adds a panel to main frame. 绝对不是创建并向主框架添加面板的监听器。 It could be the main frames role to create and add sub panels or the role of a third component, which is responsible of creating a frame with sub panels. 它可以是创建和添加子面板的主要框架角色或第三个组件的角色,第三个组件负责创建具有子面板的框架。

But the listner is a bad place for this code. 但是listner对于这段代码来说是一个糟糕的地方。

Instead of destroying and creating panels you might want to look at hiding/showing them. 您可能希望隐藏/显示它们,而不是销毁和创建面板。 There is a CardLayout layout manager that can do this: http://journals.ecs.soton.ac.uk/java/tutorial/ui/layout/card.html 有一个CardLayout布局管理器可以做到这一点: http//journals.ecs.soton.ac.uk/java/tutorial/ui/layout/card.html

Basically the idea is build and add all your panels at the start of your prog, then use the layout manager to flip between views. 基本上这个想法是构建并在您的编程开始时添加所有面板,然后使用布局管理器在视图之间切换。

As said by others, you might want to add some sort of model to your design, which is responsible for maintaining the state of the system. 正如其他人所说,您可能希望为您的设计添加某种模型,该模型负责维护系统的状态。

First of all you shouldn't let the listener manipulate the frame directly, use a nested JPanel or it's ContentPane . 首先,你不应该让监听器直接操作框架,使用嵌套的JPanel或它的ContentPane

Your question depends on where your listener is located. 您的问题取决于您的听众所在的位置。 You should only add components to a JFrame from the class itself. 您应该只从类本身向JFrame添加组件。 In your case it's OK, since the logic is confined to the class itself. 在你的情况下,没关系,因为逻辑仅限于类本身。

I don't think there is an infinity of listeners. 我不认为有无数的听众。 They are in a list and are executed sequentially. 它们在列表中并按顺序执行。 Your listener should use SwingUtilities.invokeLater for manipulating the main frame. 您的侦听器应使用SwingUtilities.invokeLater来操作主框架。

I find the passing of the JFrame as an argument a little redundant. 我发现JFrame作为参数的传递有点多余。 Why not create the listener from outside the constructor? 为什么不从构造函数外部创建侦听器?

 final JPanel mainPanel = new MainPanel();     
 JButton example = new JButton("Example");
 example.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent le) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
               MainFrame.this.removeAll();
               MainFrame.this.add(mainPanel);
            }
         });;
    }
 });
 add(example);

It's not the best of examples, but I am note sure what you are trying to do. 这不是最好的例子,但我要注意你要做的事情。

The bottom line is you should create the components outside the listener, and then add it using the listener. 底线是您应该在侦听器外部创建组件,然后使用侦听器添加它。

There is some confusion by the, not unusual, way you have organised your code. 你组织代码的方式有些混乱,而不是很奇怪。 As a general rule of Java, don't subclass where you have no reason to. 作为Java的一般规则,不要在没有理由的情况下进行子类化。 It rarely makes sense to subclass JPanel or JFrame . 子类JPanelJFrame很少有意义。

It also rarely makes sense to assign components to fields in the class that creates them. 将组件分配给创建它们的类中的字段也很少有意义。 In fact, do less in constructors. 事实上,在构造函数中做得更少。

Also do less in anonymous inner classes. 在匿名内部类中也少做。 Detangle the event data and call a method that makes sense for the enclosing class to have as an operation. 解开事件数据并调用一个对封闭类有意义的方法作为操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM