我将pygame窗口嵌入到Tkinter中,如何操作pygame窗口? [英] I'm embedding a pygame window into Tkinter, how do I manipulate the pygame window?

查看:217
本文介绍了我将pygame窗口嵌入到Tkinter中,如何操作pygame窗口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我正在pygame中制作游戏,我也想使用tkinter.我将pygame窗口嵌入到tkinter窗口中,但似乎无法执行任何操作.

So I'm making a game in pygame, and I want to use tkinter as well. I embedded a pygame window into a tkinter window, but I can't seem to do anything with it.

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

For context, here is the full code:

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似乎是不必要的.

When I use pygame.draw.rect(screen.win, (0, 0, 255), (200, 200, 100, 100)), nothing happens. Using pygame inside the class worked, but in my more complicated game, using self.variable for all my variables seems unnecessary.

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

How can I run my code in the pygame window outside of the window class?

推荐答案

所以-除了明显缺少对 pygame.display.flip 的调用-我想这是您对 pygame.display.init ( pygame.init 已经调用了该代码)-我发现tkinter需要在打包框架完全可用之前初始化其窗口和小部件.由Pygame使用.

So - besides the obvious missing call to pygame.display.flip - which I suppose is what you intended with the call to pygame.display.init (pygame.init already calls that one) - what I found out is that tkinter needs to initialize its windows and widgets before the packed frame is fully available to be used by Pygame.

为此,我在调用 pygame.init 之前,先添加了对 self.root.update_idletasks()的调用,然后为我的平台明确设置了视频驱动程序(您已经在Windows中执行过此操作),使一切正常.

I did that by adding a call to self.root.update_idletasks() before calling pygame.init -- that, and explicitly setting the video driver for my platform (which you already does for Windows), made things work.

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

Anyway, also, in your code you did not show were you wanted to make the calls to Pygamedrawing functions - as it is, it is well possible that everything is correct, but the code after screen.window() is just never run (or rather, just run at program exit) - because you call tkinter.mainloop inside the __init__ method of your application class.

将调用移到 __ init __ 之外是一个好习惯,因此您也可以初始化其他对象和资源-实际上,您确实拥有屏幕对象以对其进行操作.通过在 __ init __ 内部进行该调用,就好像您的整个程序都在初始化内部"运行一样.

Moving the call to mainloop outside the __init__ is a good practice, so you can initialize other objects and resources as well - and you actualy do have the screen object to operate things on. By making that call inside __init__ is like your whole program was running "inside the initialization".

简而言之:

  • 在初始化pygame之前先呼叫 tkinter.update_iddletasks()
  • 记住在使用Pygame绘制任何内容后调用 pygame.display.flip
  • 安排代码,以便您的绘图调用得以实际执行,并且在进入tkinter循环的调用之后不会被阻塞
  • 您应该认真考虑使用Python 3.7或更高版本-(唯一的"python 2"代码中有 import Tkinter 变成了 import tkinter 在Python 3中).Python 2在行的最后确实,并且上面没有针对pygame之类的项目的更新.
  • call tkinter.update_iddletasks() before initializing pygame
  • remember to call pygame.display.flip after you draw anything with Pygame
  • arrange your code so that your drawing calls are actually executed, and not blocked after the call to enter tkinter's loop
  • You should seriously consider using Python 3.7 or later - (the only "python 2" code there is import Tkinter which becomes import tkinter in Python 3). Python 2 is really at the end of line, and there are no updates for projects like pygame on it. .

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

That said, here is your code, modified to run on Linux + Python 3 (should still work on Windows), and to actually perform some actions using the embedded pygame frame.

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窗口嵌入到Tkinter中,如何操作pygame窗口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