Как я могу встроить окно SDL2 в мое приложение Tkinter GUI? - PullRequest
0 голосов
/ 28 января 2019

Я пытаюсь встроить окно SDL2 в мое приложение Tkinter через pySDL2.Как настроить окно pySDL2 для рендеринга таким образом, чтобы мой рендеринг или рисунок отображались во встроенной рамке?

Другие примеры приведены для pygame, но я обнаружил, что моя версия pygame в настоящее время не работает должным образом сSDL2.Я понимаю, что есть другие реализации Pygame, которые пытаются реализовать SDL2, но совместимость с SDL2 имеет для меня первостепенное значение.

Примером правильной работы этой работы может быть кадр в окне Tkinter с экраномкоторый при нажатии кнопки рисует что-то в кадре через API pySDL2.При попытке использовать решение Pygame, найденное в другом месте, я получил несколько разных ошибок, включая BadWindow, BadDrawable (связанные с функциями X-сервера.)

1 Ответ

0 голосов
/ 28 января 2019

Примеры для этого было трудно найти, поэтому, надеюсь, этот ответ поможет другим.При работе с API-оболочкой pySDL2 вам необходимо знать о 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, а затем инициализировать код pySDL2, создавая окно из любого кадра или окна, которые вы хотите, вВ этом случае я решил использовать созданную мной рамку, которая называется embed.Используя доступную функцию winfo_id() (см. Документацию tkinter), мы можем получить дескриптор окна.Функция draw() просто выполняет рисование с использованием модуля рендеринга.Обратите внимание, что для функций SDL2, которые ожидают определенных типов, ctypes используется для форматирования этих параметров способом, ожидаемым SDL2.В основном цикле while вызов функции sdl_update() проверяет наличие событий SDL.Затем следует вызов обновления корневого окна (tkinter).Созданная нами Button имеет команду, связанную с draw(), и когда вы нажимаете эту кнопку, в кадре, с которым связано окно SDL2, появляется случайно окрашенная линия.Этот код был адаптирован с Этот SO ответ от PythonNut относительно pygame и tkinter .Этот код был изначально пользователем Алекс Саллонс .

...