根窗口

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
'''

import gi
gi.require_version('Gtk', '3.0')
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()

为了创建透明窗口,我们获取 screen 对象的 visual 值,并为我们的窗口设置它。在 on_draw() 方法中,我们在 screen 的 visual 对象上绘制。这创造了部分透明的错觉。

        self.set_app_paintable(True)

我们必须将要绘制的应用设置为 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 不是 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()

我们使用部分透明的 source 在屏幕窗口上绘制。cairo.OPERATOR_SOURCE 创建一个组合操作,我们以此用 source 来绘制,其中 source 为屏幕窗口。为了获取完全的透明,我们把 alpha 值设置为 0,或者使用 cairo.OPERATOR_CLEAR 操作符。

图:透明窗口

截屏

根窗口在截屏时也是必须的。

#!/usr/bin/python

'''
ZetCode PyCairo tutorial

This code example takes a screenshot.

author: Jan Bodnar
website: zetcode.com
last edited: August 2012
'''

import gi
gi.require_version('Gdk', '3.0')
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()

在上面的这几行代码中,我们基于前面创建的图片 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
'''

import gi
gi.require_version('Gtk', '3.0')
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)

我们将管理应用窗口,所以使它为 paintable。

        self.set_type_hint(Gdk.WindowTypeHint.DOCK)

实现这个窗口 hint 移除窗口边界和装饰。

        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 来绘制标签 widget。

if __name__ == "__main__":
    import signal

    signal.signal(signal.SIGINT, signal.SIG_DFL)
    main()

有一个老 bug 使得我们无法通过 Ctrk+C 快捷键终止由终端启动的应用程序。添加这两行代码是对这种情况的一种workaround 做法。

图:根窗口上的消息

在这一章中,我们讨论了 PyCairo 中的桌面窗口。

原文

Done.

要使Tkinter应用程序中的窗口居中显示,您可以在创建主窗口后设置其位置。下面是具体的方法: 您可以先获取屏幕宽度和高度,然后据这些信息计算出窗口应放置的位置坐标(即x轴方向偏移量、y轴方向偏移量),最后使用`geometry()`方法将此值应用到窗口上。 ```python import tkinter as tk def center_window(root): # 获取屏幕宽高 screen_width = root.winfo_screenwidth() screen_height = root.winfo_screenheight() # 设置窗口大小(例如:400x300) window_width = 400 window_height = 300 # 计算左上角位置(x, y),让窗体位于屏幕中央 x_position = int((screen_width/2) - (window_width/2)) y_position = int((screen_height/2) - (window_height/2)) # 将新尺寸应用于root窗口 root.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}") if __name__ == "__main__": root = tk.Tk() center_window(root) label = tk.Label(text="Hello World") label.pack(expand=True) root.mainloop() ``` 上述脚本定义了一个辅助函数 `center_window`, 它接受一个 Tk 实例作为参数,并调整该实例所代表的窗口使之处于屏幕中心。请注意,在调用 `winfo_screenwidth()` 和 `winfo_screenheight()` 方法之前必须确保已正确初始化了Tk对象(`tk.Tk()`)。 此外需要注意的是,当首次加载时可能由于某些平台特性的缘故导致无法立即获得正确的屏幕分辨率数值;在这种情况下可以尝试在程序启动几秒钟后再执行定位逻辑或直接忽略这种情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值