Last active
September 1, 2022 01:57
-
-
Save LennyPhoenix/57344a0e049c2371622e31095bde87ed to your computer and use it in GitHub Desktop.
Using Tkinter and Pyglet in the same program
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
This version uses `Window.set_visible` instead of deleting the window, | |
so the default event loop can be used and the `on_close` event does not | |
need to be overridden. | |
""" | |
import threading | |
import pyglet | |
import tkinter | |
class Application: | |
def __init__(self): | |
# Create a window and register event handlers | |
self.pyglet_win = Window() | |
self.pyglet_win.push_handlers(self) | |
def create_tkinter_menu(self): | |
# Create the tkinter menu and register event handlers | |
self.menu = TkinterMenu() | |
self.menu.push_handlers(self) | |
# Start the tkinter mainloop | |
self.menu.run() | |
# Event called when the pyglet window is ready to pass over to the tkinter window | |
def on_pyglet_done(self): | |
self.create_tkinter_menu() | |
# Event called when the tkinter window is ready to pass back over to the pyglet window | |
def on_tkinter_done(self): | |
self.pyglet_win.set_visible(True) | |
# Start the event loop | |
def run(self): | |
pyglet.app.run() | |
# Generic window subclass with some events to pass to the Application | |
class Window(pyglet.window.Window, pyglet.event.EventDispatcher): | |
def __init__(self): | |
super().__init__() | |
self.label = pyglet.text.Label("Press ENTER") | |
def on_draw(self): | |
self.clear() | |
self.label.draw() | |
def on_key_release(self, symbol, modifiers): | |
if symbol == pyglet.window.key.ENTER: | |
self.set_visible(False) # Hide the window | |
self.dispatch_event("on_pyglet_done") | |
Window.register_event_type("on_pyglet_done") | |
# Class to handle the Tkinter side of things | |
class TkinterMenu(pyglet.event.EventDispatcher): | |
def __init__(self): | |
self.tk = tkinter.Tk() | |
# Register close protocol handler | |
self.tk.protocol("WM_DELETE_WINDOW", self.close_callback) | |
# Make a button | |
self.button = tkinter.Button(text="Press me!", command=self.button_callback) | |
self.button.pack() | |
# Helper function to get the pyglet thread to call a function. | |
# Always do | |
# self.schedule(self.dispatch_event, "on_closed") | |
# Instead of | |
# self.dispatch_event("on_closed") | |
def schedule(self, func, *args): | |
pyglet.clock.schedule_once(lambda dt: func(*args), 0) | |
# Called when the user tries to close the window manually | |
def close_callback(self): | |
# Exit the event loop | |
self.schedule(pyglet.app.exit) | |
self.tk.destroy() | |
# Hand over to the pyglet window | |
def button_callback(self): | |
self.schedule(self.dispatch_event, "on_tkinter_done") | |
self.tk.destroy() | |
# Start the mainloop in *another thread* | |
def run(self): | |
self.thread = threading.Thread(target=self.tk.mainloop) | |
self.thread.run() | |
TkinterMenu.register_event_type("on_tkinter_done") | |
# Start the application | |
if __name__ == "__main__": | |
app = Application() | |
app.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import threading | |
import pyglet | |
import tkinter | |
class Application: | |
def __init__(self): | |
# Instance the event loop | |
self.event_loop = pyglet.app.EventLoop() | |
# Create our starter window, we could technically start with tkinter here | |
self.create_pyglet_window() | |
def create_pyglet_window(self): | |
# Create a window and register event handlers | |
self.pyglet_win = Window() | |
self.pyglet_win.push_handlers(self) | |
def create_tkinter_menu(self): | |
# Create the tkinter menu and register event handlers | |
self.menu = TkinterMenu() | |
self.menu.push_handlers(self) | |
# Start the tkinter mainloop | |
self.menu.run() | |
# Event called when the pyglet window is ready to pass over to the tkinter window | |
def on_pyglet_done(self): | |
self.create_tkinter_menu() | |
# Event called when the tkinter window is ready to pass back over to the pyglet window | |
def on_tkinter_done(self): | |
self.create_pyglet_window() | |
# Event called when either window is closed manually by the user | |
def on_closed(self): | |
self.stop() | |
# Start the event loop | |
def run(self): | |
self.event_loop.run() | |
def stop(self): | |
# Stop the event loop | |
self.event_loop.exit() | |
# Generic window subclass with some events to pass to the Application | |
class Window(pyglet.window.Window, pyglet.event.EventDispatcher): | |
def __init__(self): | |
super().__init__() | |
self.label = pyglet.text.Label("Press ENTER") | |
def on_draw(self): | |
self.clear() | |
self.label.draw() | |
# Called when the user tries to close the window manually | |
def on_close(self): | |
self.close() | |
self.dispatch_event("on_closed") | |
def on_key_press(self, symbol, modifiers): | |
if symbol == pyglet.window.key.ENTER: | |
self.close() | |
self.dispatch_event("on_pyglet_done") | |
Window.register_event_type("on_pyglet_done") | |
Window.register_event_type("on_closed") | |
# Class to handle the Tkinter side of things | |
class TkinterMenu(pyglet.event.EventDispatcher): | |
def __init__(self): | |
self.tk = tkinter.Tk() | |
# Register close protocol handler | |
self.tk.protocol("WM_DELETE_WINDOW", self.close_callback) | |
# Make a button | |
self.button = tkinter.Button(text="Press me!", command=self.button_callback) | |
self.button.pack() | |
# Helper function to get the pyglet thread to call a function. | |
# Always do | |
# self.schedule(self.dispatch_event, "on_closed") | |
# Instead of | |
# self.dispatch_event("on_closed") | |
def schedule(self, func, *args): | |
pyglet.clock.schedule_once(lambda dt: func(*args), 0) | |
# Called when the user tries to close the window manually | |
def close_callback(self): | |
self.schedule(self.dispatch_event, "on_closed") | |
self.tk.destroy() | |
def button_callback(self): | |
self.schedule(self.dispatch_event, "on_tkinter_done") | |
self.tk.destroy() | |
# Start the mainloop in *another thread* | |
def run(self): | |
self.thread = threading.Thread(target=self.tk.mainloop) | |
self.thread.run() | |
TkinterMenu.register_event_type("on_tkinter_done") | |
TkinterMenu.register_event_type("on_closed") | |
# Start the application | |
if __name__ == "__main__": | |
app = Application() | |
app.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment