procesadores de celdas mesa idiomáticas en Scala
-
19-09-2019 - |
Pregunta
Yo había estado utilizando el enfoque tradicional TableCellRenderer
Java para proporcionar los procesadores en un scala.swing.Table
donde declaro mis extracción de grasas en TableColumnModel
de la tabla. El código para esta parecía:
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])
}
}
Desafortunadamente esto parece tener una pérdida de memoria - presumiblemente porque estoy creando una nueva instancia de componente para cada celda de la tabla (por filas ~ 30k). Ciertamente, cuando sustituyo mi mesa Scala con un JTable
(usando exactamente los mismos columna y datos modelos) mi pérdida de memoria desaparece.
Mi pregunta es, por lo tanto, qué tipo de código de hacer la gente usa cuando reemplazando el método rendererComponent
suponiendo que uno tiene los propios procesadores de celdas?
Solución
La forma idiomática de la utilización de procesadores de celdas Scala tabla es utilizar Table.AbstractRenderer
(si la implementación de su propia) o una de sus subclases:
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)
}
}
En este caso prepare
es un método que se definiría en su propia clase de procesador:
class MyRenderer extends Label {
def prepare(o: MyObj) {
text = o.toString //or whatever
}
}
A continuación, esto se utiliza reemplazando el método rendererComponent
en 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 viene con sus propias implementaciones de AbstractRenderer
, a saber LabelRenderer
que tiene una función como un argumento, la conversión de una instancia de MyObj a un Tuple2
que consiste en un String
y un Icon
, para que la etiqueta que se vea :
val ltcr = new LabelRenderer[MyObj] ( (o: MyObj) => (null, o.toString) )
Otros consejos
Muchísimas gracias por tu ejemplo oxbow_lakes!
En mi humilde opinión esta scala-cosa ha quedado tan feo como tabla-renderizado posiblemente pueda obtener. Tratando de ocultar lo más posible ...
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
}
Usando como (al menos la "configurar" se ha ido ...)
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
}
}