combobox - Does JavaFX 8.0 TableView have a sort bug? -


java 8.0 x64, win7 x64, clojure, emacs.

i'm doing stuff in clojure tableview wherein i'm proxying tablecell can render , edit arbitrary things in it. values fields of map inside atom. code below. makes use of plenty of utility functions , macros make simpler, gist. main thing management of cell's graphic , text properties.

there keyboard handler attached combobox knows when user presses enter, etc. handler removed on defocus cell, don't end multiple handlers in object.

in example have 3 columns, 1 name of field (a simple cell factory shows text , not editable), 1 value (fancy cell factory), , 1 type (simple cell factory). output, using sample data, looks this:

enter image description here

when sort table based on value things seem work fine, follows:

normally, when keyboard handler triggers, calls cell's commitedit function, calls tablecell superclass commitedit. tableview magic behind scenes calls column's oneditcommit handler, commits edit database. after superclass commitedit returns, there nothing left in cell's commitedit. cell's updateitem automatically called tableview replaces combobox normal contents of cell.

problem

when sort table based on field column 1 or more times, or type column two or more times , try edit combobox (in case color selector), takes click combobox drop down, , enter key doesn't work, follows:

cause

in broken case, tablecell's superclass appears return , not call column's oncommitedit handler, nor cell's updateitem called, cell not rendered normal non-editing state, ie, without combobox.

normal , broken cases this: enter image description here

the debug text output in normal case , broken case shown here. enter image description here

the weird thing problem appears non-color combobox (the sides field has combobox editor numbers, example).

so bug in javafx tableview? or doing wrong?

