根窗口
最后修改于 2023 年 7 月 17 日
在本篇 PyCairo 教程中,我们将使用根窗口。根窗口是我们通常放置图标快捷方式的桌面窗口。
可以操作根窗口。从程序员的角度来看,它只是一个特殊的窗口。
透明窗口
我们的第一个示例创建一个透明窗口。我们可以看到窗口对象下方的图像。
#!/usr/bin/python ''' ZetCode PyCairo tutorial This code example shows how to create a transparent window. author: Jan Bodnar website: zetcode.com ''' from gi.repository import Gtk import cairo class Example(Gtk.Window): def __init__(self): super(Example, self).__init__() self.tran_setup() self.init_ui() def init_ui(self): self.connect("draw", self.on_draw) self.set_title("Transparent window") self.resize(300, 250) self.set_position(Gtk.WindowPosition.CENTER) self.connect("delete-event", Gtk.main_quit) self.show_all() def tran_setup(self): self.set_app_paintable(True) screen = self.get_screen() visual = screen.get_rgba_visual() if visual != None and screen.is_composited(): self.set_visual(visual) def on_draw(self, wid, cr): cr.set_source_rgba(0.2, 0.2, 0.2, 0.4) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() def main(): app = Example() Gtk.main() if __name__ == "__main__": main()
要创建透明窗口,我们需要获取屏幕对象的 visual,并将其设置给我们的窗口。在 on_draw
方法中,我们在屏幕的 visual 对象上进行绘制。这创造了一种部分透明的错觉。
self.set_app_paintable(True)
我们必须设置应用程序进行绘制。
screen = self.get_screen()
get_screen
方法返回屏幕对象。
visual = screen.get_rgba_visual()
从屏幕窗口,我们获取其 visual。visual 包含低级显示信息。
if visual != None and screen.is_composited(): self.set_visual(visual)
并非所有显示都支持此操作。因此,我们检查我们的屏幕是否支持组合,以及返回的 visual 是否不为 None。我们将屏幕的 visual 设置为我们窗口的 visual。
def on_draw(self, wid, cr): cr.set_source_rgba(0.2, 0.2, 0.2, 0.4) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint()
我们使用一个部分透明的源在屏幕窗口上绘制。cairo.OPERATOR_SOURCE
创建一个组合操作,我们在源上进行绘制。源就是屏幕窗口。要获得完全透明,我们将 alpha 值设置为 0 或使用 cairo.OPERATOR_CLEAR
操作符。

截屏
根窗口对于截屏也很重要。
#!/usr/bin/python ''' ZetCode PyCairo tutorial This code example takes a screenshot. author: Jan Bodnar website: zetcode.com ''' from gi.repository import Gdk import cairo def main(): root_win = Gdk.get_default_root_window() width = root_win.get_width() height = root_win.get_height() ims = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) pb = Gdk.pixbuf_get_from_window(root_win, 0, 0, width, height) cr = cairo.Context(ims) Gdk.cairo_set_source_pixbuf(cr, pb, 0, 0) cr.paint() ims.write_to_png("screenshot.png") if __name__ == "__main__": main()
该示例捕获整个屏幕的快照。
root_win = Gdk.get_default_root_window()
我们通过调用 Gdk.get_default_root_window
方法来获取根窗口。
width = root_win.get_width() height = root_win.get_height()
我们确定根窗口的宽度和高度。
ims = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
创建一个空的图像表面。它的尺寸与根窗口相同。
pb = Gdk.pixbuf_get_from_window(root_win, 0, 0, width, height)
我们使用 Gdk.pixbuf_get_from_window
方法调用从根窗口获取一个 pixbuf。pixbuf 是一个描述内存中图像的对象。它被 GTK 库使用。
cr = cairo.Context(ims) Gdk.cairo_set_source_pixbuf(cr, pb, 0, 0) cr.paint()
在上面的代码行中,我们在之前创建的图像表面上创建一个 Cairo 绘图上下文。我们将 pixbuf 放置在绘图上下文中,并将其绘制到表面上。
ims.write_to_png("screenshot.png")
使用 write_to_png
方法将图像表面写入 PNG 图像。
显示消息
在第三个示例中,我们在桌面窗口上显示一条消息。
#!/usr/bin/python ''' ZetCode PyCairo tutorial This code example shows a message on the desktop window. author: Jan Bodnar website: zetcode.com ''' from gi.repository import Gtk, Gdk, Pango import cairo class Example(Gtk.Window): def __init__(self): super(Example, self).__init__() self.setup() self.init_ui() def setup(self): self.set_app_paintable(True) self.set_type_hint(Gdk.WindowTypeHint.DOCK) self.set_keep_below(True) screen = self.get_screen() visual = screen.get_rgba_visual() if visual != None and screen.is_composited(): self.set_visual(visual) def init_ui(self): self.connect("draw", self.on_draw) lbl = Gtk.Label() text = "ZetCode, tutorials for programmers." lbl.set_text(text) fd = Pango.FontDescription("Serif 20") lbl.modify_font(fd) lbl.modify_fg(Gtk.StateFlags.NORMAL,Gdk.color_parse("white")) self.add(lbl) self.resize(300, 250) self.set_position(Gtk.WindowPosition.CENTER) self.connect("delete-event", Gtk.main_quit) self.show_all() def on_draw(self, wid, cr): cr.set_operator(cairo.OPERATOR_CLEAR) cr.paint() cr.set_operator(cairo.OPERATOR_OVER) def main(): app = Example() Gtk.main() if __name__ == "__main__": import signal signal.signal(signal.SIGINT, signal.SIG_DFL) main()
代码在根窗口上显示一个消息标签。
self.set_app_paintable(True)
我们将操作应用程序窗口,因此我们使其可绘制。
self.set_type_hint(Gdk.WindowTypeHint.DOCK)
实现此窗口提示可以移除窗口边框和装饰。
self.set_keep_below(True)
我们让应用程序始终保持在底部,正好在根窗口之上。
screen = self.get_screen() visual = screen.get_rgba_visual() if visual != None and screen.is_composited(): self.set_visual(visual)
我们将屏幕的 visual 设置为我们应用程序的 visual。
lbl = Gtk.Label() text = "ZetCode, tutorials for programmers." lbl.set_text(text)
我们将一个消息标签放在应用程序窗口上。
fd = Pango.FontDescription("Serif 20") lbl.modify_font(fd) lbl.modify_fg(Gtk.StateFlags.NORMAL,Gdk.color_parse("white"))
借助 Pango 模块,我们更改文本的外观。
def on_draw(self, wid, cr): cr.set_operator(cairo.OPERATOR_CLEAR) cr.paint() cr.set_operator(cairo.OPERATOR_OVER)
我们使用 cairo.OPERATOR_CLEAR
操作符清除窗口的背景。然后我们设置 cairo.OPERATOR_CLEAR
以便绘制标签小部件。
if __name__ == "__main__": import signal signal.signal(signal.SIGINT, signal.SIG_DFL) main()
有一个旧的 bug,它不允许我们使用 Ctrl+C 快捷方式终止从终端启动的应用程序。添加这两行是对此的一个解决方法。

在本章中,我们使用 PyCairo 处理了桌面窗口。