Home / Blog / Adding a table in my Jwt Clojure app

History always repeats itself and sometimes that's good. Here's a second chance to be part of it: tmdtc.com

Adding a table in my Jwt Clojure app

Here are the results of my exploration of Jwt tables with Clojure. The code is inspired by an example in the Jwt sources.

A table in Jwt is created with WTreeView

 let [ tree-view (WTreeView.) ]

and the columns are configure in a model object. In my case, I'll use the WStandardItemModel . When instanciating the model, you tell it how many row and columns it should have, in this case 0 rows (I don't know yet why I should pass anything else than 0 here) and 4 columns:

 (WStandardItemModel. 0 4)

Once the model is intanciated, we can set the column headers with the setHeaderData method:

 (.setHeaderData model 0 Orientation/Horizontal "Places")
 (.setHeaderData model 1 Orientation/Horizontal "Weather")
 (.setHeaderData model 2 Orientation/Horizontal "Drink")
 (.setHeaderData model 3 Orientation/Horizontal "Visited")

Now we should add data to the table! A data row is represented by a list of WStandardItem objects, each being the data displayed in a column, so in our case we'll have each row represented by a list of 4 elements. A list? That's perfect for Clojure! I'll build a list of the items I want in the table and map them to a list of WStandardItems, like this:

 (map #( WStandardItem. % ) '("Leuven" "Rain" "Beer" "Yes") )

For the fun I defined a function building the WStandardItem:

 (defn standard-itemize [ item ]
   (WStandardItem. item))

Which lets me write this code to build a row:

(map standard-itemize '("Leuven" "Rain" "Beer" "Yes") )

When we have the row, we can add it to the table with appendRow :

 (.appendRow model row)

We can the set assign this model to the tree-view with :setModel

 (.setModel tree-view model)

Once we know that, it's trivial to work on list of rows:

(let [data'(("Leuven" "Rain" "Beer" "Yes")("Brussels" "Rain" "Beer" "Yes")) )
 rows (map #( map standard-itemize %) data)]
....
(doall (map #(.appendRow model %) rows))

 

With a function I called standard-rowize taking a row of data and returning a row of WStandardItems, we get somewhat cleaner code:

(defn standard-rowize [ row ]
 (map standard-itemize row))


 (let [data'(("Leuven" "Rain" "Beer" "Yes")("Brussels" "Rain" "Beer" "Yes")) )
 rows (map standard-rowize data)]


 ... 
 (doall (map #(.appendRow model %) rows))

Here's the result, a table with row ordering and alternating row colors

But there's more to it than this. As the table is represented by a tree view, it can group rows and that is achieved really easily: each row can be the container of its sub rows! Here are the only changes to do:

Create a europe-row which will contain european cities

europe-row (WStandardItem. "Europe")

appends the rows to the europe-row rather than to the model:

(doall (map #(.appendRow europe-row %) rows))

and finally, append the europe-row to the model:

(.appendRow model europe-row)

This is all what's needed to get this:

The changes were so small that despite the fact that I discovered all this, it worked at the first try! Here's the code of the function buidling the tree-view:

(defn build-tree-view []
 ( let [ tree-view (WTreeView.)
 model (WStandardItemModel. 0 4)
 europe-row (WStandardItem. "Europe")
 rows (map standard-rowize '(("Leuven" "Rain" "Beer" "Yes")("Brussels" "Rain" "Waffles" "Yes")) )
 ]
 (.setHeaderData model 0 Orientation/Horizontal "Places")
 (.setHeaderData model 1 Orientation/Horizontal "Weather")
 (.setHeaderData model 2 Orientation/Horizontal "Item")
 (.setHeaderData model 3 Orientation/Horizontal "Visited")
 (.setAlternatingRowColors tree-view true)
 (doall (map #(.appendRow europe-row %) rows))
 (.appendRow model europe-row)
 (.setModel tree-view model)
 tree-view))

Let's go further and manipulated the table: let's add a button to toggle the alternated row colors. Again, the changes to make are minimal:

  • instanciate a WPushButton
  • instanciate a WContainerWidget and pass it as the parent widget to the button and treeview constructor
  • return the container in place of the treeview
  • add a listener to the click event of the button to toggle the rows coloring. This uses the macro written for the Jwt-Clojure previous post.

Here is the code where I indicated the lines that were added or adapted:

(defn build-tree-view []
 ( let [ 
 container (WContainerWidget.) ;added
 button (WPushButton. "Toggle colors" container) ;added
 tree-view (WTreeView. container) ;adapted
 model (WStandardItemModel. 0 4)
 europe-row (WStandardItem. "Europe")
 rows (map standard-rowize '(("Leuven" "Rain" "Beer" "Yes")("Brussels" "Rain" "Waffles" "Yes")) )
 ]
 (.. button clicked (addListener container (create-listener [mouse-event]
 (.setAlternatingRowColors tree-view (not (.hasAlternatingRowColors tree-view) ))))) ; added
 (.setHeaderData model 0 Orientation/Horizontal "Places")
 (.setHeaderData model 1 Orientation/Horizontal "Weather")
 (.setHeaderData model 2 Orientation/Horizontal "Item")
 (.setHeaderData model 3 Orientation/Horizontal "Visited")
 (.setAlternatingRowColors tree-view true)
 (doall (map #(.appendRow europe-row %) rows))
 (.appendRow model europe-row)
 (.setModel tree-view model) ;adapted
 container)) ;adapted

Although there's a lot more to explore (pagination being the first thing I want to explore next), this is is for now. I hope this encourages to test Jwt and Clojure, both being very exciting projects!

I'm available for hire 

If you're looking for someone to temporarily join your IT team, or if you need help to put IT to work in your company, I'm ready to help. Contact me now !

Mon Tue Wed Thu Fri Sat Sun
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31