对于那些抱怨 Swing 太慢、界面太难看的开发人员来说,Swing开发所做的更新努力,并没有带来什么受人欢迎的好消息,这里介绍TableMode这个东西,它可以简化Swing开发。

  假如您最近没有用过Swing开发,那么您会很快乐听到其间的许多问题现已得到解决。Swing 被从头规划,它能执行得更好,并能更好地运用 Java 2D API。Swing 开发者在 1.4 版乃至***发布的 5.0 版中提高了外观支撑。Swing 从没像现在这么好过。

用TableModel结构简化Swing开发  TableModel Swing开发 第1张

  假如从前从前用过 JTable,那么您或许也一起被逼运用了TableModel。您或许还注意到,每个 TableModel 中的一切代码,与其他 TableModel 中的代码几乎是相同的,在编译的 Java 类中,有差异的代码实际上是不存在的。本文将剖析 TableModel/JTable 现在的规划办法,阐明这种规划的缺乏,展现为什么它没有完结模型-视图-控制器(MVC)形式的真实方针。您将看到结构和构成 TMF 结构的代码 —— 我从前编写的代码与最常用的开放源代码项目的组合。运用该结构,开发人员能够把 TableModel 的巨细从数百行代码削减到只要戋戋一行,并把重要的表信息放在外部 XML 文件中。在读完本文之后,只运用如下所示的一行代码,您就能够办理您的 JTable 数据:

1 TableUtilities.setViewToModel("tableconfig.xml", "My Table",
2 myJTable, CollectionUtilities.observableList(myData));
3

  JTable 和 TableModel 存在的 MVC 问题

  MVC 现已成为十分盛行的 UI 规划形式,由于它把事务逻辑明晰地从数据的视图平别离了出来。Struts 是 MVC 在 Web 上运用的一个十分好的比如。开始,Swing ***的一个卖点是它采用了 MVC,将视图从模型平别离了出来,代码背面的主意是:代码的模块化程度满足高,所以,不必修正模型中的任何代码,就能够别离出视图。我想,任何用过 JTables 和 TableModels 的人都会发笑,告知您这是必定不或许的。运用 MVC 规划形式的抱负状况是,在开发人员用 JList 或 JComboBox 替换 JTable 时,能够不必修正表明数据的形式中的代码。可是,在 Swing 中做不到这点。Swing 使得把 JTable、 JList 和 JComboBox 热交流到运用程序中成为不或许,即便一切这三个组件都是用来为相同的数据模型供给视图。关于 Swing 中的 MVC 规划,这是一个严峻的缺乏。假如您想为 JTable 交流 JList,就有必要重写视图背面的悉数代码,才干完结该交流。

  JTable/TableModel 的另一个 MVC 缺点是:模型改变的时分,视图不会更新自身。开发人员有必要坚持对模型的引证,并调用一个函数,这样模型才会告知视图对自身进行更新;可是,抱负的状况应当是:不需求任何额定的代码,就能完结自动更新。

  ***,JTable 和 TableModel 组件规划的问题是,它们彼此之间缠杂得过于亲近。假如您修正了 JTable 中的代码,那么您需求确保您没有损坏担任处理的 TableModel,反之亦然。关于一个被认为是在模块化基础上树立的规划形式来说,现在的完结显然是一种存在过多依靠联系的规划。

  TMF 结构更好地遵从了 MVC 的方针,它把 JTable 中视图和模型的作业愈加明晰地别离开来。尽管它还没有到达让组件能够热切换的更高方针,可是它现已在正确方向上迈出了一步。

  让咱们来检视 TMF 结构,看看它是怎样让传统 TableModel 过期的。规划该结构的***部分是学习 JTable 的运用 —— 开发人员怎样运用它,它显现了什么内容,以便了了解哪些东西能够内化、通用化,哪些应当保存可装备状况,以便开发人员装备。关于 TableModel,也要进行相同的考虑,我有必要确认哪些东西能够从代码中移出,哪些有必要留在代码中。一旦找出这些问题,接下来要做的便是确认能够让代码满足通用的***技能,以便一切人都能运用它,可是,还要让代码具有满足的可装备性,这也是为了让每个人都能运用它。

  该结构分红三个根本部分:一个能够处理任何类型数据的通用 TableModel、一个外部 XML 文件(担任对不同表中不同的表内容进行装备),以及模型与视图之间的桥。

  在本文中,您能够在 src 文件夹中找到文中介绍的一切源代码。特定于 TMF 的代码坐落 com.ibm.j2x.swing.table 包中。

  com.ibm.j2x.swing.table.BeanTableModel

  BeanTableModel 是结构的***部分。它充任的是通用 TableModel ,您能够用它来处理任何类型的数据。我知道,您或许会说,“您怎样这么必定它适用于一切的数据呢?”的确,很明显,我不能这么必定,并且实际上,我坚信有一些它不适用的比如。可是从我运用 JTables 的经历来说,我乐意打赌(即便看起来我有点抬杠),实际运用中的 JTables,99% 都是用来显现数据目标列表(也便是说,JavaBeans 组件的 ArrayList)。根据这个假定,我树立了一个通用表模型,它能够显现任何数据目标列表,它便是 BeanTableModel。

  BeanTableModel 很多运用了 Java 的内省机制,来查看 bean 中的字段,显现正确的数据。它还运用了来自 Jakarta Commons Collections 结构的两个类来辅助规划。

  在我深入研究代码之前,请让我解说来自类的几个概念。由于我能够在 bean 上运用内省机制,所以我需求了解 bean 自身的信息,主要是了解字段的称号是什么。我能够经过一般的内省机制来完结这项作业:我能够查看 bean ,找出其字段。可是,关于表来说,这还不够好,由于大都开发人员想让他们的表依照指定次序显现字段。除此之外,还有一项表需求的信息,我无法经过内省机制从 bean 中取得,即列名音讯。所以,为了取得正确显现,关于表中的每个列,您需求两条信息:列名和即将显现的 bean 中的字段。我用键-值对的格局表明该信息,其间,将列名用作键,字段作为值。

  正由于如此,我在这里运用了来自 Collections 结构的合适这项作业的两个类。 BeanMap 用作实用工具类,担任处理内省机制,它接手了内省机制的一切繁琐作业。一般的内省机制开发需求很多的 try / catch 块,关于表来说,这是没有必要的。 BeanMap 把 bean 作为输入,像处理 HashMap 那样来处理它,在这里,键是 bean 中的字段(例如, firstName ),值是 get 办法(例如, getFirstName() )的成果。BeanTableModel 广泛地运用 BeanMap ,消除了操作内省机制的费事,也使得拜访 bean 中的信息愈加简单。

  LinkedMap 是别的一个在 BeanTableModel 中全面运用的类。咱们仍是回到为列名-字段映射所进行的键-值数据设置,关于数据目标来说,很明显应当挑选 HashMap。可是,HashPap 没有保存刺进的次序,关于表来说,这是十分重要的一部分,开发人员期望在每次显现表的时分,都能以指定的次序显现列。这样,刺进的次序就有必要保存。解决方案是 LinkedMap ,它是 LinkedList 与 HashMap 的组合,它既保存了列,也保存了列的次序信息。拜见清单 1,能够查看我是怎样用 LinkedMap 和 BeanMap 来设置表的信息的。

  清单1. 用 LinkedMap 和 BeanMap 设置表信息

