9

通常在使用JTableor时JTree,用户会定义自己的单元格渲染器。

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

这一切都运作良好。

我的问题是怎么可能?

每次表调用此方法时,都会为其赋予不同的参数,并且输出标签会根据这些参数而更改。如果它确实是标签的同一个实例——不应该根据最后一次调用这个方法来改变它吗?这是否意味着所有表格的单元格都被感染了由相同的标签实例组成,该标签实例具有相同的值(最后一次调用渲染器方法的值)?

我已经搜索了网络,并在 Swing 的代码中挖掘,但找不到任何克隆复制构造函数实际上复制输出标签的行为。我找不到任何证据表明(也许)swing 使用反射来每次从头开始重新实例化渲染器。

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

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

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

我无法得到它。你们中的任何一个都可以吗?

4

3 回答 3

13

它是享元模式的实现。

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

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

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

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

于 2012-12-02T19:47:37.400 回答
4

除了@JB 对如何和使用享元模式的明确说明之外,请注意这两个类如何提供公共方法和. 检查这些方法以了解如何使用类文字作为运行时类型标记来按类选择渲染器或编辑器(如果没有按列指定)。在内部,使用例如存储。JTableJTreegetCellRenderer()getCellEditor()JTableJTableHashtable defaultRenderersByColumnClass

于 2012-12-02T20:48:18.817 回答
4

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

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

This is essentially what JB explained above.

Thanks for the (quick) answers

于 2012-12-02T21:48:56.863 回答