如何在我的Tkinter GUI应用程序中嵌入一个SDL2窗口?

3
我正在尝试通过pySDL2将SDL2窗口嵌入到我的Tkinter应用程序中。如何设置我的pySDL2窗口和渲染器,以便我的渲染或绘图出现在嵌入的框架内?
其他示例已经展示了如何使用pygame实现,但我发现我的pygame版本目前无法与SDL2正常配合工作。我知道有其他pygame实现正在尝试实现SDL2,但SDL2的兼容性对我来说非常重要。
一个工作得很好的例子是,在Tkinter窗口中的一个框架拥有一个屏幕,在点击按钮时,通过pySDL2 API向框架绘制一些东西。当尝试使用在其他地方找到的pygame解决方案时,我收到了一些不同的错误,包括BadWindow、BadDrawable(与X服务器函数相关)。

你好,欢迎来到 Stack Overflow!请在你的问题中添加有意义的代码。发布一个展示你问题的 最小完整可验证示例(MCVE) 将有助于你获得更好的答案。更多信息请参见 [提问指南]。 - Daniele Santi
谢谢Shunz先生。我创建了这个问题来回答自己的问题,以便将来参考。如果有其他更好的方法,包括将代码放在我的问题中,我也非常乐意这样做。 - tweedismyfavoritecolor
没问题!通常,您会想添加相关的代码,以便其他人更容易地帮助您解决问题。但在这种情况下,显然不需要。 - Daniele Santi
1个回答

5

很难找到这方面的例子,所以希望这个答案能帮助其他人。在使用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窗口链接的帧中。 这段代码改编自PythonNut关于pygame和tkinter的这个SO答案。该代码最初由用户Alex Sallons编写。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接