Skip to main content
 首页 » 编程设计

python之如何在我的 Tkinter GUI 应用程序中嵌入 SDL2 窗口

2024年09月03日27shanyou

我正在尝试通过 pySDL2 将 SDL2 窗口嵌入到我的 Tkinter 应用程序中。如何设置我的 pySDL2 窗口、渲染器,以便我的渲染或绘图出现在嵌入式框架内?

针对 pygame 显示了其他示例,但我发现我的 pygame 版本当前无法正确使用 SDL2。我知道还有其他 pygame 实现试图实现 SDL2,但与 SDL2 的兼容性对我来说是最重要的。

正确工作的一个例子是 Tkinter 窗口中的一个框架,它有一个屏幕,当点击一个按钮时,通过 pySDL2 API 在框架上绘制一些东西。 在尝试使用在别处找到的 pygame 解决方案时,我收到了一些不同的错误,包括 BadWindow、BadDrawable(与 X 服务器功能相关。)

请您参考如下方法:

这方面的例子很难找到,所以希望这个答案能对其他人有所帮助。在使用 pySDL2 包装器 API 时,您需要了解不同操作的 ctypes。在某些情况下,API 已被扩展以避免其中一些看似神秘的操作。提供了一个示例代码,然后在下面进行解释。

from sdl2 import * 
import tkinter as tk 
from tkinter import * 
import random, ctypes 
 
def draw(): 
    global renderer 
    x1 = ctypes.c_int(random.randrange(0, 600)) 
    y1 = ctypes.c_int(random.randrange(0, 500)) 
    x2 = ctypes.c_int(random.randrange(0, 600)) 
    y2 = ctypes.c_int(random.randrange(0, 500)) 
    r = ctypes.c_ubyte(random.randrange(0, 255)) 
    g = ctypes.c_ubyte(random.randrange(0, 255)) 
    b = ctypes.c_ubyte(random.randrange(0, 255)) 
    SDL_SetRenderDrawColor(renderer, r, g, b, ctypes.c_ubyte(255)) 
    SDL_RenderDrawLine(renderer, x1, y1, x2, y2) 
 
def sdl_update(): 
    global window, event, renderer 
    SDL_RenderPresent(renderer); 
    if SDL_PollEvent(ctypes.byref(event)) != 0: 
        if event.type == SDL_QUIT: 
            SDL_DestroyRenderer(renderer) 
            SDL_DestroyWindow(window) 
            SDL_Quit() 
 
# tkinter stuff # 
root = tk.Tk() 
embed = tk.Frame(root, width = 500, height = 500) #creates embed frame for pygame window 
embed.grid(columnspan = (600), rowspan = 500) # Adds grid 
embed.pack(side = LEFT) #packs window to the left 
buttonwin = tk.Frame(root, width = 75, height = 500) 
buttonwin.pack(side = LEFT) 
button1 = Button(buttonwin,text = 'Draw',  command=draw) 
button1.pack(side=LEFT) 
root.update() 
################################# 
# SDL window stuff # 
SDL_Init(SDL_INIT_VIDEO) 
window = SDL_CreateWindowFrom(embed.winfo_id()) 
renderer = SDL_CreateRenderer(window, -1, 0) 
SDL_SetRenderDrawColor(renderer, ctypes.c_ubyte(255), ctypes.c_ubyte(255),  
                                ctypes.c_ubyte(255), ctypes.c_ubyte(255)) 
SDL_RenderClear(renderer) 
event = SDL_Event() 
draw() 
 
while True: 
    sdl_update() 
    root.update() 

上面的例子表明你可以创建你的 tkinter GUI,然后初始化你的 pySDL2 代码,从你想要的任何框架或窗口创建一个窗口,在这种情况下,我选择使用我创建的框架,称为 embed。使用可用的 winfo_id() 函数(请参阅 tkinter 文档)我们可以获得窗口的句柄。 draw() 函数只是使用渲染模块进行绘图。请注意,对于需要某些类型的 SDL2 函数,ctypes 用于以 SDL2 需要的方式格式化这些参数。在主 while 循环中,调用 sdl_update() 函数检查 SDL 事件。接下来是根窗口 (tkinter) 更新调用。 我们创建的 Button 将其命令链接到 draw(),当您单击此按钮时,SDL2 窗口链接到的框架中会出现一条随机颜色的线。 此代码改编自 This SO answer from PythonNut regarding pygame and tkinter .该代码最初由用户 Alex Sallons 提供.