Java中的模型与渲染器

Java 基础类(JFC)Swing工具提供了使用Java平台创建高度可交互性图形用户界面的类。Swing是高度灵活的,但是也因此相当复杂,固然新手能够使用Swing创建基本的图形用户界面(GUI),但是真要创建一个复杂、专业的GUI界面,你必须理解Swing的体系架构的基础,尤其是使用 Swing创建复杂、像JTable、JTree、JComboBox以及JList这样基于渲染器的组件,Swing提供的基于模型和渲染器的组件是构建高性能、可扩展GUI的关键。 

Swing体系结构 

最初Smalltalk系统的UI工具使用所谓的模型-视图-控制(MVC)模式,MVC引进这样一个概念:数据源应该同屏幕展现分开。这是一个优秀的体系设计结构,能促进代码重用和程序框架。Swing使用的是一个变体的MVC架构。

典型的Swing GUI组件包括至少三个对象:一个Component,一个Model和一个UI Delegate,在这个框架中,Model负责存储数据,UI Delegate负责从Model获取数据并渲染到屏幕上往,Component通常协调Model和Delegate之间的操纵,并同时负责将 Swing嵌进到AWT窗口系统中。 

留意,UI Delegate对象可以在运行的时候动态替换,这就使Swing具备了可插拔的外观(Pluggable Look-And-Feel, PLAF)。 

固然Swing的MVC结构显然具备灵活性的好处,但是这个结构通常被指责为一些程序慢的根源。固然基于MVC结构需要更多的方法调用来支持额外的重定向,实在花费在这儿的消耗很小。对基于Swing的应用程序profile的结果显示,model-view分隔的开销可以忽略不计,不到CPU总开销的 1%,复杂的Swing用户界面的多数处理事件实在都花费在了底层的图形操纵上了。Swing的model-view结构并不是低性能的根源,它是构建可扩展程序的关键。 

矢量组件 


Swing 提供了一些处理大数据量数据集的组件,包括JTable、JTree、JList以及JComboBox。这些矢量组件被设计成能够处理成千上万甚至数百万的数据,为了避免占用大量内存,这些组件在Swing的体系架构增加了渲染器(renderer)概念。


渲染器(Renderer) 

在这些更为复杂的Swing组件中,渲染器是提供可扩展性的关键。我们以JTable作为渲染器的示例。缺省表格中的每一格可能都有一个JLabel,这对于比较小的数据集来说可行,但是对于大数据集就行不通。比如,假如使用这种表格显示1000x1000的数据集,需要的内存可能要1G,即使每个格子都是空的。 

假如解决这种扩展性题目?Swing的JTable使用一个组件来画出所有相同类型的格子。比如所有的String对象的格子都使用相同的组件画。这种类型的组件被称作渲染器(renderer),使用渲染器显示多个表格极大的减小了大型数据表存储空间。 

当渲染器用来显示表格时,JTable从model中获取格子中的数据,然后使用这些数据对渲染器进行配置,然后使用该渲染器画出该格子。接下来,渲染器继续移动到下一个格子,然后重复这个过程。 


留意你可以通过操纵渲染器和模型来控制这个过程,所有的矢量组件,包括JTree、JList以及JComboBox都使用渲染器方法,并不仅限于JTable。 

模型(Model) 

直接操纵Swing的模型(Model)对于编写可扩展的用户界面至关重要,下面代码是往JComboBox添加数据项的通常做法: 

JComboBox box = new JComboBox(); 
for (int i = 0; i < numItems; i++) { 
box.addItem(new Integer(i)); 
} 
这些代码只是简单的往JComboBox中添加数据项,代码同往AWT的Choice中添加选项类似,这种方法对于小数据量来说可以,但是当要添加大量数据时就会明显变得非常慢。 

尽管上面的代码没有明确引用任何模型,JComboBox的模型对象实际上参与这个过程,每次调用addItem时,JComboBox内部发生了很多操纵:组件将请求传递给JComboBox的模型,模型发送一个事件表明一个新项被添加。很明显,假如你直接操纵模型的将会更高效,如下例所示: 

Vector v = new Vector(numItems); 
for (int i = 0; i < numItems; i++) { 
v.add(new Integer(i)); 
} 
ComboBoxModel model = new DefaultComboBoxModel(v); 
JComboBox box = new JComboBox(model); 
这样为什么会更快呢?原因有两个。第一,由于所有项是一次添加到模型往,而不是一个一个的,只有一个事件发出,这意味着更少的事件触发,更少的方法调用。第二是由于需要通知变化的对象更少,总的工作量即是触发次数乘以侦听器数目。由于模型是新创建的,侦听在上面的侦听器为零,这意味着没有触发事件发生。 

从上面的例子可以学到两点: 

尽可能使用批操纵,尽量减少触发事件的数目。 

当初始化或者需要完全替换模型的内容时,考虑重新天生模型,不要使用已经存在的模型,已存在模型上已经保持了很多的侦听器,新天生的模型没有侦听器,这样避免了不必要的处理函数的调用。 

触发事件数目严重影响你的程序启动时间,也会影响打开对话框和相似操纵的时间。

你可能感兴趣的:(模型与渲染器)