我正在尝试通过pySDL2将SDL2窗口嵌入我的Tkinter应用程序中。如何设置pySDL2窗口,渲染器,以便渲染或绘图出现在嵌入式框架中?
还显示了pygame的其他示例,但是我发现pygame的当前版本无法在SDL2上正常使用。我知道还有其他pygame实现正在尝试实现SDL2,但是与SDL2的兼容性对我来说至关重要。
此工作正常的示例是Tkinter窗口中的框架,该框架具有屏幕,单击按钮时,该屏幕会通过pySDL2 API在框架上绘制一些内容。 在尝试使用其他地方提供的pygame解决方案时,我遇到了一些不同的错误,包括BadWindow,BadDrawable(与X服务器功能有关)。
答案 0 :(得分:0)
很难找到例子,所以希望这个答案对其他人有帮助。在使用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()
函数仅使用render模块进行绘制。请注意,对于需要某些类型的SDL2函数,ctypes
用于以SDL2期望的方式格式化这些参数。在主while循环中,对sdl_update()
函数的调用检查SDL事件。随后是根窗口(tkinter)更新调用。
我们创建的Button
的命令已链接到draw()
,并且当您单击此按钮时,SDL2窗口链接到的框架中会出现一条随机着色的线。
该代码改编自This SO answer from PythonNut regarding pygame and tkinter。该代码最初由用户Alex Sallons所提供。