在 Python 中构建 Gtk3 应用程序的正确方法

Posted

技术标签:

【中文标题】在 Python 中构建 Gtk3 应用程序的正确方法【英文标题】:Proper way of building Gtk3 applications in Python 【发布时间】:2014-01-03 16:09:30 【问题描述】:

我刚刚开始学习如何在 Python 中创建 GUI 应用程序。我决定使用 Gtk 版本 3。 根据http://python-gtk-3-tutorial.readthedocs.org/ 上的(官方?)教程,构建 hello world 应用程序的正确方法是:

from gi.repository import Gtk

class MyWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.set_default_size(200, 100)
        self.connect('destroy', Gtk.main_quit)
        self.show_all()

MyWindow()
Gtk.main()

在其他教程 (http://www.micahcarrick.com/gtk3-python-hello-world.html) 中,我发现完全不同的方法是:

from gi.repository import Gtk, Gio

class HelloWorldApp(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self, application_id="apps.test.helloworld",
                                 flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.connect("activate", self.on_activate)

    def on_activate(self, data=None):
        window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL)
        window.set_title("Gtk3 Python Example")
        window.set_border_width(24)
        label = Gtk.Label("Hello World!")
        window.add(label)
        window.show_all()
        self.add_window(window)

if __name__ == "__main__":
    app = HelloWorldApp()
    app.run(None)

在这个领域有经验的人能告诉我这些天我应该以什么方式在 python 中编写 Gtk 3 应用程序?我已经熟悉编写 GUI(在 Java 的 Swing 中花了几个月的时间),因此您可以继续使用事件、回调等术语。

【问题讨论】:

【参考方案1】:

选择使用 GtkApplication 还是仅使用 GtkWindow 来编写新程序取决于您需要的功能,在某种程度上还取决于目标受众。

对于大多数情况,尤其是当您仍在学习该工具包时,我倾向于同意 valmynd 的观点,即 GtkApplication 过于复杂。 GtkApplication 提供了许多您在小型应用程序中可能不需要或不需要的额外功能。

对于更大、更完整的应用程序,我同意 Dragnucs 的观点,第二种方法更出色,可以更好地集成到桌面环境中。来自GNOME Goal: Port to GtkApplication(另请参阅GtkApplication 文档):

移植您的应用程序以使用 GtkApplication 有很多好处: GtkApplication 处理 GTK+ 初始化、应用程序唯一性、会话管理,通过导出操作和菜单提供一些基本的脚本功能和桌面 shell 集成,并管理生命周期自动与应用程序生命周期相关联的***窗口列表。

但是我不同意 Dragnucs 关于为什么在教程中引入 GtkWindow 方法。我倾向于认为带有很少样板的简单示例更适合教程入门部分(但是,我确实认为需要更新阅读文档教程以至少包含一些提及GtkApplication)。

在我编写的应用程序中,我倾向于将 GtkApplication 和 GtkWindow 子类化,或者对于单窗口 quick-and-nasty 应用程序,只将 GtkWindow 子类化。您的决定将取决于您的应用需求。

技术差异:这两个示例的实现方式之间还有一个重要的技术差异。仅带有 GtkWindow 的示例为程序的每个实例创建了一个新的 Gtk 主循环。带有 GtkApplication 的示例创建了一个附加到第一个实例的主循环,随后对run(None) 的每次调用都将请求原始实例创建一个新窗口(然后新实例将退出)。尝试打开两个终端并在每个窗口中运行您的应用程序,注意一个终端将等到所有窗口都关闭后再变得敏感。您可以使用G_APPLICATION_NON_UNIQUE 而不是G_APPLICATION_FLAGS_NONE 来更改此行为。

【讨论】:

【参考方案2】:

第二个代码示例对我来说看起来不必要的复杂,第一个看起来非常好。第二个教程的作者提供了另一个更简单示例的链接 (Source):

from gi.repository import Gtk

window = Gtk.Window(title="Hello World")
window.connect("destroy", lambda w: Gtk.main_quit())
window.add(Gtk.Label("Hello World!"))
window.show_all()

Gtk.main()

这两种方法都没有错。您可以使用所有默认小部件,而不是继承任何东西,就像上面的示例一样。或者您可以将某些小部件子类化,主要是为了让您的代码具有良好的结构并最终拥有可重用的自定义/修改小部件。这完全取决于你。

这同样适用于 Qt 和许多其他 GUI 框架,顺便说一句。

【讨论】:

我在这里有点晚了,但对于任何发现这个的人,我认为最大的区别在于如果你正在制作一个具有多个窗口的应用程序,Gtk.Window 似乎打开了一个新的每次调用一个窗口,这意味着您为同一个应用程序打开了多个窗口,但是使用Gtk.Application 您可以在同一个窗口中打开不同的程序。 Window 可能有办法做到这一点,但我还没有看到。使用应用程序,您只需致电ApplicationWindow【参考方案3】:

第二种方法更好。它使应用程序更加集成到桌面中,并提供更多关于它做什么或打算做什么的信息。它还为您提供了更多用于您的应用程序的工具。

我认为第一种方法不是最新的。第二种确实是首选方式。

你可以看到应用程序Gnome-music实际上是在使用second approach和Gtk.Application用法。所有官方 Gnome 应用程序都在使用 Gtk.Application,所有 Gtk 应用程序也应该使用它。

【讨论】:

以上是关于在 Python 中构建 Gtk3 应用程序的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

无法将 CSS 应用于 GtkEntry 小部件(GTK3 / gi / Python)不工作

如何为 GTK3 配置 VSCode 以进行智能感知/构建/调试和 g++

如何在 Python 和 Gtk3 中使用 Pango.AttrType.FOREGROUND?

windows上pygtk 2中的gtkSwitch

如何在 GTK3 和 Python 2.7 中的图像对象上创建“点击事件”

Gtk.CssProvider 在 Gtk3 Python3 中不起作用?