使用虚拟事件的翻译感知小部件

Translation aware widgets using virtual events

我有一个多语言 Tkinter 应用程序。由于 Tkinter 本身不公开 Tk 的底层 msgcat 功能,因此我使用 ttkbootstrap。截至目前,我的翻译工作正常,当通过界面更改语言时,我会销毁并重建所有小部件。

虚拟事件是 Tkinter 的一个强大功能,它允许我 structure my application in an OO way 同时使用控制变量和虚拟事件的组合进行小部件间通信/消息传递。

我试图通过这段代码实现一个翻译感知小部件,但我现在知道,虚拟事件需要小部件焦点,但事实并非如此:

from ttkbootstrap import ttk
from ttkbootstrap.localization import MessageCatalog


def _tr(t: str) -> str:
    return MessageCatalog.translate(t)


class TrButton(ttk.Button):
    def __init__(self, master=None, text: str = "", **kwargs):
        super().__init__(master=master, text=_tr(text), **kwargs)
        self.bind(
            "<<LanguageChanged>>", lambda *_: self.configure(text=_tr(self["text"]))
        )

现在,重建所有小部件对我的应用程序来说并不是一项非常昂贵的任务,但我想知道是否有更好的方法?一种拥有真正翻译感知小部件的方法?

您写道虚拟事件需要小部件焦点,但事实并非如此。您是否在 Internet 上找到一些说明这是真的文档?

最简单的解决方案是让您的 class 跟踪自己的实例。然后您可以遍历所有实例以生成虚拟事件。

看起来像这样:

class TrButton(ttk.Button):
    instances = []
    def __init__(self, master=None, text: str = "", **kwargs):
        TrButton.instances.append(weakref.proxy(self))
        super().__init__(master=master, text=_tr(text), **kwargs)
        self.bind(
            "<<LanguageChanged>>", lambda *_: self.configure(text=_tr(self["text"]))
        )

    @classmethod
    def language_changed(self):
        for widget in TrButton.instances:
            if widget.winfo_exists():
                widget.event_generate("<<LanguageChanged>>")

只要语言发生变化,您就可以调用 TrButton.language_changed() 将事件发送到 class 的每个实例。

这段代码并不完美,应该有一种机制可以从实例列表中删除已删除的小部件。但是,它说明了如何遍历小部件列表以向它们发送虚拟事件,而无需它们具有焦点。