Is it possible to use radio buttons in a Gtk.ColumnView?

I’m trying to migrate a small GUI I wrote years ago in python, from using Gtk.TreeView to Gtk.ColumnView. I was able to rewrite it to make use of .ui Builder files, but now I’m struggling with Gtk.BuilderListItemFactory.

I have a builder file like this:

            <child>
              <object class="GtkColumnViewColumn" id="column_next">
                <property name="resizable">True</property>
                <property name="title">Boot Next</property>
                <property name="factory">
                  <object class="GtkBuilderListItemFactory">
                    <property name="bytes">
<![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <template class="GtkListItem">
    <property name="child">
      <object class="GtkCheckButton">
        <property name="group">next_group</property>
        <property name="css-classes">radio</property>
        <binding name="active">
          <lookup name="next" type="EfibootRowModel">
            <lookup name="item">GtkListItem</lookup>
          </lookup>
        </binding>
      </object>
    </property>
  </template>
</interface>
]]>
                    </property>
                  </object>
                </property>
              </object>
            </child>
          </object>
        </child>

The problem here is the group property of the Gtk.CheckButton. I tried to add an invisible button in my window template, but then Gtk complains with Error building template for list item: .:0:0 Object with ID next_group not found. On the other hand adding it inside the XML of the factory would be useless, because each button would have a different group…

Maybe I could iterate with code on each row and set each CheckButton’s group to the first row’s one, but I’m not sure about that.

I’m running out of ideas…

You could try specifying the group this other way:

Note that the same effect can be achieved via the GtkActionable API, by using the same action with parameter type and state type ‘s’ for all buttons in the group, and giving each button its own target value.

1 Like

I’m afraid I don’t understand that documentation…

This is what I tried: I added <property name="action-name">next_boot</property> to each GtkCheckButton . Then in my code I added an action:

variant = GLib.Variant.new_string("0000")
self.next_boot_action = Gio.SimpleAction.new_stateful("next_boot", variant.get_type(), variant)
self.next_boot_action.connect("change-state", print)
self.add_action(self.next_boot_action)

but it doesn’t work. What am I missing?

What is self? An Application or some other action map/group implementor? If it’s a map, your property will need the name of the map (app., win., whatever) added to it. But probably you should instead add an action group to the widget - so that e.g. if you end up having multiple instances, they won’t conflict with each other’s (or other sources’) app-level actions - using gtk_widget_insert_action_group(). Either way, I don’t see how your widget has enough info to activate whatever action you’re adding.

Generally, see if this documentation helps: Gtk – 4.0: Overview of actions in GTK, and hopefully that’ll give you enough to get it working. Let us know if you do! :slight_smile:

self is a Gtk.ApplicationWindow, should I add it to the radio buttons? I’ve never used actions in Gtk, I think I understood what an action is, but I don’t get how to use it.

I don’t see how your widget has enough info to activate whatever action you’re adding.

I told the widget it should connect to the next_boot action, didn’t I? I also set the action-state property like this: <property name="action-target">"TEST"</property>. When that action is activated it’s state should change to “TEST”, right?

Yes, but you didn’t specify where to look for the action. As @dboles said, you should change the value of the “action-name” property to “win.next_boot”.

2 Likes

Thanks, that was it.

Now I have to find a way to set a different action-target for each button. Is it possible to do this in Gtk.Builder files? I made an attempt with this:

<binding name="action-target">
  <lookup name="num" type="EfibootRowModel">
    <lookup name="item">GtkListItem</lookup>
  </lookup>
</binding>

and that gives me this warning: unable to set property 'action-target' of type 'GVariant' from value of type 'gchararray'.

I tried with a different expression:

<binding name="action-target">
  <closure type="GVariant" function="g_variant_new">
    <constant type="gchararray">s</constant>
    <lookup name="num" type="EfibootRowModel">
      <lookup name="item">GtkListItem</lookup>
    </lookup>
  </closure>
</binding>

But unfortunately it looks like I’m out of luck, because that gives another error:

Traceback (most recent call last):
  File "/nix/store/49dqxcpncsy2hd8xkj7xwbi2mbc7g4kj-python3.10-pygobject-3.44.1/lib/python3.10/site-packages/gi/_gtktemplate.py", line 64, in do_create_closure
    if func_name not in current_object.__gtktemplate_methods__:
AttributeError: 'ListItem' object has no attribute '__gtktemplate_methods__'

Radio buttons and treeviews were definitely easier to manage in GTK3.

I’ve now tried using actions instead of button groups and been disappointed, so if you do figure out how to make it work from .ui files, watch out for that caveat about keynav not working the same way. :frowning:

[edit] I presume we could subclass the widget containing the buttons, and override gtk_widget_move_focus() to imitate the behaviour of grouped buttons, but I just don’t think I can be bothered to be honest…

1 Like

In the end I was able to implement all the behaviors I wanted with a Gtk.SignalListItemFactory (see New implementation for next boot and activate · Elinvention/efiboots@85ab055 · GitHub).

1 Like

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