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

18

我刚刚开始学习如何使用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中花了几个月时间),所以你可以继续讲解事件、回调等术语。

3个回答

15

选择使用GtkApplication或仅使用GtkWindow编写新程序取决于您需要的功能,以及在某种程度上取决于受众。

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

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

将您的应用程序移植到使用GtkApplication具有相当好的优点: GtkApplication处理GTK+初始化、应用程序唯一性、会话管理,通过导出操作和菜单提供一些基本的脚本化和桌面外壳集成,并管理一个顶级窗口列表,其生命周期自动绑定到您的应用程序的生命周期。

然而,我不同意Dragnucs所说的为什么在教程中引入了GtkWindow方法。我倾向于认为,在教程的“入门”部分中,简单示例与非常少的样板更为合适(但是,我认为需要更新阅读文档教程,包括至少提到GtkApplication)。
在我编写的应用程序中,我倾向于同时对GtkApplication和GtkWindow进行子类化,或者对于单个窗口的“快速且肮脏”的应用程序,只对GtkWindow进行子类化。您的决定将取决于应用程序的需求。
技术差异:这两个示例之间还存在一个重要的技术差异。仅具有GtkWindow的示例为程序的每个实例创建一个新的Gtk主循环。具有GtkApplication的示例创建一个附加到第一个实例的单个主循环,并且每个后续对run(None)的调用都将请求原始实例创建一个新窗口(新实例随即退出)。尝试打开两个终端并在每个窗口中运行应用程序,注意一个终端将等待所有窗口关闭后才变得敏感。您可以通过使用G_APPLICATION_NON_UNIQUE而不是G_APPLICATION_FLAGS_NONE来更改此行为。

6
第二个代码示例对我来说似乎过于复杂,第一个看起来很好。那篇第二个教程的作者提供了另一个更简单的示例链接(源代码):
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 完成,但我没有看到过。使用 Application 只需调用 ApplicationWindow 即可。 - Hercislife

6
第二种方法更好。它使应用程序更加整合到桌面,并提供了更多关于其功能或意图的信息。它还为您提供了更多可与应用程序一起使用的工具。
我认为第一种方法已经过时了或者说不够现代化。第二种方法确实是首选方式。
您可以看到应用程序 Gnome-music 实际上正在使用 第二种方法,即使用 Gtk.Application。所有官方 Gnome 应用程序都在使用 Gtk.Application,所有 Gtk 应用程序也应该使用它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接