带有多窗口的Pygame

8 人关注

我需要建立一个有多个窗口的应用程序。 在其中一个窗口中,我需要能够玩一个简单的游戏,另一个窗口必须显示问题并从影响游戏的用户那里得到回应。

(1) 我想使用pygame来制作游戏。 是否有一个 simple 如何让pygame在多个窗口下运行?

(2) 如果没有简单的方法来解决(1),有没有一种简单的方法来使用一些其他的python GUI结构,让我可以同时运行pygame和另一个窗口?

python
user-interface
wxpython
pygame
Marjoram
Marjoram
发布于 2015-04-23
4 个回答
derricw
derricw
发布于 2022-05-08
已采纳
0 人赞同

简短的回答是否定的,在同一进程中创建两个pygame窗口是不可能的(截止到2015年4月)。 如果你想在一个进程中运行两个窗口,你应该研究一下 pyglet or cocos2d .

如果你必须使用pygame,另一个选择是使用进程间通信。 你可以有两个进程,每个都有一个窗口。 它们将使用套接字来互相传递信息。 如果你想走这条路,请查看套接字教程 here .

套接字可能是太低级的解决方案。ZeroMq或其他类似的库可能足以来回推送消息。
你可以打开多个窗口并从一个事件循环中控制它们。 你使用的绘图方法是不同的,你必须跟踪WINDOWENTER和WINDOWLEAVE事件,以便你知道在哪里发送输入事件。
panicq
panicq
发布于 2022-05-08
0 人赞同

在内部,set_mode()可能设置了一个指针,代表一个独特的显示器的内存。因此,如果我们写

screenA = pygame.display.set_mode((500,480), 0, 32)
screenB = pygame.display.set_mode((500,480), 0, 32)

例如,我们以后可以做这样的事情。

screenA.blit(background, (0,0))
screenB.blit(player, (100,100))

两个blit()调用都会在同一个表面上进行blit,screenA和screenB都指向同一个内存地址。在pygame中要实现两个窗口的工作是相当困难的。

user9152964
发布于 2022-05-08
0 人赞同

是的,这是有可能的。SDL2能够打开多个窗口。在例子文件夹中,你可以看一下 "video.py"。

https://github.com/pygame/pygame/blob/main/examples/video.py

" 这个例子需要 pygame 2 和 SDL2。_sdl2是实验性的,会有变化。 "

Darrel Lee
Darrel Lee
发布于 2022-05-08
0 人赞同

我已经尝试做了几天,终于有了进展。 这算不算简单? 甚至可以说是 "在 "pygame中。 在这个例子中,我甚至没有调用 pygame.init(),这似乎妨碍了它。 事件泵正在运行(针对鼠标和键盘),但似乎不是所有的正常事件都能通过(尤其是 FOCUSGAINED 和 LOST)。 在这个例子中,每个窗口都向自己渲染了它的状态(大小、位置等)。我也有将SDL窗口与pygame显示混合的版本。 但是这些涉及到封装一个窗口,而不是扩展它。

为了在这些窗口上作画,你可以像往常一样在一个虚无的表面上作画,然后使用与该窗口相关的渲染器来创建一个纹理,以更新该窗口的内容。 (texture.draw(), renderer.present)。 你没有使用 display.update() 或 flip() ,因为你没有使用 pygame 的显示表面。

X11包只是我的实验性视窗东西,与X11没有关系。 我想我所有的导入都是明确的,所以应该很容易弄清缺少的部分是什么。

from typing import List
from pygame import Rect, Surface, Color
import pygame.event
from pygame.event import Event
from pygame.freetype import Font
from pygame._sdl2.video import Window, Renderer, Texture
from X11.windows import DEFAULT_PAD, default_font, window_info
from X11.text import prt
class MyWindow(Window):
    def __init__(self, font: Font=None):
        super().__init__()
        self._font = font if font else default_font()
        self.resizable = True
        self._renderer = None
    def destroy(self) -> None:
        super().destroy()
    def update(self):
        r = self.renderer
        r.draw_color = Color('grey')
        r.clear()
        #self.render_line(f"TICKS: {pg.time.get_ticks()}", 5, size=16.0)
        txt: List[str] = window_info(self)
        self.render_text(txt, lineno=0)
        r.present()
    @property
    def renderer(self):
        if self._renderer is None:
                self._renderer = Renderer.from_window(self)
            except:
                self._renderer = Renderer(self)
        return self._renderer
    def render_text(self, txt: List[str], lineno: int=0):
        for line in txt:
            self.render_line(line, lineno, size=16.0)
            lineno += 1
    def render_line(self, txt: str, lineno: int = 0, size: float = 0.0):
        font = self._font
        line_spacing = font.get_sized_height(size) + DEFAULT_PAD
        x = DEFAULT_PAD
        y = DEFAULT_PAD + lineno * line_spacing
        # compute the size of the message
        src_rect = font.get_rect(txt, size=size)
        # create a new surface (image) of text
        l_surf = Surface((src_rect.width, src_rect.height))
        src_rect = font.render_to(l_surf, (0, 0), txt, size=size)
        # get ready to draw
        texture = Texture.from_surface(self.renderer, l_surf)
        dst = Rect(x, y, src_rect.width, src_rect.height)
        texture.draw(None, dst)
_running: bool = False
def test():
    global _running
    win1 = MyWindow()
    win2 = MyWindow()
    my_windows = {win1.id: win1, win2.id: win2}
    win = win1
    rnd = win1.renderer
    print("pygame.get_init():", pygame.get_init())
    print("pygame.display.get_init():", pygame.display.get_init())
    print("pygame.mouse.get_pos():", pygame.mouse.get_pos())
    clock = pygame.time.Clock()
    _running = True
    while _running:
        events = pygame.event.get()
        for event in events:
            if event.type != pygame.MOUSEMOTION:
                print(event)
            if event.type == pygame.QUIT:
                _running = False
            elif event.type == pygame.WINDOWENTER:
                win = my_windows[event.window.id]
                print(f"Enter Window ({event.window.id}")
            elif event.type == pygame.WINDOWLEAVE:
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_q:
                    _running = False
                if event.key == pygame.K_1:
                   win = my_windows[1]
                   rnd = win.renderer
                if event.key == pygame.K_2:
                   win = my_windows[2]
                   rnd = win.renderer
                elif event.key == pygame.K_b:
                    rnd.draw_color = Color('blue')
                    rnd.clear()
                elif event.key == pygame.K_g:
                    rnd.draw_color = Color('grey')
                    rnd.clear()
                elif event.key == pygame.K_t:
                    win.render_line("Hello, world")
                elif event.key == pygame.K_s:
                    surface = pygame.display.get_surface()
                    print("surface: ", surface)
                elif event.key == pygame.K_f:
                    pygame.display.flip()
                    # pygame.error: Display mode not set
                elif event.key == pygame.K_u:
                    pygame.display.update()
                    # pygame.error: Display mode not set
        for win in my_windows.values():
            win.update()