窗口化

A Window 对应于操作系统提供的顶级窗口。窗口可以是浮动的(带或不带边框),也可以是全屏的。

创建窗口

如果 Window 构造函数在没有参数的情况下被调用,将假定所有参数为默认值::

window = pyglet.window.Window()

使用的默认参数为:

  • 窗口的大小为960x540,并且不能调整大小。

  • 将使用中所述的模板配置创建默认上下文 OpenGL配置选项

  • 窗口标题将是正在执行的Python脚本的名称(即, sys.argv[0] )。

窗口在创建后立即可见,除非您提供 visible=False 参数传递给构造函数。以下示例显示如何分两步创建和显示窗口:

window = pyglet.window.Window(visible=False)
# ... perform some additional initialisation
window.set_visible()

OpenGL上下文配置

窗口的上下文一旦创建就不能更改。有几种方法可以控制创建的上下文:

  • 提供已创建的 Context 使用 context 论点::

    context = config.create_context(share)
    window = pyglet.window.Window(context=context)
    
  • 提供完整的 Config 获取自 Screen 使用 config 争论。将从此配置创建上下文,并将与最近创建的现有上下文共享对象空间::

    config = screen.get_best_config(template)
    window = pyglet.window.Window(config=config)
    
  • 提供模板 Config 使用 config 争论。上下文将使用从默认显示的默认屏幕获得的最佳配置:

    config = gl.Config(double_buffer=True)
    window = pyglet.window.Window(config=config)
    
  • 指定一个 Screen 使用 screen 争论。上下文将使用从默认模板配置和此屏幕创建的配置:

    screen = display.get_screens()[screen_number]
    window = pyglet.window.Window(screen=screen)
    
  • 指定一个 Display 使用 display 争论。此显示屏上的默认屏幕将用于获取使用默认模板配置的上下文:

    display = platform.get_display(display_name)
    window = pyglet.window.Window(display=display)
    

如果模板 Config 被赋予,则一个 ScreenDisplay 也可以指定;但是,任何其他参数组合都会过度约束配置,并且某些参数将被忽略。

全屏窗口

如果 fullscreen=True 参数提供给窗口构造函数,则窗口将绘制到整个屏幕而不是浮动窗口。不会显示任何窗口边框或控件,因此您必须确保提供一些其他方法来退出应用程序。

默认情况下,将使用默认显示上的默认屏幕,但您可以选择指定另一个屏幕来替代。例如,下面的代码在辅助屏幕上创建一个全屏窗口:

screens = display.get_screens()
window = pyglet.window.Window(fullscreen=True, screen=screens[1])

无法创建跨越多个窗口的全屏窗口(例如,如果要跨多个监视器创建身临其境的3D环境)。相反,您应该为每个屏幕创建一个单独的全屏窗口,并将相同的事件处理程序附加到所有窗口。

属性可以切换窗口进入和退出全屏模式 set_fullscreen() 方法。例如,要从全屏返回窗口模式::

window.set_fullscreen(False)

以前的窗口大小和位置(如果有)将尝试恢复,但是操作系统并不总是允许这样做,并且窗口可能已重新定位。

大小和位置

本节仅适用于非全屏窗口。全屏窗口始终具有它们填充的屏幕的宽度和高度。

您可以将窗口的大小指定为窗口构造函数的前两个参数。在下面的示例中,创建了一个宽度为1280像素、高度为720像素的窗口:

window = pyglet.window.Window(1280, 720)

窗口的“大小”指的是其中的可绘制空间,不包括操作系统绘制的任何附加边框或标题栏。

您可以通过指定来允许用户调整窗口大小 resizable=True 在构造函数中。如果执行此操作,则可能还需要处理 on_resize() 活动::

window = pyglet.window.Window(resizable=True)

@window.event
def on_resize(width, height):
    print(f'The window was resized to {width},{height}')

属性指定用户可以调整窗口大小的最小和最大大小。 set_minimum_size()set_maximum_size() 方法:

