Scrollable Tree View
rafael-guerra-www opened this issue · 5 comments
How can we produce a scrollable Tree View using Mousetrap.jl, as in this Gtk.jl example
Hi, sorry for the late reply. TreeView
was deprecated in GTK4, but mousetrap has ColumnView
which works almost identically.
To make any widget scrollable, you insert it into a Viewport
, see here for more information.
To create the above, first update mousetrap (as there was a bug with ColumnView
that was only fixed recently):
import Pkg; Pkg.update("Mousetrap")
Then run:
using Mousetrap
main() do app::Application
window = Window(app)
# create column view with columns
column_view = ColumnView()
row_index_column = push_back_column!(column_view, " ")
count_column = push_back_column!(column_view, "#")
name_column = push_back_column!(column_view, "Name")
weight_column = push_back_column!(column_view, "Weight")
unit_column = push_back_column!(column_view, "Units")
# fill columns with text
for i in 1:100
row = [
Label(string(i)), # row index
Label(string(rand(0:99))), # count
Label(rand(["Apple", "Orange", "Banana", "Kumquat", "Durian", "Mangosteen"])), # name
Label(string(rand(0:100))), # weight
Label(string(rand(["mg", "g", "kg", "ton"]))) # unit
]
set_horizontal_alignment!.(row, ALIGNMENT_START)
push_back_row!(column_view, row...)
end
# create viewport, this will add a scrollbar
scrolled_viewport = Viewport()
set_propagate_natural_width!(scrolled_viewport, true) # hides horizontal scrollbar
set_child!(scrolled_viewport, column_view)
# show both in window
set_child!(window, scrolled_viewport)
present!(window)
end
@Clemapfel, thanks for your time and nice example, which ran fine.
How can we add to the Mousetrap.jl code above some subtitles (or submenus) that expand when clicked to show their respective column view items?
See the example in the linked original Gtk code:
ColumnView
does not support nested rows, I removed that feature because it would've made filtering rows, which is a feature scheduled for a future version of mousetrap, impossible.
You can still kinda do this by inserting a widget that has the expandable element as a row, keeping everything but the first column empty.
There are two options for the widget, you can either use Expander
, which has a label and a child:
expander = Expander()
set_label_widget!(expander, Label("Expander VEGETABLE"))
set_child!(expander, Label("Nested Tomato"))
set_widget_at!(column_view, row_index_column, 5, expander)
Or you can use a nested ListView
, which is a little more complicated, but it auto-indents the nested elements, and you can have more than one nested child:
expander_list = ListView(ORIENTATION_VERTICAL)
nested_it = push_back!(expander_list, Label("ListView VEGETABLE"))
push_back!(expander_list, Label("Nested Tomato"), nested_it)
push_back!(expander_list, Label("Nested Apple"), nested_it)
set_widget_at!(column_view, row_index_column, 6, expander_list)
Here the outermost listview has only one child, which acts as the label "ListView VEGETABLE"
, while the inner listview has the actual elements "Nested Tomato"
, "Nested Apple"
.
You can see how the first column is stretched to fit the entire expander, which isn't ideal, but its the closest you can get using ColumnView
.
Full main.jl
for the image above is:
using Mousetrap
main() do app::Application
window = Window(app)
# create column view with columns
column_view = ColumnView()
row_index_column = push_back_column!(column_view, " ")
count_column = push_back_column!(column_view, "#")
name_column = push_back_column!(column_view, "Name")
weight_column = push_back_column!(column_view, "Weight")
unit_column = push_back_column!(column_view, "Units")
set_expand!.((row_index_column, count_column, name_column, weight_column, unit_column), true)
# fill columns with text
for i in 1:100
row = [
Label(string(i)), # row index
Label(string(rand(0:99))), # count
Label(rand(["Apple", "Orange", "Banana", "Kumquat", "Durian", "Mangosteen"])), # name
Label(string(rand(0:100))), # weight
Label(string(rand(["mg", "g", "kg", "ton"]))) # unit
]
# insert empty row, then set first element to expandable item, while leaving the other columns empty
if i == 5 # using `Expander`
expander = Expander()
set_label_widget!(expander, Label("Expander VEGETABLE"))
set_child!(expander, Label("Nested Tomato"))
set_widget_at!(column_view, row_index_column, 5, expander)
elseif i == 6 # using nested `ListView`
expander_list = ListView(ORIENTATION_VERTICAL)
nested_it = push_back!(expander_list, Label("ListView VEGETABLE"))
push_back!(expander_list, Label("Nested Tomato"), nested_it)
push_back!(expander_list, Label("Nested Apple"), nested_it)
set_widget_at!(column_view, row_index_column, 6, expander_list)
else # else fill all columns
set_horizontal_alignment!.(row, ALIGNMENT_START)
push_back_row!(column_view, row...)
end
end
# create viewport, this will add a scrollbar
scrolled_viewport = Viewport()
set_propagate_natural_width!(scrolled_viewport, true) # hides horizontal scrollbar
set_child!(scrolled_viewport, column_view)
# show both in window
set_child!(window, scrolled_viewport)
present!(window)
end
In my personal opinion, if the nested elements are the last rows of the column view like in the GTK picture you send, I would do this by doing a vertical box whose first element is the column view, and the last two elements are ListView
s. That way the first column doesn't get stretched.
# after `column_view` was filled
vbox = Box(ORIENTATION_VERTICAL)
push_back!(vbox, column_view)
expander_list = ListView(ORIENTATION_VERTICAL)
nested_it = push_back!(expander_list, Label("ListView VEGETABLE"))
push_back!(expander_list, Label("Nested Tomato"), nested_it)
push_back!(expander_list, Label("Nested Apple"), nested_it)
push_back!(vbox, expander_list)
scrolled_viewport = Viewport()
set_propagate_natural_width!(scrolled_viewport, true) # hides horizontal scrollbar
set_child!(scrolled_viewport, vbox) # child is now vbox, which contains column_view
But this way you can't have rows after the nested elements, since the end of the column_view is above them
Thank you for your feedback and I am sorry, but I could not test your latest code as I am now experiencing errors:
(julia.exe:20440): GLib-GIO-WARNING **: 21:13:43.406: C:\Users\jguerra\.julia\artifacts\13606487e48c4dea9d20813adf4f03a3edea59fd\bin\gdbus.exe dbus binary failed to launch bus, maybe incompatible version
[ERROR] In Mousetrap.main: MethodError: no method matching set_expand!(::ColumnViewColumn, ::Bool)
I will get back to you later when this has been sorted out.
PS:
Meanwhile your snapshots do not seem to match the Gtk example? Tbc.
My bad, I was using the development version of Mousetrap, simply remove the line 16 with set_expand!
and it should work.
It doesn't match your picture because ColumnView
does not support expanded rows, like I said the closest you can do is inserting a row that has an expander. The picture is using Gtk.TreeView
, which was deprecated in 4.10 and is not part of mousetrap.