难以理解swing的JTable和JTree的渲染器机制

问题描述 投票:0回答:3

通常在使用

JTable
JTree
时,用户定义自己的单元格渲染器。

DefaultTableCellRenderer
继承用户组件,并实现渲染器方法
getTableCellRendererComponent
是很常见的。事实证明,
DefaultTableCellRenderer
实际上继承自JLabel,因此在调用super(在渲染方法中)时返回自身(this),因此用户的渲染器也可以类似地返回自身(this)。

一切都很顺利。

我的问题是怎么会这样?

表每次调用此方法时,都会给出不同的参数,并且输出标签会根据这些参数的函数进行更改。如果它确实是标签的同一个实例 - 难道它不应该根据上次调用此方法进行更改吗? 这是否意味着表格的所有单元格都由相同的标签实例组成,该实例具有相同的值(上次调用渲染器方法的值)?

我搜索了网络,并深入研究了 Swing 的代码,但找不到任何 clonecopy constructor 的行为实际上复制了输出标签。 我找不到任何证据表明(也许)swing 使用反射来每次从头开始重新实例化渲染器。

我已经阅读了 Swing 的 JTables 教程,在那里我可以找到下几行:

您可能希望表格中的每个单元格都是一个组件。然而,出于性能原因,Swing 表的实现方式有所不同。 相反,单个单元格渲染器通常用于绘制包含相同类型数据的所有单元格。您可以将渲染器视为可配置的印章,表格使用它来将适当格式的数据印记到每个单元格上。当用户开始编辑单元格的数据时,单元格编辑器接管该单元格,控制单元格的编辑行为。

他们给出了一个暗示,我所说的确实是正确的,但没有解释它实际上是如何实现的。

我听不懂。你们谁都可以吗?

java swing jtable jtree tablecellrenderer
3个回答
13
投票

它是享元模式的实现。

当 JTable 重新绘制自身时,它会启动一个循环并迭代必须绘制的每个单元格。

对于每个单元格,它使用与该单元格相对应的参数调用渲染器。渲染器返回一个组件。该组件绘制在与当前表格单元格相对应的矩形中。

然后为下一个单元格调用渲染器,并将返回的组件(例如,具有不同的文本和颜色)绘制在与单元格对应的矩形中,等等。

想象一下,每次调用渲染器时,都会获取返回组件的屏幕截图并将其粘贴到表格单元格中。


4
投票

除了@JB对JTable

JTree
如何使用
flyweight模式的明确解释之外,请注意这两个类如何提供公共方法
getCellRenderer()
getCellEditor()
。检查这些方法以了解
JTable
如何使用类文字作为运行时类型标记来按类选择渲染器或编辑器(如果列未指定任何渲染器或编辑器)。在内部,
JTable
使用
Hashtable defaultRenderersByColumnClass
作为实例存储。


4
投票

经过一番挖掘,从 DefaultTableCellRenderer 文档中找到了下一个实现说明:

实现说明:该类继承自标准组件类JLabel。然而,JTable 采用独特的机制来渲染其单元格,因此需要对其单元格渲染器进行一些稍微修改的行为。 table 类定义了一个单元格渲染器,并将其用作渲染表中所有单元格的橡皮图章;它渲染第一个单元格,更改该单元格渲染器的内容,将原点移动到新位置,重新绘制它,等等。标准 JLabel 组件并非设计用于这种方式,我们希望避免每次绘制单元格时触发重新验证。这会大大降低性能,因为重新验证消息将沿着容器的层次结构向上传递,以确定是否有任何其他组件受到影响。由于渲染器仅在绘画操作的生命周期内成为父级,因此我们同样希望避免与遍历绘画操作的层次结构相关的开销。因此,此类将 validate、invalidate、revalidate、repaint 和 firePropertyChange 方法重写为无操作,并重写 isOpaque 方法只是为了提高性能。如果您编写自己的渲染器,请记住这一性能考虑因素。

这基本上就是 JB 上面所解释的。

感谢您的(快速)回答

© www.soinside.com 2019 - 2024. All rights reserved.