window.set_minimum_size(320, 200)
window.set_maximum_size(1024, 768)

方法以编程方式调整窗口大小(即使窗口不可由用户调整大小)。 set_size() 方法:

window.set_size(1280, 720)

该窗口最初将由操作系统定位。通常,它会使用自己的算法将窗口定位在不会阻塞其他应用程序窗口或与它们一起层叠的位置。属性手动调整窗口的位置。 get_location()set_location() 方法:

x, y = window.get_location()
window.set_location(x + 20, y + 20)

请注意,与Piglet中常用的坐标系不同,窗口位置相对于桌面的左上角,如下图所示:

../_images/window_location.png

窗口相对于桌面的位置和大小。

外观

窗样式

可以使用以下六种样式之一创建非全屏窗口:默认、对话框、工具、无边框、透明或覆盖。透明和覆盖窗口只在Windows上实现,而不是在Mac OS X上。下面是Windows和Mac OS X 13.2下每种样式的外观示例。

这些窗口样式的不可调整大小的变体可能看起来略有不同(例如,最大化按钮将被禁用或不存在)。

除了外观更改外,窗样式还会影响窗的行为。例如,工具窗口通常不会出现在任务栏中,并且无法接收键盘焦点。对话框窗口不能最小化。覆盖需要自定义相应窗口的大小和移动。适合Windows的窗口样式意味着您的应用程序将在其运行的平台上正确运行,但这种行为在Windows、Linux和Mac OS X上可能不一致。

根据发行版、窗口管理器和用户偏好的不同,Linux中窗口的外观和行为会有很大的不同。

无边界窗口 (WINDOW_STYLE_BORDERLESS )根本不是由操作系统装饰的,并且无法在桌面上调整大小或移动。这些对于实现闪屏或自定义窗口边框很有用。

中指定窗口的样式。 Window 构造函数。窗样式一旦创建,就不能修改:

window = pyglet.window.Window(style=pyglet.window.Window.WINDOW_STYLE_DIALOG)

标题

窗口标题显示在其标题栏和任务栏图标中(在Windows和某些Linux窗口管理器上)。您可以在创建窗口时设置标题,也可以在以后的任何时候使用 set_caption() 方法:

window = pyglet.window.Window(caption='Initial caption')
window.set_caption('A different caption')

图标

窗口图标在Windows和Linux上显示在标题栏和任务栏图标中,在Mac OS X上显示在停靠图标中。对话框窗口和工具窗口不一定显示其图标。

Windows、Mac OS X和Linux窗口管理器都有自己的首选图标大小:

WindowsXP
  • 标题栏和任务栏的16x16图标。

  • Alt+Tab切换器的32x32图标。

Mac OS X
  • 16x16、24x24、32x32、48x48、72x72和128x128分辨率的任意数量的图标。实际显示的图像将根据提供的图像内插到正确的大小。

Linux
  • 没有限制,但大多数窗口管理器将使用与Windows XP相同的16x16和32x32图标。

这个 set_icon() 方法允许您将任意数量的图像设置为图标。Piglet将选择最合适的应用程序并将其应用于窗口。如果需要但未提供替代大小,则pyglet会使用简单的内插算法将图像缩放到正确的大小。

以下示例提供16x16和32x32图像作为窗口图标:

window = pyglet.window.Window()
icon1 = pyglet.image.load('16x16.png')
icon2 = pyglet.image.load('32x32.png')
window.set_icon(icon1, icon2)

您可以使用pyglet支持的任何格式的图像,但建议使用支持Alpha透明度的格式,如PNG。Windows.ico文件仅在Windows上受支持,因此不鼓励使用它们。Mac OS X.icons文件根本不受支持。

请注意,您在运行时设置的图标不需要与应用程序图标有任何关系,应用程序图标必须在应用程序二进制文件中专门编码(请参见 Self-contained executables )。

可见性

窗具有多种可见性状态。已经显示的是 visible 显示或隐藏窗口的属性。

