I'm trying to create a GtkDropDown with a searchbar to sort through a list of timezones.
The Gtk4 documentation states
GtkDropDown knows how to obtain strings from the items in a GtkStringList
which is the model I originally tried to use.
It also says in the set_enable_search()
method description
Note that GtkDropDown:expression must be set for search to work.
I've looked on GitLab and GitHub for other projects and how they are doing it, but all the methods I found don't seem to work for me, throwing errors in python or straight up ignoring the text input.
After multiple attempts, here is the snippet of the last one which throws a ValueError: row sequence has the incorrect number of elements
on model.append(Timezone(_(tz)))
# unrelated code above
model = Gtk.ListStore(GObject.GType(Timezone))
for tz in pytz.common_timezones:
model.append(Timezone(_(tz)))
dropdown = Gtk.DropDown()
dropdown.set_model(model)
dropdown.set_enable_search(True)
dropdown.set_expression(Gtk.PropertyExpression(GObject.GType(Timezone), None, "name"))
self.action_row.add_suffix(dropdown) # parent defined above
# unrelated code below
The class Timezone
:
from gi.repository import GObject
class Timezone(GObject.GObject):
def __init__(self, name):
__gtype_name__ = "Timezone"
self.name = name
def __len__(self):
return len(self.name)
def __str__(self):
return self.name
I'm stuck, what am I missing to make it work?
Here is an example of what I believe you are trying to achieve:
#!/usr/bin/env python3
import gi
import pytz
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk # noqa: E402
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
drop_down = self.create_drop_down()
self.set_child(drop_down)
def create_drop_down(self):
string_list_items = "\n".ljust(11).join(
[f"<item>{time_zone}</item>" for time_zone in pytz.common_timezones]
)
drop_down_ui_string = f"""<interface>
<object class="GtkDropDown" id="drop-down">
<property name="model">
<object class="GtkStringList" id="string-list">
<items>
{string_list_items}
</items>
</object>
</property>
<property name="enable-search">true</property>
<property name="expression">
<lookup type="GtkStringObject" name="string"></lookup>
</property>
</object>
</interface>"""
builder = Gtk.Builder.new_from_string(drop_down_ui_string, -1)
drop_down = builder.get_object("drop-down")
return drop_down
class Application(Gtk.Application):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.connect("activate", self.on_activate)
def on_activate(self, app):
self.win = ApplicationWindow(application=app)
self.win.show()
app = Application()
app.run()
A few comments:
PyGObject
does not support GtkExpression
. The only way to currently make the search feature work in a GtkDropDown
is to use a GtkBuilder
.GtkDropDown
in the form of GListModel
. This means that you cannot set the model using a GtkListStore
. Indeed, the documentation explains that a GtkListStore
object is a list model for use with a GtkTreeView
widget, which is different from a GtkDropDown
.GtkListStore
, then you can do so in the following way:import gi
import pytz
gi.require_version("Gtk", "4.0")
from gi.repository import GObject, Gtk # noqa: E402
class Timezone(GObject.GObject):
__gtype_name__ = "Timezone"
def __init__(self, name, *args, **kwargs):
super().__init__(*args, **kwargs)
self.name = name
def __len__(self):
return len(self.name)
def __str__(self):
return self.name
model = Gtk.ListStore.new([GObject.GType(Timezone)])
for time_zone in pytz.common_timezones:
model.append([Timezone(time_zone)])