关于java:您最好的Swing设计模式和技巧是什么?

What are your best Swing design patterns and tips?

我正在使用Swing为应用程序编写GUI,出于代码维护和可读性的考虑,我希望在整个系统中遵循一致的模式。

我读过的大多数文章和书籍(或至少是书籍部分)似乎都提供了许多有关如何创建和排列各种组件的示例,但是却忽略了编写完整GUI的全局图。

您对应用程序GUI设计的最佳建议是什么?在设计或重构GUI应用程序时遵循什么模式?


永远不要从JDialog,JFrame或JInternalFrame派生用于定义表单,对话框...

而是从JPanel派生。这将为您带来以下优势:

  • 以后可以改变的可能性
    从JFrame到JDialog例如
    (因为用户改变了主意)
  • 您可以从一个JDialog到另一个JDialog重复使用一个面板实例(JDialog通常不可重用,因为它们是通过引用其"父",框架或另一个对话框来构造的)
  • 以后可以更换
    JDialog具有更多功能
    第三方框架的子类。


使用布局管理器。您可能会认为,现在就用硬编码的位置放置所有内容会更简单(尤其是如果您使用图形布局工具),但是当需要更新gui或使其国际化时,您的后继者会讨厌您。 (对此,请相信我,我是那个家伙,从一开始就说要使用布局管理器,而后继者就是那个忽略我的家伙。)


避免使用GUI布局设计器(生成器)。稍后,它将使您的代码更简洁,更易于维护。


我认为对并发的良好使用常会被低估。您确实需要熟悉Swing的线程策略和常规同步技术,以构建响应式GUI和高效的后端。


mvc是您的朋友。


这是关于GUI表示的更抽象的高级答案,而不是其机制。

根据您的任务,可能很难做到这一点,因此您的用户可以从概念上掌握GUI的功能。我已经完成了一些涉及GUI的非常棘手的工作,而我最成功的方法是采用了一组复杂的控件并将它们置于用户期望的布局中的方法。

例如,我写了一个系统来管理2台设备,它们分别在T1线路的两端(有点像调制解调器)。这些控件真的很难理解-诸如"创建环回,测试远端信号,测试近端位模式,发送各种位模式……"之类的字段(这是一个极大的简化,比这差很多)

我必须非常了解这个问题,所以我去了技术支持代表那里,他一直为客户解决这个问题。他在手册中为我显示了一个图,并逐步引导我完成了该图上不同控件的操作。

我拿起了图表,使用图形重新创建了它(大部分情况下只是简单的线条画,但是它显示了两端以及它们之间的连接),然后使用图形的区域来表示控件和反馈(颜色变化) 。您可以从视觉上看到一个信号正在发出。当您在远端打开环回时,您会看到该线将信号循环回到它的出线,然后您会看到颜色发生变化,因为您的近端开始获得它发出的另一条线的图案。

"控件"比这要复杂得多,但是GUI将其简化为客户理解问题所需要的。

此后,我们有客户回来告诉我们,他们以前从未能够弄清楚这些东西,但是现在他们完全明白了!

此演示文稿比GUI实现的实现更加重要。


当用户多次单击操作按钮时,请避免产生太多线程。第一次单击时禁用按钮,在后台线程中生成操作,完成后再次启用按钮。对于短期运行的任务,这可能不是问题。


养成让您的回调产生线程来完成实际工作的习惯,然后当您的回调之一变成耗时的怪物时,您就不会冻结GUI。


  • Karsten Lentzsch的JGoodies对我的建筑设计非常有帮助,尤其是在Presentation Model模式,绑定和验证方面。查看他的文章和库。
  • 使用类似MVC的模式。我之所以说"喜欢",是因为目标实际上是将视图与模型分开,而不是遵循MVC的特定风格。我更喜欢自己使用Presentation Model。
  • MiGLayout-除非基本的布局管理器可以使用,否则我将其用于所有内容。
  • 尽可能地模块化和重用。
  • WindowBuilder Pro for Eclipse-最佳的视觉设计器,因为它可以与现有/已编辑的代码一起使用,并且不会锁定您。它现在免费!我对使用设计器没有任何问题,因为视图应与其余代码分开。
  • Netbeans平台(RCP)-唯一真正的Swing框架。我希望有空的时候学习和使用它,因为框架的一部分工作是解决像您这样的问题。
  • JavaBuilders-允许声明性UI的很酷的项目,但是我不确定它是否成熟到足以冒风险,特别是对于现有项目。但是,如果仅了解他们正在尝试解决的问题,那么阅读他们的PDF书籍就很有趣。

