PythonGtk教程展示了如何使用Gtk模块在Python中创建GUI应用程序。本教程涵盖GTK4。
GTK
GTK是一个用于创建图形用户界面的多平台工具包。它是用C语言创建的。GTK经过全新设计,支持多种语言,包括Python、Ruby和Perl。
GTK库也称为GIMP工具包。最初,该库是在开发GIMP图像处理程序时创建的。从此,GTK成为Linux和BSDUnix下最流行的工具包之一。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk print(f'{Gtk.MAJOR_VERSION}.{Gtk.MINOR_VERSION}.{Gtk.MICRO_VERSION}')
我们通过语言内省访问GTK库。PyGObject
是C库的语言接口。
import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk
我们导入Gtk模块。require_version
方法确保命名空间加载给定版本。gi.repository
是PyGObject
的Python模块。PyGObject
(PythonGObject自省)包含Python绑定和对GObject、GLib、GTK和其他库的支持。
$ ./version.py 4.6.5
PythonGtk简单例子
在第一个应用程序中,我们在屏幕上显示一个窗口。Gtk.Window
是一个可以包含其他小部件的顶层窗口。换句话说,它是一个容器。Windows通常具有受窗口系统控制的装饰,并允许用户操作窗口。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk def on_activate(app): win = Gtk.ApplicationWindow(application=app) win.set_title('Simple') win.present() app = Gtk.Application(application_id='com.zetcode.Simple') app.connect('activate', on_activate) app.run(None)
该示例在屏幕上显示一个小窗口。
def on_activate(app): win = Gtk.ApplicationWindow(application=app) win.set_title('Simple') win.present()
我们在on_activate
函数中创建主应用程序窗口。我们使用set_title
设置应用程序的标题,并使用present
将其呈现给用户。
app = Gtk.Application(application_id='com.zetcode.Simple') app.connect('activate', on_activate) app.run(None)
我们创建一个新的Gtk.Application
。要设置应用程序,我们连接到activate
信号,该信号在应用程序激活时发出。run
函数运行应用程序。
在下一个示例中,我们将以OOP风格重写示例。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui() def init_ui(self): self.set_title('Simple') self.set_default_size(350, 250) def on_activate(app): win = AppWindow(app) win.present() app = Gtk.Application(application_id='com.zetcode.Simple') app.connect('activate', on_activate) app.run(None)
我们创建一个继承自Gtk.ApplicationWindow
的类。我们在init_ui
库中构建UI。
self.set_default_size(350, 250)
使用set_default_size
函数,我们设置应用程序窗口的默认大小。
PythonGtk.Image
Gtk.Image
显示图像。如果文件加载不成功,图像将包含一个“损坏的图像”图标。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui() def init_ui(self): self.set_title('Image') image = Gtk.Image.new_from_file('sid.png') self.set_child(image) self.set_default_size(450, 350) def on_activate(app): win = AppWindow(app) win.present() app = Gtk.Application(application_id='com.zetcode.Image') app.connect('activate', on_activate) app.run(None)
该示例在窗口上显示PNG图像。
image = Gtk.Image.new_from_file('sid.png')
Gtk.Image
是从文件创建的。
self.set_child(image)
我们将图像设置为应用程序窗口的主容器。
PythonGtk.Button
Gtk.Button
用于触发按下按钮时调用的回调函数。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui() def init_ui(self): self.set_title('Quit button') box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) box.set_margin_start(5) box.set_margin_top(5) btn = Gtk.Button(label="Quit") btn.connect('clicked', lambda _: self.close()) btn.set_halign(Gtk.Align.START) box.append(btn) self.set_default_size(350, 250) self.set_child(box) def on_activate(app): win = AppWindow(app) win.present() app = Gtk.Application(application_id='com.zetcode.QuitButton') app.connect('activate', on_activate) app.run(None)
在示例中,我们有一个按钮。当我们按下按钮时,应用程序终止。
box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) box.set_margin_start(5) box.set_margin_top(5)
我们创建一个垂直框。我们在框的左侧和顶部放置了一些边距。Gtk.Box
是一个简单的布局小部件,可以将小部件排列成一行或一列。
btn = Gtk.Button(label="Quit")
创建了一个Gtk.Button
。
btn.connect('clicked', lambda _: self.close())
当按钮被点击时,它发出一个clicked
信号。使用connect
方法,我们将信号绑定到self.close
方法.
btn.set_halign(Gtk.Align.START) box.append(btn)
我们将按钮对齐到框的左侧并将其添加到垂直框。
self.set_default_size(350, 250) self.set_child(box)
最后,我们设置应用程序窗口的默认大小,并将垂直框添加到窗口容器中。
PythonGtk.CheckButton
Gtk.CheckButton
一个有两种状态的小部件:打开和关闭。onstate通过复选标记可视化。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui() def init_ui(self): self.set_title('Check button') box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) box.set_margin_start(5) box.set_margin_top(5) cbtn = Gtk.CheckButton.new_with_label('Show title') cbtn.set_active(True) cbtn.connect('toggled', self.on_toggle) box.append(cbtn) self.set_child(box) self.set_default_size(450, 350) def on_toggle(self, wid): if wid.get_active(): self.set_title('CheckButton') else: self.set_title('') def on_activate(app): win = AppWindow(app) win.present() app = Gtk.Application(application_id='com.zetcode.CheckButton') app.connect('activate', on_activate) app.run(None)
该示例根据Gtk.CheckButton
的状态在窗口的标题栏中显示一个标题。
cbtn = Gtk.CheckButton.new_with_label('Show title') cbtn.set_active(True)
Gtk.CheckButton
已创建。由于默认情况下窗口的标题是可见的,我们使用set_active
激活按钮。
cbtn.connect('toggled', self.on_toggle)
当我们选中或取消选中Gtk.CheckButton
时,会发出toggled
信号。我们将on_toggle
处理程序插入信号。
def on_toggle(self, wid): if wid.get_active(): self.set_title('CheckButton') else: self.set_title('')
我们使用get_active
确定Gtk.CheckButton
的状态并相应地设置标题。
按键事件
下一个示例对key-pressed
事件作出反应。
#!/usr/bin/python import gi from gi.repository import Gtk gi.require_version("Gtk", "4.0") class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui() def init_ui(self): self.set_title('Key press') keycont = Gtk.EventControllerKey() keycont.connect('key-pressed', self.on_key_pressed) self.add_controller(keycont) self.set_default_size(350, 250) # keyval, keycode, state, user_data def on_key_pressed(self, keyval, keycode, *_): if keycode == ord('q'): self.close() def on_activate(app): win = AppWindow(app) win.present() app = Gtk.Application(application_id='com.zetcode.KeyPress') app.connect('activate', on_activate) app.run(None)
应用程序监听按键事件。如果用户输入q键,则应用程序终止。
keycont = Gtk.EventControllerKey() keycont.connect('key-pressed', self.on_key_pressed) self.add_controller(keycont)
我们创建并注册了Gtk.EventControllerKey
。我们连接到key-pressed
信号。
# keyval, keycode, state, user_data def on_key_pressed(self, keyval, keycode, *_): if keycode == ord('q'): self.close()
我们检查键码。如果是q,我们关闭应用程序。
PythonGtk.Entry
Gtk.Entry
小部件是一个单行文本输入小部件。默认情况下支持许多键绑定。如果输入的文本比小部件的分配长,小部件将滚动以便光标位置可见。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui() def init_ui(self): self.set_title('Quit button') vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 8) hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8) vbox.set_margin_start(5) vbox.set_margin_top(5) self.entry = Gtk.Entry() hbox.append(self.entry) keycont = Gtk.EventControllerKey() keycont.connect('key-released', self.on_key_released) self.add_controller(keycont) self.label = Gtk.Label.new('...') hbox.append(self.label) self.set_title('Entry') self.set_default_size(450, 350) vbox.append(hbox) self.set_child(vbox) def on_key_released(self, *_): self.label.set_text(self.entry.get_text()) def on_activate(app): win = AppWindow(app) win.present() app = Gtk.Application(application_id='com.zetcode.QuitButton') app.connect('activate', on_activate) app.run(None)
在示例中,我们有一个条目小部件和一个标签。输入到条目中的文本显示在标签中。
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 8) hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8)
布局是通过垂直和水平框的组合创建的。
self.entry = Gtk.Entry()
我们创建了Gtk.Entry
小部件。
keycont = Gtk.EventControllerKey() keycont.connect('key-released', self.on_key_released) self.add_controller(keycont)
为了能够处理按键事件,我们创建了一个Gtk.EventControllerKey
。我们对on_key_released
事件作出反应。
def on_key_released(self, *_): self.label.set_text(self.entry.get_text())
在on_key_released
事件处理程序中,我们使用get_text
从条目中获取文本,并使用set_text
将其设置为标签。
PythonGtk.ComboBoxText
Gtk.ComboBoxText
是Gtk.ComboBox
的一个简单变体,它隐藏了简单的纯文本用例的模型视图复杂性。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui() def init_ui(self): self.set_title('Quit button') vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 8) hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8) combo = Gtk.ComboBoxText() vbox.set_margin_start(5) vbox.set_margin_top(5) hbox.append(combo) combo.connect('changed', self.on_changed) combo.append_text('Arch') combo.append_text('Fedora') combo.append_text('Redhat') combo.append_text('Gentoo') combo.append_text('Xubuntu') self.label = Gtk.Label.new('') hbox.append(self.label) self.set_title('ComboBoxText') self.set_default_size(450, 350) vbox.append(hbox) self.set_child(vbox) def on_changed(self, wid): self.label.set_label(wid.get_active_text()) def on_activate(app): win = AppWindow(app) win.present() app = Gtk.Application(application_id='com.zetcode.ComboBoxText') app.connect('activate', on_activate) app.run(None)
在示例中,我们有一个Gtk.ComboBoxText
和一个标签。从组合框中选择的项目显示在标签小部件中。
combo = Gtk.ComboBoxText()
Gtk.ComboBoxText
已创建。
combo.connect('changed', self.on_changed)
当活动项目发生变化时,changed
信号被发射。
combo.append_text('Arch') combo.append_text('Fedora') combo.append_text('Redhat') combo.append_text('Gentoo') combo.append_text('Xubuntu')
我们向组合框添加五个文本项。
def on_changed(self, wid): self.label.set_label(wid.get_active_text())
在on_changed
事件处理程序中,我们使用get_active_text
获取活动文本,并使用set_label
将其设置为标签。
绘图
绘图是在Gtk.DrawingArea
小部件上完成的。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') import math from gi.repository import Gtk class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui() def init_ui(self): self.set_title('Drawing') area = Gtk.DrawingArea.new() area.set_draw_func(self.on_draw) self.set_default_size(450, 300) self.set_child(area) def on_draw(self, da, ctx, w, h): ctx.set_source_rgb(0.6, 0.6, 0.6) ctx.rectangle(20, 20, 120, 80) ctx.rectangle(180, 20, 80, 80) ctx.fill() ctx.arc(330, 60, 40, 0, 2*math.pi) ctx.fill() ctx.arc(90, 160, 40, math.pi/4, math.pi) ctx.fill() ctx.translate(220, 180) ctx.scale(1, 0.7) ctx.arc(0, 0, 50, 0, 2*math.pi) ctx.fill() def on_activate(app): win = AppWindow(app) win.present() app = Gtk.Application(application_id='com.zetcode.Drawing') app.connect('activate', on_activate) app.run(None)
该示例绘制了一些基本形状。
area = Gtk.DrawingArea.new() area.set_draw_func(self.on_draw)
我们创建Gtk.DrawingArea
并使用set_draw_func
设置绘图功能。
def on_draw(self, da, ctx, w, h): ...
on_draw
的第二个参数是绘图区域,第三个是绘图上下文。上下文是一个用于在所有可绘制对象上绘制的对象。最后两个参数是区域的宽度和高度。
ctx.set_source_rgb(0.6, 0.6, 0.6)
set_source_rgb
方法为绘图上下文设置颜色。该方法的三个参数是颜色强度值。取值范围为0到1。
ctx.rectangle(20, 20, 120, 80) ctx.rectangle(180, 20, 80, 80) ctx.fill()
我们绘制两个矩形。fill
方法以先前设置的颜色绘制矩形的内部。
ctx.arc(330, 60, 40, 0, 2*math.pi) ctx.fill()
使用arc
方法,我们画了一个完整的圆。
ctx.translate(220, 180)
translate
方法将用户空间原点移动deltax和deltay。
ctx.scale(1, 0.7) ctx.arc(0, 0, 50, 0, 2*math.pi) ctx.fill()
如果我们想画一个椭圆,我们先做一些缩放。这里scale
方法缩小了y轴。
PythonGtk.Menu
在下一个示例中,我们将创建一个带有菜单栏的应用程序。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, Gio class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui(app) def init_ui(self, app): self.set_title('Simple menu') main = Gio.Menu.new() fmi = Gio.MenuItem.new('File') menu = Gio.Menu.new() emi = Gio.MenuItem.new('Exit', 'app.quit') menu.append_item(emi) fmi.set_submenu(menu) main.append_item(fmi) app.set_menubar(main) act_quit = Gio.SimpleAction.new('quit', None) Gio.ActionMap.add_action(app, act_quit) act_quit.connect('activate', self.on_close, app) self.set_show_menubar(True) self.set_default_size(350, 250) def on_close(self, *_): self.close() def on_activate(app): win = AppWindow(app) win.present() app = Gtk.Application(application_id='com.zetcode.SimpleMenu') app.connect('activate', on_activate) app.run(None)
菜单栏有一个菜单项,它终止了应用程序。
main = Gio.Menu.new() fmi = Gio.MenuItem.new('File') menu = Gio.Menu.new() emi = Gio.MenuItem.new('Exit', 'app.quit') menu.append_item(emi) fmi.set_submenu(menu) main.append_item(fmi)
我们设置菜单和菜单项。app.quit
字符串是指在应用程序对象中注册的操作。
app.set_menubar(main)
我们使用set_menubar
设置菜单栏。
act_quit = Gio.SimpleAction.new('quit', None) Gio.ActionMap.add_action(app, act_quit) act_quit.connect('activate', self.on_close, app)
创建了一个简单的动作;该操作调用on_close
,它会终止应用程序。
self.set_show_menubar(True)
我们使用set_show_menubar
显示菜单栏。
CSS主题
我们可以使用CSS为我们的应用设置主题。
window { background-color: rgb(59, 56, 56); } button { color: rgb(233, 32, 27); }
在CSS中,我们为窗口设置自定义背景色,为按钮设置自定义前景色。
#!/usr/bin/python import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, Gio class AppWindow(Gtk.ApplicationWindow): def __init__(self, app): super(AppWindow, self).__init__(application=app) self.init_ui() def init_ui(self): self.set_title('CSS theme') box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) btn = Gtk.Button(label="Quit") btn.connect('clicked', lambda _: self.close()) btn.set_margin_start(5) btn.set_margin_top(5) btn.set_halign(Gtk.Align.START) box.append(btn) self.set_child(box) self.set_default_size(350, 250) def on_activate(app): win = AppWindow(app) display = Gtk.Widget.get_display(win) provider = Gtk.CssProvider.new() fname = Gio.file_new_for_path('theme.css') provider.load_from_file(fname) Gtk.StyleContext.add_provider_for_display(display, provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) win.present() app = Gtk.Application(application_id='com.zetcode.CheckButton') app.connect('activate', on_activate) app.run(None)
主题是使用Gtk.CssProvider
创建的。在此示例中,我们从文件加载CSS。
display = Gtk.Widget.get_display(win) provider = Gtk.CssProvider.new() fname = Gio.file_new_for_path('theme.css') provider.load_from_file(fname) Gtk.StyleContext.add_provider_for_display(display, provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
我们创建一个CSS提供程序,加载主题,并将提供程序应用于显示。
在本教程中,我们使用PythonGtk创建了基本的GUI应用程序。
列出所有Python教程。