【问题标题】:How can I embed an SDL2 window in my Tkinter GUI application?如何在我的 Tkinter GUI 应用程序中嵌入 SDL2 窗口?
【发布时间】:2019-06-21 14:14:20
【问题描述】:

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

已经展示了 pygame 的其他示例,但我发现我的 pygame 版本目前不能与 SDL2 正常工作。我知道还有其他的 pygame 实现正在尝试实现 SDL2,但与 SDL2 的兼容性对我来说是最重要的。

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

【问题讨论】:

  • 您好,欢迎来到 Stack Overflow!请为您的问题添加有意义的代码。发布证明您的问题的Minimal, Complete, and Verifiable example (MCVE) 将帮助您获得更好的答案。有关详细信息,请参阅How to Ask
  • 谢谢顺茨先生。我创建了这个问题来回答我自己的问题以供将来参考。如果有其他方法我应该解决这个问题,包括将代码放在我的问题中,我很乐意这样做。
  • 没问题!通常,您需要添加遇到问题的相关代码,以便其他人更容易帮助您。在这种情况下,显然没有必要。

标签: python tkinter pysdl2


【解决方案1】:

这方面的例子很难找到,所以希望这个答案能帮助其他人。在使用 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 提供。

【讨论】:

    猜你喜欢
    • 2021-11-23
    • 1970-01-01
    • 2014-03-21
    • 2017-03-17
    • 2023-04-01
    • 2011-02-06
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    相关资源
    最近更新 更多