当组合会更容易时,避免继承。

例如,我看过很多这样的事情:

1
2
3
4
5
6
7
public class CustomerSupportApp extends JFrame {
     JList<Customer> customers;
     OtherBusinessComponent importantComponent;

     etc. etc

}

这将业务逻辑与演示结合在一起。它只会使改变从困难变为不可能。

更好的是:

1
2
3
4
5
6
7
public class CustomerSupportApp {
     JList<Customer> customers;
     OtherBusinessComponent importantComponent;
     // The app HAS-A frame but not IS-A frame
     JFrame frame;
     etc. etc
}


大量使用MVC模式。这是我的意思的简单示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Person
{
  String firstName;
  String lastName;
  // and getters and setters...
}

class PersonSwingModel
{
  private Person person;
  private javax.swing.text.PlainDocument firstName;
  private javax.swing.text.PlainDocument lastName;
  // and getters and setters...
  // Create some method like init() that initializes PlainDocument values
  // to attributes in model.
}

class SavePersonAction extends AbstractAction
{
  private PersonSwingModel model;
  // and getters and setters...
}

class PersonSwingView extends JFrame
{
  private PersonSwingModel model;
  private javax.swing.JTextField firstName;
  private javax.swing.JTextField lastName;
  private SavePersonAction savePersonAction; // hook up to JButton/JMenuItem
  // and getters and setters...
  // Create some method like init() which binds PlainDocument to JTextField
  // and Actions to JButtons or JMenuItems
}

我看到有些人不同意扩展JFrame或JPanel。我不。为我工作。

另外,使用LayoutManagers。 GridBagLayout非常强大。如果使用它,请定义一些GridBagConstraints常量(例如LABEL_GBC和FIELD_GBC)并继续重用它们。


尽量不要将文字编码到您的应用中。可以很容易地将Swing GUI编写为数据驱动的,请考虑在xml文件中定义GUI(包括组件名称和position / layout属性)。

我在具有很多属性表的系统上工作(这些属性表只是一堆堆控件,一页一页一页)—如果不使其成为数据驱动的,则几乎不可能进行维护或国际化。

如果决定使用GUI构建器,请尽可能避免修改它输出的代码-最好从外部类绑定到GUI。想一想如果您在没有构建者的情况下必须要做的事情,会很难移植吗?不可能?

了解摆动中的陷阱-仅修改AWT线程中的GUI组件,尽快返回AWT线程(如果您需要花费100ms以上的时间来生成新线程),

尽力使代码保持干燥-使用Swing GUI可能是真正的编程挑战-同样,数据驱动代码是我发现不经常重复执行诸如此类的唯一方法
新的JButton(" ...");

如果您的数据是基于属性表的,请认真考虑创建绑定机制以将控件绑定到数据。 DRY代码的一个好目标是每个控件0(零)控件特定的代码行,以将数据库中的数据片段发送到GUI,让用户对其进行编辑并将其返回到DB。这意味着您只需要修改数据就可以添加新控件。


您不应该扩展JFrame,JDialog,JPanel,JButton,Janything类(尽管对表行为的某些扩展仅在对其进行扩展时可用)。如果您想进行自定义组件,则可以扩展JComponent。如果应该实现模型(例如通过扩展抽象模型),侦听器(例如通过扩展适配器),仅此而已。您通常不需要/不必扩展swing组件,最好不要这样做,因为它会使您的代码与超类的实现联系在一起。


绝对将GUI放在一个类别中,将逻辑放在另一个类别或多个类别中-尽最大可能。如果您使用MVC(模型-视图-控制器)模式,则会自动发生。如果不这样做,GUI将很快变得难以维护。


看看应用程序框架API(https://appframework.dev.java.net/和http://java.sun.com/developer/technicalArticles/javase/swingappfr/。这是构建swing应用程序的绝佳API 。例如:所有样式(颜色,字体,图标...)都在一个简单的配置文件中定义。


我认为您将要面临的主要问题是gui应用程序的可测试性。

因此,关于可维护性和单元测试的易用性,我倾向于" Presenter first"惯用语,而不是Model View Controller(MVC)和其他衍生产品,这些衍生产品指示您了解实际的应用程序逻辑(Model)。最好的资源是作为想法进行介绍的小组的网站。

由于使用这种方法将花费大量样板代码来初始化应用程序的各个元素,因此我也建议使用依赖注入框架。我已经和吉斯定居了。