【问题标题】:Idiomatic table cell renderers in ScalaScala 中惯用的表格单元格渲染器
【发布时间】:2010-11-14 18:22:54
【问题描述】:

我一直在使用传统的 Java TableCellRenderer 方法在 scala.swing.Table 中提供渲染器,我在表的 TableColumnModel 上声明了我的渲染器。代码如下:

val myTable = new Table {
  lazy val tcm = initColumnModel
  peer.setColumnModel(tcm)

  override 
  protected def rendererComponent(sel: Boolean, foc: Boolean, row: Int, col: Int) = {
    //GET THE VALUE FROM THE TableModel
    val value = model.getValueAt(
                        peer.convertRowIndexToModel(row), 
                        peer.convertColumnIndexToModel(col))
    //GET THE RENDERER FROM THE ColumnModel
    val renderer = tcm.getColumn(col).getCellRenderer
    //WRAP IN A COMPONENT
    Component.wrap(renderer.getTableCellRendererComponent(
                        peer, 
                        value, 
                        sel, 
                        foc, 
                        row, 
                        col).asInstanceOf[JComponent])
   }
}

不幸的是,这似乎存在内存泄漏 - 大概是因为我正在为表中的每个单元格(约 30k 行)创建一个新的 Component 实例。当然,当我用 JTable(使用完全相同的 columndata 模型)替换我的 scala 表时,我的内存泄漏就消失了。

因此,我的问题是,假设一个人拥有自己的单元格渲染器,人们在覆盖 rendererComponent 方法时会使用什么样的代码?

【问题讨论】:

    标签: swing scala jtable tablecellrenderer


    【解决方案1】:

    非常感谢您提供的示例 oxbow_lakes!

    恕我直言,这个 Scala 的东西已经变得像表格渲染一样丑陋。 试图尽可能地隐藏它......

    class TableRenderer[A](comp: TableRendererComp[A]) extends Table.AbstractRenderer[A,TableRendererComp[A]](comp) {
      def configure(t: Table, sel: Boolean, foc: Boolean, a: A, row: Int, col: Int): Unit =
        component.render(a, sel, foc)
    }
    
    trait TableRendererComp[A] extends Component {
      def render(a: A, sel: Boolean, foc: Boolean): Unit
    }
    

    使用like(至少“配置”不见了……)

    val tcr = new TableRenderer[MyObj](new MyRenderer)
    
    class MyRenderer extends Label with TableRendererComp[MyObj] {
      def render(o: MyObj, sel: Boolean, foc: Boolean) {
         text = o.toString //or whatever
      }
    }
    

    【讨论】:

    • 我阅读了您的评论,但起初没有明白。只有在我创建了Table.AbstractRenderer 的几个子类之后,我才意识到我为什么需要你的代码。我要补充的改进是您不妨将剩余的configure() 参数传递给render(a, sel, foc, row, col)。我最终需要所有这些
    【解决方案2】:

    使用 Scala 表格单元格渲染器的惯用方式是使用 Table.AbstractRenderer(如果您自己实现)或其子类之一:

    val tcr = new Table.AbstractRenderer[MyObj, MyRenderer](new MyRenderer) {
      def configure(t: Table, sel: Boolean, foc: Boolean, o: MyObj, row: Int, col: Int) = {
        //component variable is bound to your renderer
        component.prepare(o)
      }
    }
    

    在这种情况下,prepare 是您可以在自己的渲染器类中定义的方法:

    class MyRenderer extends Label {
      def prepare(o: MyObj) {
          text = o.toString //or whatever
      }
    }
    

    然后通过覆盖Table 上的rendererComponent 方法来使用它:

    val t = new Table {
      override def rendererComponent(sel: Boolean, foc: Boolean, row: Int, col: Int) = {
         //FIND VALUE
         val v = model.getValueAt(
                           peer.convertRowIndexToModel(row), 
                           peer.convertColumnIndexToModel(row))
         col match {
           case 0 => tcr.componentFor(this, sel, foc, v, row, col)
         }
      }
    }
    

    Scala 有自己的AbstractRenderer 实现,即LabelRenderer,它接受一个函数作为参数,将MyObj 的实例转换为由String 组成的Tuple2Icon,用于显示该标签:

    val ltcr = new LabelRenderer[MyObj] ( (o: MyObj) => (null, o.toString)  )
    

    【讨论】:

    • 我想你想要peer.convertColumnIndexToModel(col)而不是peer.convertColumnIndexToModel(row)
    • 您也可以使用scala.swing.Table.viewToModelColumn(Int): Int。请注意为什么没有等效的行包装方法..
    猜你喜欢
    • 2010-11-22
    • 2018-08-26
    • 2021-09-24
    • 2011-10-02
    • 2018-02-13
    • 2018-10-15
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    相关资源
    最近更新 更多