【问题标题】:I'm embedding a pygame window into Tkinter, how do I manipulate the pygame window? [duplicate]我在 Tkinter 中嵌入了一个 pygame 窗口,如何操作 pygame 窗口? [复制]
【发布时间】:2019-09-09 08:07:43
【问题描述】:

所以我在 pygame 中制作游戏,我也想使用 tkinter。我将 pygame 窗口嵌入到 tkinter 窗口中,但我似乎无法用它做任何事情。

关于上下文,这里是完整的代码:

import Tkinter as tk
import os
import platform
import pygame

class window(object):
    def __init__(self):
        self.root = tk.Tk()  # Main window
        self.root.title("SquareScape")
        self.root.iconbitmap(r'C:\Users\17_es\PycharmProjects\square_puzzle\images\icon.ico')
        self.root.configure(background='#9b9b9b')

        # Large Frame
        self.win_frame = tk.Frame(self.root, width=670, height=520, highlightbackground='#595959', highlightthickness=2)

        # menu (left side)
        self.menu = tk.Frame(self.win_frame, width=150, height=516, highlightbackground='#595959', highlightthickness=2)
        self.menu_label = tk.Label(self.menu, text="Settings", bg='#8a8a8a', font=("Courier", "16", "bold roman"))
        self.mute = tk.Button(self.menu, text="XXXX", font="Courier", bg='#bcbcbc', activebackground='#cdcdcd')

        # pygame
        self.pygame_frame = tk.Frame(self.win_frame, width=514, height=514, highlightbackground='#595959', highlightthickness=2)
        self.embed = tk.Frame(self.pygame_frame, width=512, height=512,)

        # Packing
        self.win_frame.pack(expand=True)
        self.win_frame.pack_propagate(0)

        self.menu.pack(side="left")
        self.menu.pack_propagate(0)
        self.menu_label.pack(ipadx=60, ipady=2)
        self.mute.pack(ipadx=40, ipady=2, pady=5)

        self.pygame_frame.pack(side="left")
        self.embed.pack()

        #This embeds the pygame window
        os.environ['SDL_WINDOWID'] = str(self.embed.winfo_id())
        if platform.system == "Windows":
            os.environ['SDL_VIDEODRIVER'] = 'windib'

        #Start pygame
        pygame.init()
        self.win = pygame.display.set_mode((512, 512))
        self.win.fill(pygame.Color(255, 255, 255))
        pygame.display.init()

        self.root.mainloop()

screen = window()

#Here is sample code that I want to run
pygame.draw.rect(screen.win, (0, 0, 255), (200, 200, 100, 100))

当我使用pygame.draw.rect(screen.win, (0, 0, 255), (200, 200, 100, 100)) 时,没有任何反应。在类中使用 pygame 是可行的,但在我更复杂的游戏中,对我的所有变量使用 self.variable 似乎是不必要的。

如何在窗口类之外的 pygame 窗口中运行我的代码?

【问题讨论】:

标签: python tkinter pygame embed


【解决方案1】:

所以 - 除了对 pygame.display.flip 的明显缺失调用 - 我想这是你对 pygame.display.init 的调用的意图(pygame.init 已经调用了那个) - 我发现 tkinter 需要初始化它在打包框架完全可供 Pygame 使用之前的窗口和小部件。

我通过在调用pygame.init 之前添加对self.root.update_idletasks() 的调用来做到这一点——并为我的平台显式设置视频驱动程序(你已经为 Windows 设置了),让一切正常工作。

无论如何,同样,在您的代码中,您没有显示是否要调用 Pygamedrawing 函数 - 事实上,很可能一切都是正确的,但 screen.window() 之后的代码永远不会运行(或者更确切地说,只是在程序退出时运行) - 因为您在应用程序类的 __init__ 方法中调用 tkinter.mainloop。

将对mainloop 的调用移到__init__ 之外是一种很好的做法,因此您也可以初始化其他对象和资源——实际上您确实有screen 对象可以操作。通过在 __init__ 内部进行调用,就像您的整个程序在“初始化内部”运行一样。

简而言之:

  • 在初始化pygame之前调用tkinter.update_iddletasks()
  • 使用 Pygame 绘制任何东西后记得致电pygame.display.flip
  • 安排您的代码,以便实际执行绘图调用,而不是在调用进入 tkinter 循环后被阻塞
  • 您应该认真考虑使用 Python 3.7 或更高版本 - (唯一的“python 2”代码是 import Tkinter,在 Python 3 中变为 import tkinter)。 Python 2 真的在行尾,并且没有像 pygame 这样的项目的更新。 .

