Question

J'avais utilisé l'approche traditionnelle Java TableCellRenderer pour fournir les équarrisseurs dans un scala.swing.Table où je déclare mes équarrisseurs sur TableColumnModel de la table. Le code de cette ressemblait:

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 scala avec un JTable (en utilisant exactement les mêmes colonne et données modèles) ma fuite de mémoire disparaît.

Ma question est donc, quel genre de code de gens utilisent quand redéfinissant la méthode rendererComponent en supposant qu'on a les propres CellRenderer?

Était-ce utile?

La solution

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 classe renderer:

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 cette étiquette pour afficher :

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

Autres conseils

Merci une tonne pour votre exemple oxbow_lakes!

à mon humble avis ce scala-chose est devenu aussi laid que la table-rendu 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
}

Utilisation 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
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top