1 protected List mapValues = new ArrayList();
2 protected LinkedMap columnInfo = new LinkedMap();
3
4 protected void initializeValues(Collection values)
5 {
6 List listValues = new ArrayList(values);
7 mapValues.clear();
8 for (Iterator i=listValues.iterator(); i.hasNext();)
9 {
10 mapValues.add(new BeanMap(i.next()));
11 }
12 }

  在 BeanTableModel 中比较风趣的查看代码实际上是通用 TableModel 的那一部分,这部分代码扩展了 AbstractTableModel 。将清单 2 中的代码与您一般用来树立传统 TableModel 的代码进行比较,您能够看到一些类似之处。

  清单 2. BeanTableModel 中的通用 TableModel 代码

1 /**
2 * Returns the number of BeanMaps, therefore the number of JavaBeans
3 */
4 public int getRowCount()
5 {
6 return mapValues.size();
7 }
8 /**
9 * Returns the number of key-value pairings in the column LinkedMap
10 */
11 public int getColumnCount()
12 {
13 return columnInfo.size();
14 }
15
16 /**
17 * Gets the key from the LinkedMap at the specified index (and a
18 * good example of why a LinkedMap is needed instead of a HashMap)
19 */
20 public String getColumnName(int col)
21 {
22 return columnInfo.get(col).toString();
23 }
24 /**
25 * Gets the class of the column.A lot of developers wonder what
26 * this is even used for.It is used by the JTable to use custom
27 * cell renderers, some of which are built into JTables already
28 * (Boolean, Integer, String for example).If youwrite a custom cell
29 * renderer it would get loaded by the JTable for use in displayif that
30 * specified class were returned here.
31 * The function uses the BeanMap to get the actual value out of the
32 * JavaBean and determine its class.However, because the BeanMap
33 * autoboxes things -- it converts the primitives to Objects for you
34 * (e.g. ints to Integers) -- the code needs to unautobox it, since the
35 * function must return a Class Object.Thus, it recognizes any primitives
36 * and converts them to their respective Object class.
37 */
38 public Class getColumnClass(int col)
39 {
40 BeanMap map = (BeanMap)mapValues.get(0);
41 Class c = map.getType(columnInfo.getValue(col).toString());
42 if (c == null)
43 return Object.class;
44 else if (c.isPrimitive())
45 return ClassUtilities.convertPrimitiveToObject(c);
46 else
47 return c;
48 }
49 /**
50 * The BeanTableModel automatically returns false, and if you
51 * need to make an editable table, you'll have to subclass
52 * BeanTableModel and override this function.
53 */
54 public boolean isCellEditable(int row, int col)
55 {
56 return false;
57 }
58 /**
59 * The function that returns the value that you see in the JTable.It gets
60 * the BeanMap wrapping the JavaBean based on the row, it uses the
61 * column number to get the field from the column information LinkedMap,
转载请说明出处
知优网 » 用TableModel结构简化Swing开发

发表评论

您需要后才能发表评论