2009-07-28 15 views
9

Ich hatte den traditionellen Java TableCellRenderer Ansatz für die Bereitstellung der Renderer in einem scala.swing.Table verwendet, wo ich meine Renderer auf der Tabelle TableColumnModel deklarieren. Der Code für das sah aus wie:Idiomatische Tabellenzellen-Renderer in Scala

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]) 
    } 
} 

Leider ist dies ein Speicherleck zu haben scheint - vermutlich, weil ich in der Tabelle für jede Zelle eine neue Komponente Instanz erschaffe (für ~ 30k Zeilen). Sicherlich, wenn ich meine Scala-Tabelle durch eine JTable (mit genau den gleichen Spalte und Daten Modelle ersetzt) ​​mein Speicherleck verschwindet.

Meine Frage ist daher, welche Art von Code verwenden Menschen beim Überschreiben der rendererComponent-Methode vorausgesetzt, man hat seine eigenen Cell-Renderer?

Antwort

8

Der idiomatische Weg von Scala Tabellenzelle Renderer verwendet, ist Table.AbstractRenderer zu verwenden oder eine ihrer Unterklassen (wenn Sie Ihre eigene Implementierung):

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 ist ein Verfahren, in diesem Fall, dass Sie auf Ihrem eigenen Renderer definieren würden Klasse:

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

Dann wird diese durch Überschreiben der rendererComponent Methode auf Table verwendet:

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 kommt mit seinen eigenen Implementierungen von AbstractRenderer, nämlich LabelRenderer, die eine Funktion als ein Argument nimmt, eine Instanz von MyObj zu einem Tuple2 Umwandeln des aus einem String und einem Icon, für das Etikett zu display:

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

Ich glaube, Sie wollen 'peer.convertColumnIndexToModel (col) '' anstelle von 'peer.convertColumnIndexToModel (Zeile)' –

+0

Sie können auch 'scala.swing.Table.viewToModelColumn (Int): Int' verwenden. Beachten Sie, warum es keine äquivalente Wrapper-Methode für Zeilen gibt. –

1

Vielen Dank für Ihr Beispiel oxbow_lakes!

IMHO dieses Scala-Ding ist so hässlich geworden, wie Table-Rendering möglicherweise bekommen kann. Der Versuch, es so weit wie möglich zu verstecken ...

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 
} 

wie Verwenden von (zumindest die "konfigurieren" ist weg ...)

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 
    } 
} 
+0

Ich habe Ihren Kommentar gelesen, aber zuerst nicht verstanden. Erst nachdem ich mehrere Unterklassen von 'Table.AbstractRenderer' erstellt habe, wurde mir klar, warum ich Ihren Code brauchte. Die Verbesserung, die ich hinzufügen würde, ist, dass Sie auch die restlichen 'configure()' Parameter zu 'render (a, sel, foc, row, col)' übergeben können. Ich brauchte schließlich alle von ihnen – Core

Verwandte Themen