也就是说,这是您的代码,修改后可在 Linux + Python 3 上运行(仍应在 Windows 上运行),并使用嵌入式 pygame 框架实际执行一些操作。

import tkinter as tk
import os
import platform
import pygame
import time

class window(object):
    def __init__(self):
        self.root = tk.Tk()  # Main window
        self.root.title("SquareScape")
        # self.root.iconbitmap(r'C:\Users\17_es\PycharmProjects\square_puzzle\images\icon.ico')
        self.root.configure(background='#9b9b9b')

        # Large Frame
        self.win_frame = tk.Frame(self.root, width=670, height=520, highlightbackground='#595959', highlightthickness=2)

        # menu (left side)
        self.menu = tk.Frame(self.win_frame, width=150, height=516, highlightbackground='#595959', highlightthickness=2)
        self.menu_label = tk.Label(self.menu, text="Settings", bg='#8a8a8a', font=("Courier", "16", "bold roman"))
        self.mute = tk.Button(self.menu, text="XXXX", font="Courier", bg='#bcbcbc', activebackground='#cdcdcd')

        tk.Button(self.menu, text="<->", command=lambda: setattr(self, "direction", (-self.direction[0], self.direction[1]))).pack()
        tk.Button(self.menu, text="^", command=lambda: setattr(self, "direction", (self.direction[0], -self.direction[1]))).pack()

        # pygame
        self.pygame_frame = tk.Frame(self.win_frame, width=514, height=514, highlightbackground='#595959', highlightthickness=2)
        self.embed = tk.Frame(self.pygame_frame, width=512, height=512,)

        # Packing
        self.win_frame.pack(expand=True)
        self.win_frame.pack_propagate(0)

        self.menu.pack(side="left")
        self.menu.pack_propagate(0)
        self.menu_label.pack(ipadx=60, ipady=2)
        self.mute.pack(ipadx=40, ipady=2, pady=5)

        self.pygame_frame.pack(side="left")
        self.embed.pack()
        #This embeds the pygame window
        os.environ['SDL_WINDOWID'] = str(self.embed.winfo_id())
        system = platform.system()
        if system == "Windows":
            os.environ['SDL_VIDEODRIVER'] = 'windib'
        elif system == "Linux":
            os.environ['SDL_VIDEODRIVER'] = 'x11'

        self.root.update_idletasks()
        #Start pygame
        pygame.init()
        self.win = pygame.display.set_mode((512, 512))

        self.bg_color = (255, 255, 255)
        self.win.fill(self.bg_color)
        self.pos = 0, 0
        self.direction = 10, 10
        self.size = 40
        self.color = (0, 255, 0)
        self.root.after(30, self.update)

        self.root.mainloop()


    def update(self):

        first_move = True
        pygame.draw.rect(self.win, self.bg_color, self.pos + (self.size, self.size))


        self.pos = self.pos[0] + self.direction[0], self.pos[1] + self.direction[1]


        if self.pos[0] < 0 or self.pos[0] > 512 - self.size:
            self.direction = -self.direction[0], self.direction[1]
            self.pos = self.pos[0] + 2 * self.direction[0], self.pos[1] + self.direction[1]
        if self.pos[1] < 0 or self.pos[1] > 512 - self.size:
            self.direction = self.direction[0], -self.direction[1]
            self.pos = self.pos[0] + self.direction[0], self.pos[1] + 2 * self.direction[1]

        pygame.draw.rect(self.win, self.color, self.pos + (self.size, self.size))
        pygame.display.flip()
        self.root.after(30, self.update)


screen = window()
tk.mainloop()

【讨论】:

  • 谢谢,我有两个问题。首先,调用pygame.display.flip() 而不是pygame.display.update() 有什么好处吗?另外,在最初学习 pygame 时,有人告诉我 pygame 在 python 2 中工作得更好,这是错的吗?
  • 调用display.update 应该一样好。至于在 Python 3 中工作,现在这是错误的,但在 Pygame 几乎作为一个非活动项目的一段时间内是正确的。它在 Python 3 中的安装很麻烦,而且容易出错。该项目运行良好,并再次运行,并且使用 pip install 完美安装。
猜你喜欢
  • 1970-01-01
  • 2021-04-20
  • 2015-09-13
  • 1970-01-01
  • 1970-01-01
  • 2014-06-12
相关资源
最近更新 更多