Help migrating to GTK4 ColumnView

I have a new GTK program in Rust. For my initial attempt I used a fairly crude implementation of a TreeView and a ListStore for displaying a multicolumn filtered list of around 35,000 rows, and doing the filtering myself incode and rebuilding a new ListStore each time the filter parameters changed.

I am trying to migrate from the Treeview to a ColumnView with my own model implementation and a GTK CustomFilter. This is all working well except for two problems.

  • The first is the selection related: I have a popover menu that is displayed when right clicking on a row. In the TreeView implementation the Right Click caused the row that received the click to be selected, so the menu actions could act upon the selection. This doesn’t happen when using the ColumnView, which seems inconsistent, but the real issue is I can find no way to identify the clicked on row, even though I have the x,y coordinate of the click.

( The second is slightly more trivial, but I can find no way to get the ColumnView to use the .data-table style class, to give a more compact list, similar to the TreeView’s presentation.) - Solved this bit by adding

       <style>
         <class name="search-box"/>
       </style>

to the xml definition of the CoumnView widget. Obvious once you work it out :).

Hi,

For the 1st point, here is what I do for a ListView in Python:

def on_event_click(self, event, n, x, y):
    if n == 1:   # FIXME: event.get_current_event().triggers_context_menu() currently doesn't work in python
        # If right click on valid row, then show the popup menu
        listview = event.get_widget()
        if w := listview.pick(x, y, Gtk.PickFlags.DEFAULT):
            if tree_exp := w.get_ancestor(Gtk.TreeExpander.__gtype__):
                px, py = listview.translate_coordinates(self.manager, x, y)
                rect = Gdk.Rectangle()
                rect.x, rect.y, rect.width, rect.height = px, py, 1, 1
                self.set_pointing_to(rect)
                self.popup()
                self.manager.set_context_data(tree_exp)
            else:
                listview.get_model().unselect_all()
            event.set_state(Gtk.EventSequenceState.CLAIMED)

Note: self.manager is my custom widget with an overriden size_allocate method that I use to present all my popovers.

I do approx the same to show the popup. That is not my problem. The issue I have is I cannot determine which row the is actually being clicked on.

On my side I packed Gtk.TreeExpanders in my ListView.
I used pick() and get_parent() in my example above to get it (–> variable tree_exp)

Then I can use tree_exp.get_item() to get the row item.

I never used ColumnView but I suppose it should be similar. In your factory, at some point, there should be a link made between the row and the widget. Make sure to use a widget like GtkTreeExpander that can keep a reference to the row.

This is what worked for me for a double-click “activation” (I use my list as a document selector, double-click opening the document) in Ruby:

@column_view.signal_connect "activate" do |column_view, item_idx| # <== this is Ruby-speak for a callback, with two positional parameters that we named
  # first parameter (column_view) is the ColumnView itself
  # second parameter (item_idx) is the index of the item in your GListModel

  #  ColumnView wraps a SelectionModel:
  selection_model = column_view.model

  # the SelectionModel wraps your GListModel
  g_list_model = selection_model.model

  # the GListModel has your clicked item at the specified index
  your_item = g_list_model.get_item(item_idx)

  # enjoy your item!
end

@HuBandiT , That also works for me for a double-click activate signal. But for a right click Gesture I can’t find an equivalent.

Maybe you can use closure_local! to make the Gtk::ColumnViewCell available in the signal callback, that you connect when you create its widget.

Something in the direction of this maybe?:

gesture.connect_closure(
    "pressed", false,
    closure_local!(@watch cell => |_, _, _, _| {
        println!("do whatever");
    }));

Might not be quite right as I haven’t written much rust/gtk-rs, so I tried to adapt some of the examples from here:

The code to get the gesture and show the popup is straightforward enough, see below. But knowing which underlying row in the ListModel was clicked on seems unobainable.

            let gesture = gtk::GestureClick::new();
            gesture.set_button(3);
            gesture.connect_released(clone!(@weak self as view => move | gesture, _n, x, y| {
                gesture.set_state(gtk::EventSequenceState::Claimed);
                if let Some(popover) = view.popover.borrow().as_ref() {
                        popover.set_pointing_to(Some(&Rectangle::new(x as i32, y as i32, 1, 1)));
                        popover.popup();
                };
            }));
            self.airport_list.add_controller(gesture);

GtkNoSelection does, somehow, do a “hover” effect over the items when I move my mouse cursor over them. So the information is in there somewhere.

I suggest two courses of action:

  • dive into the code and try to find out
  • publicize your specific question more clearly: rename this topic to be (or create a new topic with a title) more descriptive title, asking specifically the question you are having difficulty with, to recruit people with knowledge: if it sounds specific enough to suggest it is quick to answer, you have a higher chance of attracting someone with knowledge.

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