JavaFX和Clojure - 不能把TableCell放在TableCell里面,必须使用其他一些Node类型

时间:2013-09-10 18:40:38

标签: java clojure javafx-2 javafx

我在JavaFX 2.0上使用Clojure来创建一个包含给定TableColumn中任意节点的TableView。我已经proxy使用了一个TableCell,并且在UpdateItem方法中我尝试了.setGraphic我要使用的新“真实”节点的各种尝试。我可以创建另一个TableCell,例如CheckBoxTableCell,但是在.setGraphic的内部调用期间,当NullPointerException调用setPrefWidth时,该程序崩溃了,基本上当专栏试图摆脱它时。似乎我可以然后放置一个非TableCell派生节点,例如一个普通按钮,它有自己的ActionEvent等。我这样做没有问题。

问题: 为什么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)
...

0 个答案:

没有答案
相关问题