什么是你最好的Swingdevise模式和技巧?
我正在为使用Swing的应用程序编写GUI,为了维护代码和可读性,我希望在整个系统中遵循一致的模式。
我读过的大部分文章和书籍(或者至less是书籍部分)似乎都提供了大量关于如何创build和安排各种组件的例子,但忽略了编写一个完整的GUI的大局。
什么是应用程序GUIdevise的最佳技巧,以及在devise或重构GUI应用程序时遵循哪些模式?
使用布局pipe理器。 你可能会认为只需要用硬编码的位置来定位所有的东西(尤其是如果你使用graphics化的布局工具),但是当需要更新gui或将其国际化时,你的后继者会恨你。 (相信我,我是那个从一开始就用布局经理的人,还有那个不理我的人的inheritance人。)
永远不要派生自JDialog,JFrame或JInternalFrame来定义表单,对话框…
而是从JPanel派生。 这将带给你以下优点:
- 例如,后来从JFrame改为JDialog的可能性(因为用户改变了主意)
- 您可以将一个面板实例从一个JDialog重用到另一个(JDialog通常不可重用,因为它们是通过引用其“父”,框架或另一个对话框构build的)
- 您稍后可以更改JDialog,使用第三方框架中的更多function子类。
避免使用GUI布局devise器(构build器)。 稍后它将使您的代码更清洁,更易于维护。
我认为并发的一个良好的工作知识往往被低估。 您确实需要熟悉Swing的线程策略和常规同步技术来构build响应式GUI和高效的后端。
mvc是你的朋友。
这是一个更抽象的关于你的GUI代表的高层次的答案,而不是它的机制。
根据你的任务,这可能是很难做到这一点,所以你的用户可以在概念上掌握graphics用户界面正在做什么。 我做了一些非常棘手的工作,涉及到graphics用户界面(GUI),而我最成功的方法是使用一组复杂的控件,并把它们放到用户期望的布局中。
比如我写了一个系统来pipe理T1设备两端的一台设备(有点像调制解调器)。 这些控件真的很难理解,比如“创build回送,testing远端信号,testing近端位模式,发送各种位模式……”(这是一个巨大的过分简化,比这更糟糕)
我必须真正理解这个问题,所以我去了一位技术支持代表,他一直帮助客户处理这个问题。 他向我展示了手册中的图表,并向我介绍了该图表上不同的控件。
我拿了图表,重新创build它使用graphics(大部分只是一个简单的线条图,但它显示了两端和它们之间的连接),然后使用graphics区域来表示控制和反馈(颜色变化) 。 你可以在视觉上看到一个信号发出。 当你在远端打开一个环回时,你可以看到这条线将信号环回到它的外线,然后你可以看到颜色的变化,因为你的近端开始得到它发出的模式, 。
“控件”比这个更加复杂,但是GUI将其简化为客户理解问题所需要的东西。
之后,我们有客户回来告诉我们,他们以前从来没有能够find这个东西,但现在他们完全明白了!
这个演示文稿比GUI实现的布线要重要得多。
当用户多次点击操作button时,避免产生太多的线程。 第一次点击禁用button,在后台线程中产生你的动作,完成后,再次启用button。 对于短时间运行的任务,这可能不是问题。
养成你的callback产生线程来完成实际工作的习惯,然后当你的callback变成一个耗时的怪物时,你不会有冻结的GUI。
大量使用MVC模式。 这里是我的意思的一个简单的例子:
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。 GridBagLayoutfunction非常强大。 如果使用它,定义一些GridBagConstraints常量(如LABEL_GBC和FIELD_GBC)并继续重用它们。
- Karsten Lentzsch的JGoodies对于我的build筑devise非常有帮助,特别是关于Presentation Model模式,绑定和validation。 看看他的文章和图书馆 。
- 使用类似MVC的模式。 我说“喜欢”是因为目标实际上是将观点从模型中分离出来,而不是遵循MVC的特定风格。 我更喜欢自己使用演示模型 。
- MiGLayout – 除非基本的布局pipe理员会这么做,否则我会使用它。
- 尽可能地模块化和重用。
- WindowBuilder Pro for Eclipse – 最好的视觉devise师,因为它与现有/编辑的代码一起工作,并不会locking你。现在它是免费的! 我没有使用devise师的问题,因为视图应该与其他代码分开。
- Netbeans平台 (RCP) – 唯一真正的Swing框架。 我希望在我有时间的时候学习和使用它,因为框架的一部分工作是解决像你这样的问题。
- JavaBuilders – 酷的项目,允许声明性用户界面,但我不知道它是成熟的风险,尤其是对于一个现有的项目。 但是,阅读PDF书籍只是为了了解他们正在努力解决的问题,这很有趣。
尽量不要将文本编码到您的应用程序。 Swing guis可以很容易地写成数据驱动,可以考虑在xml文件(包括组件名称和位置/布局属性)中定义GUI。
我曾经在拥有大量属性表的系统上工作(它们只是一堆一堆的控制,一页接一页),但是没有数据驱动,几乎不可能维护或国际化。
如果您决定使用GUI构build器,请不要修改它输出的代码(如果可以避免的话) – 最好是从外部类绑定到GUI。 想想如果你不用build造者就必须这样做,会发生什么事 – 难以移植吗? 不可能?
理解swing中的陷阱 – 仅从AWT线程修改GUI组件,尽快返回AWT线程(如果必须执行超过100ms的任何操作,则产生一个新线程),
尽量保持代码的干爽 – 使用Swing GUI可能是一个真正的编程挑战 – 同样,数据驱动代码是我发现不会像JButton(“…”)那样不断重复代码的唯一方式;
如果您的数据是基于财产表,请认真考虑创build绑定机制,将您的控件与您的数据绑定。 DRY代码的一个好的目标是每个控件的控制特定的代码行,从数据库中获取一段数据到你的GUI,让用户编辑它并把它返回到你的数据库。 这意味着你应该可以通过不做任何事情而是修改你的数据来添加一个新的控件。
避免组成会更容易inheritance。
比如我看到很多这样的东西:
public class CustomerSupportApp extends JFrame { JList<Customer> customers; OtherBusinessComponent importantComponent; etc. etc }
这是混合业务逻辑与演示文稿。 它只是使变化从困难到不可能。
更好的是:
public class CustomerSupportApp { JList<Customer> customers; OtherBusinessComponent importantComponent; // The app HAS-A frame but not IS-A frame JFrame frame; etc. etc }
绝对把graphics用户界面放在一个类中,并把逻辑放在另一个类或多个类中 – 尽最大可能。 如果使用MVC(模型 – 视图 – 控制器)模式,则会自动发生。 如果不这样做,GUI将很快变得难以维系复杂。
你不应该扩展JFrame,JDialog,JPanel,JButton,Janything类(尽pipe表行为的某些扩展只在扩展时才可用)。 如果您想要自定义组件,可以扩展JComponent。 如果应该实现模型(例如通过扩展抽象模型),听众(例如通过扩展适配器),但就是这样。 你通常不需要/不得不扩展swing组件,最好不要这样做,因为它使得你的代码和超类的实现绑定在一起。
看看应用程序框架API( https://appframework.dev.java.net/和http://java.sun.com/developer/technicalArticles/javase/swingappfr/ 。这是一个伟大的API来build立你的swing应用程序例如:所有样式(颜色,字体,图标…)都是在一个简单的configuration文件中定义的。
我认为你将要面临的主要问题是你的GUI应用程序的可testing性。
所以关于unit testing的可维护性和易用性,我倾向于“Presenter first”成语,而不是模型视图控制器(MVC)和其他衍生产品,这些衍生产品指示您了解实际应用逻辑(模型)。 最好的资源是作为一个想法介绍的小组的网站 。
由于使用这样的方法将需要大量的样板代码来初始化应用程序的各种元素,我还build议使用dependency injection框架。 我已经和Guice解决了。