2009-07-28 6 views
9

J'avais utilisé l'approche traditionnelle Java TableCellRenderer pour fournir les moteurs de rendu dans un scala.swing.Table où je déclare mes moteurs de rendu sur la table TableColumnModel. Le code de cette ressemblait:Rendeurs de cellules de table idiomatiques dans 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]) 
    } 
} 

Malheureusement, cela semble avoir une fuite de mémoire - sans doute parce que je suis en train de créer une nouvelle instance de composants pour toutes les cellules de la table (pour les lignes de ~ 30K). Certes, quand je remplace ma table de scala avec un JTable (en utilisant exactement la même colonne et données modèles) ma fuite de mémoire disparaît.

Ma question est donc de savoir quel type de code les gens utilisent-ils en surchargeant la méthode rendererComponent en supposant que l'on possède ses propres moteurs de rendu?

Répondre

8

La façon idiomatiques d'utiliser CellRenderer de table Scala est d'utiliser Table.AbstractRenderer (si la mise en œuvre de votre propre) ou un de ses sous-classes:

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

Dans ce cas prepare est une méthode que vous définiriez votre propre moteur de rendu classe:

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

Ensuite, il est utilisé en remplaçant la méthode rendererComponent sur Table:

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 est livré avec ses propres implémentations de AbstractRenderer, à savoir LabelRenderer qui prend une fonction comme un argument, la conversion d'une instance de MyObj à un Tuple2 constitué d'un String et un Icon, pour que l'étiquette d'affichage:

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

Je pense que vous voulez 'peer.convertColumnIndexToModel (col) 'à la place de' peer.convertColumnIndexToModel (row) ' –

+0

Vous pouvez également utiliser' scala.swing.Table.viewToModelColumn (Int): Int'. Notez bien pourquoi il n'y a pas de méthode wrapper équivalente pour les lignes. –

1

Merci beaucoup pour votre exemple oxbow_lakes!

IMHO ce scala-chose est devenu aussi laid que le rendu de table peut éventuellement obtenir. Essayer de cacher autant que possible ...

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 
} 

En utilisant comme (au moins la "configure" est parti ...)

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

J'ai lu votre commentaire mais au début je n'ai pas compris. Ce n'est qu'après avoir créé plusieurs sous-classes de 'Table.AbstractRenderer' que j'ai réalisé pourquoi j'avais besoin de votre code. L'amélioration que j'ajouterais est que vous pouvez aussi passer les paramètres 'configure()' restants à 'render (a, sel, foc, row, col)'. J'ai finalement eu besoin de tous – Core

Questions connexes