I have a small python column-view application, which will be filled with the values from 1 to 199.
#!/usr/bin/env python3
# Source = https://discourse.gnome.org/t/how-to-select-item-in-columnview/14653
import gi
import socket
gi.require_version("Adw", "1")
gi.require_version("Gtk", "4.0")
from gi.repository import Adw, Gio, GObject, Gtk, GLib # noqa
class Value(GObject.Object):
__gtype_name__ = 'Value'
def __init__(self, Value_name):
super().__init__()
self._Value_name = Value_name
@GObject.Property(type=str)
def Value_name(self):
return self._Value_name
def __repr__(self):
return f"Value(Value_name={self.Value_name})" # noqa
class ExampleWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super().__init__(application=app, title="ColumnView_Values", default_width=300)
# Model
self.model = Gio.ListStore(item_type=Value)
for entry in range(1, 200):
self.model.append(Value(Value_name=entry))
# Factory
factory = Gtk.SignalListItemFactory()
factory.connect("setup", self._on_factory_setup)
factory.connect("bind", self._on_factory_bind, "Value_name")
factory.connect("unbind", self._on_factory_unbind, "Value_name")
factory.connect("teardown", self._on_factory_teardown)
# SingleSelection
self.cv_selected = Gtk.SingleSelection(model=self.model)
self.cv_selected.connect("selection-changed", self._on_selection_change)
self.cv_selected.set_autoselect(True)
self.cv_selected.set_can_unselect(False)
# View
self.cv = Gtk.ColumnView(model=self.cv_selected)
self.cv.connect("activate", self._on_activate_cv)
self.cv.set_property('vexpand', True)
self.cv.set_single_click_activate(False)
# Column
col1 = Gtk.ColumnViewColumn(title="Value", factory=factory)
col1.props.expand = True
self.cv.append_column(col1)
# ScrolledWindow
self.scrollable_window = Gtk.ScrolledWindow()
self.scrollable_window.set_child(self.cv)
self.scrollable_window.set_has_frame(True)
self.scrollable_window.set_max_content_width(300)
self.scrollable_window.set_min_content_width(200)
self.scrollable_window.set_max_content_height(1000)
self.scrollable_window.set_min_content_height(800)
self.scrollable_window.set_overlay_scrolling(False)
row_factor = 35
page_increment_ = 603.0
self.adj_v = Gtk.Adjustment.new(value=0.0, lower=0.0, upper=(self.model.get_n_items() * row_factor), step_increment=(self.scrollable_window.get_min_content_height() - 30) / 10, page_increment=page_increment_, page_size=(self.scrollable_window.get_min_content_height() - 30))
self.adj_v = self.scrollable_window.set_vadjustment(self.adj_v)
# Button
self.button = Gtk.Button(label='Jump to 33')
self.button.connect('clicked', self._onclicked_button)
# Box
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
box.append(self.button)
box.append(self.scrollable_window)
# Window
self.set_child(box)
self.cv_selected.set_selected(29)
self.connect('show', self.visibile_window)
# self.connect('map', self.visibile_window)
# self.connect('realize', self.visibile_window)
# Try to load the window
self.set_visible(True)
self.realize()
self.cv_selected.set_selected(30)
def visibile_window(self, widget):
print('---visibile_window---')
print('Select item 32')
self.cv_selected.set_selected(31)
def _onclicked_button(self, button):
print('---_onclicked_button---')
print('Select item 33')
self.cv_selected.set_selected(32)
def _on_selection_change(self, selection_model, position, n_items):
print('---_on_selection_change---')
item_selected = self.cv_selected.get_selected()
item_all = self.model.get_n_items()
print('Element %s from %s selected' % (item_selected, item_all))
# Values
self.adj_v = self.scrollable_window.get_vadjustment()
item_all_upper = self.adj_v.get_upper() - self.adj_v.get_page_size()
item_step = self.adj_v.get_step_increment()
item_page_size = self.adj_v.get_page_size()
# Take widget-size to define the factor
item_visible = round(self.adj_v.get_page_size() / 35)
item_visible_factor = round(item_visible / 2 - 1)
# Calculate the scroll-value
if item_selected < item_visible_factor:
item_selected_value = 0
elif item_selected > item_all - item_visible_factor:
item_selected_value = item_all_upper
else:
item_selected_value = (item_selected - item_visible_factor) * 35
# Set the scroll value
self.adj_v.set_value(item_selected_value)
# Print scroll values
print(f'Debugging: {self.adj_v.get_value()=} {self.adj_v.get_lower()=} {self.adj_v.get_upper()=} {self.adj_v.get_step_increment()=} {self.adj_v.get_page_increment()=} {self.adj_v.get_page_size()=}')
# Print Windows sizes and status
print('Window-size =',self.get_width(),'x',self.get_height(),'| mapped =',self.get_mapped(),'| get realized =',self.get_realized(),'| is visible =',self.is_visible())
def _on_activate_cv(self, position, user_data):
print('_on_activate_cv')
print(f'Selected = {self.model.get_item(user_data).Value_name}')
def _on_factory_setup(self, factory, list_item):
cell = Gtk.Inscription()
cell._binding = None
list_item.set_child(cell)
def _on_factory_bind(self, factory, list_item, what):
cell = list_item.get_child()
Value = list_item.get_item()
cell._binding = Value.bind_property(what, cell, "text", GObject.BindingFlags.SYNC_CREATE)
def _on_factory_unbind(self, factory, list_item, what):
cell = list_item.get_child()
if cell._binding:
cell._binding.unbind()
cell._binding = None
def _on_factory_teardown(self, factory, list_item):
cell = list_item.get_child()
cell._binding = None
class ExampleApp(Adw.Application):
def __init__(self):
super().__init__()
self.window = None
def do_activate(self):
if not self.window: # allow just one instance
self.window = ExampleWindow(self)
self.window.present()
system_name = socket.gethostname()
app = ExampleApp()
app.run([])
I want to jump to the 29,30,31,32 or 33 value at the start.
At start I got these logging result:
--_on_selection_change---
Element 29 from 199 selected
Debugging: self.adj_v.get_value()=0.0 self.adj_v.get_lower()=0.0 self.adj_v.get_upper()=0.0 self.adj_v.get_step_increment()=0.0 self.adj_v.get_page_increment()=0.0 self.adj_v.get_page_size()=0.0
Window-size = 0 x 0 | mapped = False | get realized = False | is visible = False
---visibile_window---
Select item 32
---_on_selection_change---
Element 31 from 199 selected
Debugging: self.adj_v.get_value()=0.0 self.adj_v.get_lower()=0.0 self.adj_v.get_upper()=0.0 self.adj_v.get_step_increment()=0.0 self.adj_v.get_page_increment()=0.0 self.adj_v.get_page_size()=0.0
Window-size = 0 x 0 | mapped = True | get realized = True | is visible = True
---_on_selection_change---
Element 30 from 199 selected
Debugging: self.adj_v.get_value()=0.0 self.adj_v.get_lower()=0.0 self.adj_v.get_upper()=0.0 self.adj_v.get_step_increment()=0.0 self.adj_v.get_page_increment()=0.0 self.adj_v.get_page_size()=0.0
Window-size = 0 x 0 | mapped = True | get realized = True | is visible = True
When I click at a entry or the “Jump to 33” button, I got these results:
---_on_selection_change---
Element 2 from 199 selected
Debugging: self.adj_v.get_value()=0.0 self.adj_v.get_lower()=0.0 self.adj_v.get_upper()=7164.0 self.adj_v.get_step_increment()=77.0 self.adj_v.get_page_increment()=693.0 self.adj_v.get_page_size()=770.0
Window-size = 300 x 848 | mapped = True | get realized = True | is visible = True
---_onclicked_button---
Select item 33
---_on_selection_change---
Element 32 from 199 selected
Debugging: self.adj_v.get_value()=770.0 self.adj_v.get_lower()=0.0 self.adj_v.get_upper()=7164.0 self.adj_v.get_step_increment()=77.0 self.adj_v.get_page_increment()=693.0 self.adj_v.get_page_size()=770.0
Window-size = 300 x 848 | mapped = True | get realized = True | is visible = True
In the starting phase the “Window-size = 0 x 0” identifies that the window is still not loaded.
When I click at one entry or at the button, the “Window-size = 300 x 848” seems to be loaded now.
What kind of “signal” (Gtk.Widget) I should use to be sure the window is loaded? I try with “show”, “map” and “realize”…
It would be really nice if someone can give me a hint. Thanks.