Windows可以最小化,这等同于隐藏它们,只是它们仍然显示在任务栏上(或者在OS X上最小化到停靠)。用户可以通过点击标题栏中的适当按钮来最小化窗口。方法以编程方式最小化窗口。 minimize 方法(也有对应的 maximize 方法)。

当窗口变为可见时, on_show() 事件被触发。当它被隐藏时, on_hide() 事件被触发。在Windows和Linux上,仅当您手动更改窗口的可见性或最小化或恢复窗口时,才会发生这些事件。在Mac OS X上,用户还可以使用Command+H快捷键隐藏或显示窗口(影响可见性)。

子类化窗口

Piglet中的一个有用模式是子类化 Window 对于您将显示的每种类型的窗口,或作为主应用程序类。这有几个好处:

  • 您可以从构造函数加载字体和其他资源,确保已经创建了OpenGL上下文。

  • 只需在类上定义事件处理程序,即可添加它们。这个 on_resize() 事件将在窗口创建后立即被调用(这种情况通常不会发生,因为您必须先创建窗口才能附加事件处理程序)。

  • 减少了对全局变量的需要,因为您可以在窗口上维护应用程序状态。

下面的示例显示与中提供的相同的“Hello World”应用程序 编写一个pyglet应用程序 ,使用的子类 Window **

class HelloWorldWindow(pyglet.window.Window):
    def __init__(self):
        super().__init__()

        self.label = pyglet.text.Label('Hello, world!')

    def on_draw(self):
        self.clear()
        self.label.draw()

if __name__ == '__main__':
    window = HelloWorldWindow()
    pyglet.app.run()

此示例程序位于 examples/programming_guide/window_subclass.py

Windows和OpenGL上下文

Pyglet中的每个窗口都有一个关联的OpenGL上下文。指定此上下文的配置已在中介绍 创建窗口 。绘制到OpenGL上下文是绘制到窗口的工作区的唯一方法。

双缓冲

如果窗口是双缓冲的(即,指定的配置 double_buffer=True ,则将OpenGL命令应用于隐藏的后台缓冲区。此后台缓冲区可以使用 flip 方法。然后,前一个前台缓冲区成为我们在下一帧中渲染到的隐藏后台缓冲区。如果您使用的是标准 pyglet.app.runpyglet.app.EventLoop 事件循环,这将在每个事件后自动处理 on_draw() 事件。

如果窗口不是双缓冲的,则 flip() 操作是不必要的,并且您应该记住只调用 pyglet.gl.glFlush() 以确保执行缓冲的命令。

垂直回程同步

双缓冲消除了闪烁的一个原因:用户无法在绘制图像时看到它,只能看到最终的渲染。然而,它确实引入了另一个被称为“撕裂”的闪烁来源。

在动画中显示快速移动的对象时,撕裂会变得很明显。当视频显示器仍在从帧缓冲区读取数据时,发生缓冲区翻转,导致显示器的上半部分显示前一帧,而下半部分显示更新后的帧。如果您以特别快的速度更新帧缓冲区,您可能会在显示中注意到三个或更多这样的“撕裂”。

通过将缓冲区翻转同步到视频刷新率,pyglet提供了一种避免撕裂的方法。这在默认情况下是启用的,但可以随时使用 vsync (垂直回溯同步)属性。在以下示例中,在最初禁用vsync的情况下创建窗口:

window = pyglet.window.Window(vsync=False)

通常需要使vsync处于启用状态,因为这会产生无闪烁的动画。在某些用例中,您可能想要禁用它,例如:

  • 分析应用程序。测量执行操作所花费的时间将受到等待视频设备刷新所花费的时间的影响,这可能会丢弃结果。如果您正在测量应用程序的性能,则应禁用vsync。

  • 如果您负担不起阻止应用程序的费用。例如,如果您的应用程序运行循环需要快速轮询硬件设备,您可能希望避免使用vsync阻塞。