2

我在 JavaFX 2.0 上使用 Clojure 在给定的TableColumn. 我已经proxy创建了一个 TableCell,并且在该方法中,我正在尝试对我想要使用的新“真实”节点进行UpdateItem各种尝试。.setGraphic我可以创建另一个TableCell,例如 a ,但是在对 的一些内部调用期间,程序在调用时崩溃了,CheckBoxTableCell基本上是当列试图自行布局时。然而,我似乎可以放置一个非派生节点,例如一个带有自己的普通按钮等。我这样做没有问题。 .setGraphicNullPointerExceptionsetPrefWidthTableCellActionEvent

问题:为什么一个实例在TableCell用作另一个实例时会崩溃TableCell?我猜它期望一个TableColumnTableView成为父母或其他东西。

在下面的缩写代码中item是底层数据项,它是一个 clojure 映射,其值为 java bean/properties。

(defmacro callback 
  "Reifies the callback interface."
  [args & body]
  `(reify javafx.util.Callback
     (~'call [this# ~@args]
       ~@body)))

(defmacro eventhandler
  "Reifies the eventhandler interface."
  [args & 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))

缩写错误:

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)
...
4

0 回答 0