When a application window is loaded at all?

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.

It’s more complex for ColumsViews, they’re built dynamically on the fly depending on what is shown, so relying in the parent window’s state (show/realize…) is not reliable, the window will be ready before.

I think what you need is the “scroll_to” API:

Side notes:

  • better use self.present() instead of self.set_visible(True)
  • don’t call self.realize() manually , it’s done internally

This topic was automatically closed 45 days after the last reply. New replies are no longer allowed.