Note that there are some explanatory texts on larger screens.

plurals
  1. POJavaFX and Clojure -- can't put TableCell inside a TableCell, must use some other Node type
    text
    copied!<p>I'm using Clojure on JavaFX 2.0 to create a TableView with arbitrary nodes in a given <code>TableColumn</code>. I've <code>proxy</code>ied a TableCell, and in the <code>UpdateItem</code> method I'm trying various attempts to <code>.setGraphic</code> the new "real" Node that I want to use. I can create another <code>TableCell</code> for example a <code>CheckBoxTableCell</code>, but the program crashed when it gets to the <code>.setGraphic</code> call with <code>NullPointerException</code> during some internal call to <code>setPrefWidth</code>, basically when the column is trying to lay itself out. It seems that I <em>can</em> however put a non-<code>TableCell</code> derived node, eg a plain button with its own <code>ActionEvent</code> etc. I don't have a problem doing this. </p> <p>QUESTION: Why does an instance of <code>TableCell</code> crash when it's used as the graphic of another <code>TableCell</code>? I'm guessing it expects a <code>TableColumn</code> or <code>TableView</code> to be a parent or something.</p> <p>In the abbreviated code below <code>item</code> is the underlying data item which is a clojure map, whose values are java bean/properties.</p> <pre><code>(defmacro callback "Reifies the callback interface." [args &amp; body] `(reify javafx.util.Callback (~'call [this# ~@args] ~@body))) (defmacro eventhandler "Reifies the eventhandler interface." [args &amp; body] `(reify javafx.event.EventHandler (~'handle [this# ~@args] ~@body))) (defn button-cell-factory "Uses a proxy of TableCell because there is no ButtonTableCell in javafx." [] (callback [callback-column] (proxy [TableCell] [] (updateItem [item empty] ;; Item is the content of the TableCell, not very interesting since it's just the button and button parameters ;; This is the actual TableCell with all the info we are interested in (proxy-super updateItem item empty) (println "in button-cell proxy updateItem" item empty) (if empty nil (let [button (doto (Button. (:name item)) (.setMaxWidth Double/MAX_VALUE) (.setAlignment Pos/CENTER_LEFT) (.setOnAction (eventhandler [evt] (if-let [action (:action item)] (let [index (.getIndex this) tableview (.getTableView this) rowdata (.. tableview (getItems) (get index))] (action rowdata)) nil)))) imageview (ImageView. (:image item))] (if (not (nil? imageview)) (.setGraphic button imageview)) (.setGraphic this button))))))) (defn generic-cell-factory [spec] "Provide arbitrary cell based on data" (callback [callback-column] (proxy [TableCell] [] (updateItem [item empty] (proxy-super updateItem item empty) (or empty (let [inner-cell (.call (button-cell-factory) callback-column)] (.setGraphic this inner-cell))))))) ;; this crashes when inner-cell is a proxy of TableCell, but not when it's a Button or other non-TableCell node. (defn make-cell-factory "Generic factory maker. Dispatches on model, and uses other column specs. Column in the actual column created. spec is the full spec map. The other names are the values of the map destructured." [column {:keys [model] :as spec} ] (cond ;; ... (= model :generic) (generic-cell-factory spec) ;; ... )) (defn make-tableview "colspecs is a map of keys and names." [colspecs] (let [tableview (TableView.)] (doseq [{:keys [name key editable minwidth] :as colspec} colspecs] (let [col (TableColumn. name)] (doto col ;; ... (.setCellFactory (make-cell-factory col colspec))) ;; I can call (button-cell-factory) here just fine, but trying to put a button-cell in TableCell crashes. ;; ... (.. tableview (getColumns) (add col)))) tableview)) </code></pre> <p>Abbreviated error:</p> <pre><code>SEVERE: javafx.scene.control.Control loadSkinClass Failed to load skin 'StringProperty [bean: TableView[id=null, styleClass=table-view], name: skinClassName, value: com.sun.javafx.scene.control.skin.TableViewSkin]' for control TableView[id=null, styleClass=table-view] java.lang.NullPointerException at com.sun.javafx.scene.control.skin.TableCellSkin.computePrefWidth(TableCellSkin.java:102) at javafx.scene.Parent.prefWidth(Parent.java:867) at javafx.scene.layout.Region.prefWidth(Region.java:1368) at javafx.scene.control.Control.computePrefWidth(Control.java:852) ... </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload