Closed lispmarc closed 3 years ago
I was in your shoes a couple of months back—with a side of needing to be able to tab from column-to-column for easy data entry—and ended up with the code below. I've got everything worked out except how to define the table in such a way that it knows what the next column is.
I can create a table using:
(editable-table [["Column 1" :column-1-data-field] ["Column 2" :column-2-data-field]]
(get-in context [:cljfx.context/m :next-level-to-data :level-after-that-to-data :etc]))}
The get-in-context
part expects to be pointed to a vector of maps (the records to be displayed) with fields of :column-1-data-field and :column-2-data-field. (Mine are coming from postgraphile.)
You'll notice it's not that much different from the example, just a little simpler.
;====table stuff...for handling all the weird and complicated issues that arise when doing a table control====
(defn focus-when-on-scene! [node]
(if (some? (.getScene node))
(.requestFocus node)
(.addListener (.sceneProperty node)
(reify ChangeListener
(changed [this _ _ new-scene]
(when (some? new-scene)
(.removeListener (.sceneProperty node) this)
(.requestFocus node)))))))
(defn editable-cell [{:keys [fx/context id attr value-converter] :as e}]
(let [edit (fx/sub-val context :edit)
value (attr id)]
(when (= edit [id attr])
(if (= edit [id attr])
{:fx/type fx/ext-on-instance-lifecycle
:on-created focus-when-on-scene! ;; using it with `ext-on-instance-lifecycle`
:desc {:fx/type :text-field
:on-key-pressed {:event/type :edit-next-column :next-column :data}
:text-formatter {:fx/type :text-formatter
:value-converter value-converter
:value value
:on-value-changed {:event/type :cell-commit
:attr attr
:id id}}}}
{:fx/type :label
:on-mouse-clicked {:event/type :grid-activate-edit :id id :attr attr}
:text (str value)})))
(defn make-attr-cell-factory [view attr value-converter]
(fn [id]
{:text ""
:graphic {:fx/type view
:id id
:attr attr
:value-converter value-converter}}))
(defn etc [header data-column]
{:fx/type :table-column
:text header
:cell-value-factory identity
:cell-factory {:fx/cell-type :table-cell
:describe (make-attr-cell-factory editable-cell data-column :default)}})
(defn editable-table [columns items]
{:fx/type :table-view
:columns (map #(apply etc %) columns)
:items items})
Perhaps this is of some use.
It certainly is, one question however, I assume in editable-table that items is a vector of rows to be displayed in the table. how is a column mapped on a column value of a row in the vector. I guess I don't fully understand how a collection of rows with column values is mapped on the columns in a table.
Thanks
You are correct. The items are a vector of maps:
[{:first-name "John" :last-name "Smith" :age 24} {:first-name "Bob" :last-name "Roberts" :age 45}...]
The data is extracted here:
(defn editable-cell [{:keys [fx/context id attr value-converter] :as e}]
(let [edit (fx/sub-val context :edit)
value (attr id)] ;<----
So, if you define your table:
(editable-table [["first" :first-name] ["last" :last-name]["age" :age]...
When you get to that line in editable-cell
, it's:
(:first-name {:first-name "John" :last-name "Smith" :age 24})
then
{:last-name {:first-name "John" :last-name "Smith" :age 24})
then
{:age {:first-name "John" :last-name "Smith" :age 24})
Why is it called id
when it's the whole record? Because I pulled it out of e32:
(defn- editable-cell [{:keys [fx/context id attr value-converter]}]
(let [edit (fx/sub-val context :edit)
value (fx/sub-ctx context value-sub id attr)]
In that case, you're literally just passing in the ID and the attribute and the value-sub
routine is doing the extraction:
(defn- value-sub [ctx id attr]
(fx/sub-ctx ctx query-sub '[:find ?v . :in $ ?e ?a :where [?e ?a ?v]] id attr))
For me, simplifying this started with not caring where the data comes from. In most of the editable-table cases I have, it's a specific record already pulled from a DB, so my call looks like:
(editable-table [["first-name" :first-name] ["last-name" :last-name]]
(get-in context [:cljfx.context/m :selected-customer]))}
Hope that helps.
Thank you this really helps
Marc
@dsbw thanks for helping out!
I'm retunring to clojure after many years and looking for a non web based GUI and found cljfx (I have used seesaw before). I'm looking now for some sample code to work wit tables with editable cells. I looked at the example 'e32_editable_table_cell_with_datascript.clj' but found it difficult to understand because the use of 'datascript' en context in the code. Is there a more simple example of how to work with table, showing just the essence.
Thanks a lot in advance
Marc