PyCairo指南的这个部分,我们将与根窗口打交道。根窗口就是桌面窗口,通常也是我们放置图标的地方。
通过根窗口来控制也是可能的。从程序员的角度来看,它仅仅是一种特殊的一个窗口。
我们的第一个例子将创建一个透明窗口。我们将看到窗口对象下面是什么东西。
#!/usr/bin/python ''' ZetCode PyCairo tutorial This code example shows how to create a transparent window. author: Jan Bodnar website: zetcode.com last edited: August 2012 ''' from gi.repository import Gtk import cairo class MainWindow(Gtk.Window): def __init__(self): super(self.__class__, 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, wdith, cr): cr.set_source_rgba(0.2, 0.2, 0.2, 0.4) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint() def main(): window = MainWindow() Gtk.main() if __name__ == "__main__": main()
为了创建一个透明的窗口,我们获取screen对象的visual值,并为我们的on_draw()方法设置它,我们在screen的visual对象上来画。这将创建一种假想的透明。
self.set_app_paintable(True)
我们必须设置应用paintable值为on。
screen = self.get_screen()
get_screen()方法返回screen对象。
visual = screen.get_rgba_visual()
从screen窗口,我们获取它的visual。这个visual包含一些底层的显示信息。
if visual != None and screen.is_composited(): self.set_visual(visual)
不是所有的显示都支持这种操作。然而,我们会检测我们的屏幕是否支持组合,并且返回的visual是非空的。我们将屏幕的visual设为我们的窗口的visual。
def on_draw(self, wdith, cr): cr.set_source_rgba(0.2, 0.2, 0.2, 0.4) cr.set_operator(cairo.OPERATOR_SOURCE) cr.paint()
我们使用部分透明的source来在屏幕窗口上绘制。cairo.OPERATOR_SOURCE创建一个组合操作,我们以此用source来画,其中source为屏幕窗口。为了获取完全的透明,我们可以设置alpha值为0,或者使用cairo.OPERATOR_CLEAR操作。
Figure: Transparent window
根窗口在截屏时也是需要的。
#!/usr/bin/python ''' ZetCode PyCairo tutorial This code example takes a screenshot. author: Jan Bodnar website: zetcode.com last edited: August 2012 ''' 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)
创建一个口的图像surface。它的大小与跟窗口一致。
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()
在上面的这几行code中,我们基于前面创建的图片surface创建了一个Cairo绘制上下文。我们把pixbuf放进绘制上下文,并且将它绘制到surface上。
ims.write_to_png("screenshot.png")
使write_to_png()方法将图片surface写如一个PNG图片。
在第三个例子中,我们将在桌面窗口中显示一条信息。
#!/usr/bin/python ''' ZetCode PyCairo tutorial This code example shows a message on the desktop window. author: Jan Bodnar website: zetcode.com last edited: August 2012 ''' from gi.repository import Gtk, Gdk, Pango import cairo class MainWindow(Gtk.Window): def __init__(self): super(self.__class__, self).__init__() self.setup() self.init_ui() 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 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 on_draw(self, wdith, cr): cr.set_operator(cairo.OPERATOR_CLEAR) cr.paint() cr.set_operator(cairo.OPERATOR_OVER) def main(): window = MainWindow() Gtk.main() if __name__ == "__main__": import signal signal.signal(signal.SIGINT, signal.SIG_DFL) main()
这段code在根窗口上显示一条消息标签。
self.set_app_paintable(True)
我们将管理应用窗口,所以使它为paintable。
self.set_type_hint(Gdk.WindowTypeHint.DOCK)
实现这个窗口hint移除窗口边界和装饰。
self.set_keep_below(True)We keep the application always at the bottom, just over the root window.我们保持应用总是在底部,只是在跟窗口上方。
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, wdith, cr): cr.set_operator(cairo.OPERATOR_CLEAR) cr.paint() cr.set_operator(cairo.OPERATOR_OVER)
我们使用cairo.OPERATOR_CLEAR操作符来清除窗口的背景。然后我们设置cairo.OPERATOR_CLEAR来画标签widget。
if __name__ == "__main__": import signal signal.signal(signal.SIGINT, signal.SIG_DFL) main()
有一个早先的bug 使得我们无法通过Ctrk+C快捷键来终止由终端启动的应用程序。添加这两行code是对这种情况的一种workaround的做法。
Figure: Message on the root window
在这一章中,我们讨论了PyCairo中的桌面窗口。