PyGObject (GTK4) - 如何在项目列表更改时自动更新下拉列表?

问题描述 投票:0回答:1

我正在尝试在 GTK4 应用程序中创建一个下拉菜单,但我一直在思考如何使下拉菜单工作。

我发现并一直在使用这个 python GTK4 Dropdown 示例,它最初可以工作,但是当列表存储使用的

dict
更新时,下拉列表不会改变。

由于我不确定自己是否正确地解决了问题,因此我将呈现实际问题的简化版本。

@dataclass
class Coffee:
    """
    Represents a coffee entry in the db
    """
    coffee_id:int
    name:str
    description:str
    # date/time added (as unix time)
    date_added:datetime

我的应用程序窗口使用

self.coffees:list[Coffees]
存储“咖啡列表”,并使用
self.curr_coffee:Coffee
跟踪“当前活动”咖啡。该列表由应用程序的其他部分更新。

我的目标是由此列表中的

Gtk.Dropdown
中的
name
组成的
Coffee
,并且当用户进行选择时
self.curr_coffee
会更新。

我正在使用 简化的下拉示例,并进行了少量修改。

然后我创建一个

dict
,
self.coffees_dict:dict
传递到下拉列表。该字典会在
self.coffees
的每次更新时更新。 (是的,我知道这不太好;我只是想让它发挥作用)

for c in self.coffees:
    self.coffees_dict[c.coffee_id] = c.name

然后使用示例类创建一个下拉列表,如下所示:

self.coffee_setting_dropdown = DropDown(data=self.appstate.localDB.coffees_dict,
                                 itemSelectNotifyMethod=self._on_coffee_changed_notify)
self.dropDownBox = self.coffee_setting_dropdown.getDropDownElementWithBoxAndLabel("Coffee:")

但是,尽管更新了

coffee_dict
,数据库的新添加内容并未反映在下拉列表中。必须有一种更简单的方法来做到这一点 - 如何从咖啡名称创建 GTK4 下拉列表并在添加新名称时更新它?


下面是基本情况的一个工作单文件示例,改编自上面链接的示例。

import gi
from dataclasses import dataclass


gi.require_version("Adw", "1")
gi.require_version("Gtk", "4.0")

from gi.repository import Adw, Gio, GObject, Gtk


@dataclass
class Coffee:
    """
    Represents a coffee entry in the db
    """
    coffee_id: int
    name: str
    description: str


# used to generate example list[Coffee]
EXAMPLE_COFFEES_LIST = [
    "Espresso",
    "Americano",
    "Latte",
    "Cappuccino",
    "Mocha",
    "Macchiato",
    "Flat White",
    "Affogato",
    "Cold Brew",
    "Nitro Coffee",
    "Turkish Coffee",
    "Irish Coffee",
    "Ristretto",
    "Doppio",
    "Café au Lait",
    "Vienna Coffee",
    "Café con Leche",
    "Iced Coffee",
    "Breve",
    "Coffee Milk",
]


# DropDown classes are from
# https://github.com/ksaadDE/GTK4PythonExamples/blob/main/DropDownSimplified.md
class DataDropDownChild(GObject.Object):
    __gtype_name__ = "DataDropDownChild"

    def __init__(self, key, value):
        super().__init__()

        self.k = key
        self.v = value

    @GObject.Property
    def key(self):
        return self.k

    @GObject.Property
    def value(self):
        return self.v

    def getKey(
        self,
    ):
        return self.k

    def getValue(
        self,
    ):
        return self.v


class DropDown:
    def __init__(
        self,
        data=[],
        factoryBindSetupMethod=None,
        factoryBindMethod=None,
        itemSelectNotifyMethod=None,
    ):
        self.box = None
        self.data = data
        self.model = Gio.ListStore(item_type=DataDropDownChild)
        for k in data.keys():
            self.model.append(DataDropDownChild(key=k, value=data[k]))

        # Set up the factory
        self.factory = Gtk.SignalListItemFactory()
        if factoryBindSetupMethod is None:
            self.factory.connect("setup", self._on_factory_setup)
        else:
            self.factory.connect("setup", factoryBindSetupMethod)

        if factoryBindMethod is None:
            self.factory.connect("bind", self._on_factory_bind)
        else:
            self.factory.connect("bind", factoryBindMethod)

        self.dd = Gtk.DropDown(model=self.model, factory=self.factory, hexpand=True)

        if itemSelectNotifyMethod is None:
            self.dd.connect("notify::selected-item", self._on_selected_item_notify)
        else:
            self.dd.connect("notify::selected-item", itemSelectNotifyMethod)

    def getDropDownElement(
        self,
    ):
        return self.dd

    def getDropDownElementWithBox(self, labelText="Select Object:"):
        self.box = Gtk.Box(spacing=12, hexpand=True, vexpand=True)
        self.box.props.margin_start = 12
        self.box.props.margin_end = 12
        # self.box.props.margin_top = 6
        # self.box.props.margin_bottom = 6
        # self.box.append(Gtk.Label(label=labelText))
        self.box.append(self.getDropDownElement())
        self.box.set_vexpand(False)
        return self.box

    # Set up the child of the list item; this can be an arbitrarily
    # complex widget but we use a simple label now
    def _on_factory_setup(self, factory, list_item):
        label = Gtk.Label()
        list_item.set_child(label)

    # Bind the item in the model to the row widget; again, since
    # the object in the model can contain multiple properties, and
    # the list item can contain any arbitrarily complex widget, we
    # can have very complex rows instead of the simple cell renderer
    # layouts in GtkComboBox
    def _on_factory_bind(self, factory, list_item):
        label = list_item.get_child()
        item = list_item.get_item()
        label.set_text(str(item.v))

    # The notify signal is fired when the selection changes
    def _on_selected_item_notify(self, dropdown, _):
        item = dropdown.get_selected_item()
        print(item.getKey(), item.getValue())

    def update_liststore(self, data):
        # naive (and rather stupid) way of updating items in dropdown. will not scale
        self.data = data
        self.model = Gio.ListStore(item_type=DataDropDownChild)
        for k in data.keys():
            self.model.append(DataDropDownChild(key=k, value=data[k]))


class ExampleWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(application=app, title="DropDown")


        # generate example data
        self.coffees: list[Coffee] = []
        for idx, item in enumerate(EXAMPLE_COFFEES_LIST):
            self.coffees.append(Coffee(idx, item, ""))

        self.coffees_dict: dict = {}
        for c in self.coffees:
            self.coffees_dict[c.coffee_id] = c.name

        # not used in this example, here for reference
        self.curr_coffee:Coffee = None

        self.dd = DropDown(
            data=self.coffees_dict, itemSelectNotifyMethod=self.onItemChangeNotify
        )
        self.dropDownBox = self.dd.getDropDownElementWithBox(labelText="Coffees:")

        self.set_child(self.dropDownBox)


    def onItemChangeNotify(self, dropdown, _):
        item = dropdown.get_selected_item()
        print("22:", item.getKey(), item.getValue())

class ExampleApp(Adw.Application):
    def __init__(self):
        super().__init__()
        self.window = None

    def do_activate(self):
        if self.window is None:
            self.window = ExampleWindow(self)
        self.window.present()
app = ExampleApp()
app.run([])

python gtk pygobject
1个回答
0
投票

所以你有一个下拉框来设置咖啡,并且你希望它在新咖啡添加到字典中时更新?

© www.soinside.com 2019 - 2024. All rights reserved.