(defn add-handlers!   "adds common keyboard handler , focus listener temporary editing graphic.   graphic typically textfield or combo-box. cell tablecell   being edited.  getterfn function value graphic   can commited database."   [graphic cell getterfn]   (let [focus-listener (make-focus-change-listener cell getterfn)]     (println "adding focus , keyboard listener")     (add-listener! graphic :focused focus-listener)     (.setonkeypressed graphic (eventhandler [e] ;; here "cell" still refers tablecell                                             (condp = (.getcode e)                                               keycode/enter (do (println "enter pressed.  removing focus listener")                                                                 (remove-listener! graphic :focused focus-listener) ;; prevent double-commit on defocus                                                                 (.commitedit cell (getterfn)))                                               keycode/escape (do (println "esc pressed. removing focus listener")                                                                  (remove-listener! graphic :focused focus-listener) ;; prevent double-commit on defocus                                                                  (.canceledit cell)) ;; removes textfield                                               keycode/tab (let [index (.. cell gettablerow getindex)                                                                 next-column (get-next-column cell (not (.isshiftdown e)))]                                                             (println "tab pressed.  removing focus listener")                                                             (remove-listener! graphic :focused focus-listener) ;; prevent double-commit on defocus                                                             (.commitedit cell (getterfn))                                                             (.edit (.gettableview cell) index next-column))                                               nil))))) ;; nothing   (defn make-combobox   "implements dropdown combobox.  'cell' fancy table cell in   question.  'items' list of things dropdown, can   dropdown can render , choose final item"   [cell initvalue & [items]]   (let [cmb (jfxnode combobox (observable items))         cell-factory fancy-listcell-factory         blank-cell (.call cell-factory nil)]     (doto cmb       (add-handlers! cell #(.getvalue cmb))       (.setvalue initvalue)       (.setbuttoncell blank-cell)       (.setcellfactory cell-factory))))   (defn render-cell-with-item!   "puts correct item in cell graphic and/or text property based on item   type.  additional arguments editing such drop-down,   handled in startedit function; function renders   cell when called updateitem or canceledit."   [cell item]   (cond     (instance? node item) (set-graphic-text! cell item nil) ;; graphic/node item     (instance? boolean item) (let [[var full-accesspath] (calc-full-accesspath cell)                                    cb (jfxnode checkbox                                                :text (str item)                                                :selected item                                                :disable (not (mutable? var)))]                                (.seteditable cell false)                                (set-graphic-text! cell cb nil)                                (when (mutable? var)                                  (uni-bind! (.selectedproperty cb) var full-accesspath)))     (instance? clojure.lang.persistentvector item) (set-graphic-text! cell (label. "put vector editor here") nil)     (instance? color item) (set-graphic-text! cell (make-color-box item) (color-map-inverse item))     ;; other types go here, presumably text types, assume editable     :else (set-graphic-text! cell nil (si/to-normstr item))))   ;; else set underlying text   (def fancy-tablecell-factory   "the main callback interface constructs actual each cell   arbitrary types.  assumes editable cell text representations."   (callback [column]               (proxy [tablecell] []               (updateitem [item empty]                 (proxy-super updateitem item empty)                 (when (not empty)                    (render-cell-with-item! item)))                (startedit []                 (proxy-super startedit)                 ;; change appropriate graphic when editing                 (println "in proxy's startedit.  column commithandler is" (.getoneditcommit column))                 (let [item (apply access-db (calc-full-accesspath this))                       options (get-field-options this)] ;; nil ...                   (if-let [combo-items (:combo-items options)] ;; ... put argument :combo-items                     (let [cmb (make-combobox item combo-items)]                       (set-graphic-text! cmb nil)                       (.requestfocus cmb)                       (.show cmb)) ;; makes drop-down appear without clicking twice.                     (when (textish? item)                       (let [tf (make-textfield-editor this)]                         (set-graphic-text! tf nil) ;; set tf graphic; leave existing text alone                         (.requestfocus tf)                         (.selectall tf))))))               (canceledit []                 ;; canceledit gets called either defocus or esc.                 ;; in case, use item in database                 ;; cell , render in updateitem                 (proxy-super canceledit)                 (let [item (apply access-db (calc-full-accesspath this))]                   (render-cell-with-item! item)))               (commitedit [value]                 ;; nothing here.  commits happen either in textfield callback or in column edit callback                 (println "in cell's commitedit, before super")                 (proxy-super commitedit value)                 (println "in cell's commitedit, after super")))))   (defn inner-table-view*   "make inner table view use inspector-view , table-view"   [var accesspath columns]   (let [obslist (observable (var-snapshot var accesspath))]     (jfxnode tableview              :user-data {:var var ;; actual var...                           :accesspath accesspath }  ;; ... , how displayed data              :items obslist              :columns columns              :editable (mutable? var))))  (defn inspector-view   "takes plain map or atom/var/ref/agent of map , displays fields   , values in jfx tableview. compound values (ie maps, vectors,   etc., displayed string value.  if access   supplied, assumes m var/ref/atom , assigns appropriate   linkage between m , view contents.  topmost available var or   map assigned tableview, , accessor each field   assigned each column."   [var & {:keys [accesspath field-options]}]   (let [ismutable (mutable? var)         field-col (jfxnode tablecolumn "field"                            :cell-value-factory cell-value-factory                            :cell-factory simple-tablecell-factory                            :user-data {:accessfn key } ;; label-only option not relevant yet                            :editable false                            :sortable true)         value-col (jfxnode tablecolumn "value"                            :cell-value-factory cell-value-factory                            :cell-factory fancy-tablecell-factory                            :user-data {:accessfn val} ;; val fn accessing cell values data item                            :on-edit-start (eventhandler [e] (println "editing column " (.getoldvalue e) (.getnewvalue e)))                            :on-edit-cancel (eventhandler [e] (println "canceling column event" e))                            :on-edit-commit (eventhandler [e] (do (println "column's on-edit-commit handler calling column-commit") (column-commit e)))                            :editable ismutable                            :comparator columncomparator)         type-col (jfxnode tablecolumn "type"                           :cell-value-factory cell-value-factory                           :cell-factory simple-tablecell-factory                           :user-data {:accessfn #(type (val %))}                           :editable false                           :sortable true)         cols [field-col value-col type-col]          tv (inner-table-view* var accesspath cols)]     ;; add options table's userdata.  inspector-view     ;; not table-view, don't put in inner-table-view     ;; function     (let [userdata (.getuserdata tv)           newuserdata (conj userdata {:field-options field-options})]       (.setuserdata tv newuserdata))      ;; add watches, use tv instance key can remove later     ;; gets called each time db changed.     (if (mutable? var)       (add-watch var tv (fn [k r o n] ;; key ref old new                           (println "inside kron new var" n)                           ;; capture existing sort order , type                           ;; taken http://stackoverflow.com/questions/11096353/javafx-re-sorting-a-column-in-a-tableview                           (let [sort-order (vec (.getsortorder tv)) ;; need remember observablelist<tablecolumn> , vectorize or gets reset underneath                                 sort-types (map #(.getsorttype %) sort-order)                                 sortables (map #(.issortable %) sort-order)]                              ;; here put items tableview after change                             (.setitems tv (observable (var-snapshot var accesspath)))                               ;; sort order empty put in                             (let [new-sort-order (.getsortorder tv)] ;; observablelist<tablecolumn>                               (.setall new-sort-order (into-array sort-order)) ;; reset sort order based on there before                                ;; assign sorting each column                               (doseq [col sort-order, sort-type sort-types, sortable sortables]                                 (.setsorttype col sort-type)                                 (.setsortable col sortable)))))))     tv)) 

i found problem, was, of course, in code.

because jfx reuses cells, editable property of cell persists when there different contents rendered in cell. in case had boolean member of databased rendered checkbox. checkbox clickable, cell in rendered not editable. when cell got re-rendered after sort different item, non-editing state persisted , screwed editing of new item, somehow led drop-down box not going away properly. bug showed in non-combobox items too, such text edits, etc.

so solution explicitly set editable property of cell each item type rendered.


Comments

Popular posts from this blog

yii2 - Yii 2 Running a Cron in the basic template -

asp.net - 'System.Web.HttpContext' does not contain a definition for 'GetOwinContext' Mystery -

mercurial graft feature, can it copy? -