3

pySDL2 を使用して、SDL2 ウィンドウを Tkinter アプリケーションに埋め込もうとしています。レンダリングまたは描画が埋め込みフレーム内に表示されるように、pySDL2 ウィンドウ、レンダラーをセットアップするにはどうすればよいですか?

pygame の他の例が示されていますが、私のバージョンの pygame が現在 SDL2 で適切に動作しないことがわかりました。SDL2 を実装しようとしている pygame の他の実装があることは理解していますが、SDL2 との互換性は私にとって最も重要です。

これが正しく機能する例は、ボタンがクリックされると、pySDL2 API を介してフレームに何かを描画する画面を持つ Tkinter ウィンドウのフレームです。他の場所で見つかった pygame ソリューションを使用しようとすると、BadWindow、BadDrawable (X サーバー機能に関連) など、いくつかの異なるエラーを受け取りました。

4

1 に答える 1

3

この例を見つけるのは困難だったので、この回答が他の人に役立つことを願っています。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 関数では、SDL2ctypesが期待する方法でこれらのパラメータをフォーマットするために使用されることに注意してください。メインの while ループでは、sdl_update()関数の呼び出しによって SDL イベントがチェックされます。これに続いて、ルート ウィンドウ (tkinter) の update 呼び出しが行われます。作成したButtonには、そのコマンドがリンクされていますdraw()このボタンをクリックすると、SDL2 ウィンドウがリンクされているフレームにランダムな色の線が表示されます。このコードは、 pygame および tkinter に関する PythonNut からの This SO answer から改作されました。このコードは、元はユーザーAlex Sallonsによるものでした。

于 2019-01-28T15:07:09.563 に答える