I am building a Gtk.ColumnView-based GTK4 application and I noticed some oddity.
First the structure: The application’s main content page is fully used by a Gtk.ColumnView. This table contains multiple columns and rows. The first row is something like a label/key and uses a Gtk.Label. The other rows contain values, most of them also Gtk.Labels, but some contain a list of labels. I wrapped those into an Adw.WrapBox, so if the column width isn’t sufficient to display them, the list can break into multiple lines.
Now the oddity: I noticed that for a specific length of the list (in my case 5 elements with each element having 5-10 characters), the Gtk.ColumnViewCellWidget increases its height even thought Adw.WrapBox has enough space to display all items in a single row:
The following is a minimal working example for replicating the problem. It requires Adwaita 1.7 or higher.
When you resize the second column in this demo app, you should notice that one or multiple rows increase their height even though there’s enough space left. How can I achieve them break only when there’s really not enough space left?
import random
import string
import sys
import gi
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1') # >= version 1.7
from gi.repository import Gtk, Adw, Gio, GObject
class RowItem(GObject.Object):
label = GObject.Property(type=str, default="")
list1 = GObject.Property(type=Gtk.StringList, default=None)
list2 = GObject.Property(type=Gtk.StringList, default=None)
class ColumnViewApp(Adw.Application):
def __init__(self):
super().__init__(application_id='org.example.columnviewapp')
def do_activate(self):
win = Adw.ApplicationWindow(application=self, title='ColumnView Example')
win.set_default_size(600, 600)
column_view = Gtk.ColumnView()
column_view.set_hexpand(True)
column_view.set_vexpand(True)
column_view.add_css_class('data-table')
selection = Gtk.NoSelection()
store = Gio.ListStore.new(RowItem)
for i in range(3):
row_item = RowItem()
row_item.label = f"Row{i}"
row_item.list1 = Gtk.StringList.new([
''.join(random.choices(string.ascii_lowercase, k=6))
for _ in range(5)
])
row_item.list2 = Gtk.StringList.new([
"".join(random.choices(string.ascii_lowercase, k=5))
])
store.append(row_item)
selection.set_model(store)
column_view.set_model(selection)
for col_index in range(3):
factory = Gtk.SignalListItemFactory()
factory.connect('setup', self._on_factory_setup, col_index)
factory.connect('bind', self._on_factory_bind, col_index)
column = Gtk.ColumnViewColumn(title=f'Col{col_index + 1}', factory=factory)
column.set_expand(True)
column.set_resizable(True)
column_view.append_column(column)
win.set_content(column_view)
win.present()
def _on_factory_setup(self, factory, list_item, col_index):
if col_index == 0:
# Col1: GtkTreeExpander with GtkLabel
expander = Gtk.TreeExpander()
expander.set_halign(Gtk.Align.FILL)
expander.set_valign(Gtk.Align.CENTER)
list_item.set_child(expander)
label = Gtk.Label(label="")
label.set_halign(Gtk.Align.FILL)
label.set_valign(Gtk.Align.CENTER)
expander.set_child(label)
else:
# Col2 and Col3: AdwWrapBox
wrap_box = Adw.WrapBox()
wrap_box.set_halign(Gtk.Align.FILL)
wrap_box.set_valign(Gtk.Align.CENTER)
wrap_box.set_child_spacing(8)
wrap_box.set_line_spacing(8)
list_item.set_child(wrap_box)
def _on_factory_bind(self, factory, list_item, col_index):
child = list_item.get_child()
row_item = list_item.get_item()
if col_index == 0:
# Col1: Set GtkTreeExpander with GtkLabel
label = child.get_child()
label.set_label(row_item.label)
return
# Col2 and Col3: AdwWrapBox with labels
my_list = row_item.list1 if col_index == 1 else row_item.list2
for s in my_list:
label = Gtk.Label(label=row_item.label)
label.set_label(s.get_string())
label.add_css_class("card")
child.append(label)
app = ColumnViewApp()
sys.exit(app.run(None))
I experimented with setting properties, such as h/v align, but haven’t found the right combination yet. Many thanks for any help.
