For my project, I have a Tkinter window as the main menu, from which, a pygame window can be launched. In the pygame window, a simulation runs with a conditional infinite main loop.
I want to have a stop functionality so that the user can close the pygame window and be able to start a new one, however, if I call pygame.quit()
(or sys.exit()
or pygame.display.quit()
) in the pygame program, it closes the Tkinter window as well, which I'd want to stay open.
I have tried to embed the pygame program into a Toplevel
window, but after I stop the pygame main loop and call destroy()
on the Toplevel
window it closes, but the main Tk window freezes and will not respond to any user input, but code execution continues after calling destroy()
.
Pygame
Main loop
def run(self):
while not self.exit_flag:
self.display.fill(GREY)
self.draw_text()
self.draw_obstacles()
self.pygame_event_check() # a method for checking if event.type == pygame.QUIT
if self.running: #self.running is for pausing the window
if self.counter >= self.lifespan: # create new generation for simulation
self.counter = 0
new_generation, finished = self.rocket_pop.selection()
self.rocket_pop = Population(new_generation)
time.sleep(1)
self.gen_count += 1
if finished > 0 and self.reached_goal == False: # tracking the first generation to reach the goal
print(f"Reached the goal in {self.gen_count} generations")
self.reached_goal = True
for rocket in self.rocket_pop.population: # runs the update method on all individuals
rocket.update(self.counter)
self.counter += 1 # keeping track of the lifetime of the rockets
self.clock.tick(self.fps)
pygame.draw.circle(self.display, PINK, self.target, 20) # draw the goal
pygame.display.update()
print("exit")
Simulation start procedure
def run():
main = Main()
mThread = threading.Thread(target=main.run) # I get a "PyEval_RestoreThread: NULL tstate" error if I just call main.run()
mThread.start()
mThread.join()
Tkinter
Setup
import tkinter as tk
from genetic_stuff import *
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master=master)
self.master = master
self.pack()
self.setup()
def setup(self):
start = tk.Button(self.master, text="Start", command = self.run_simulation)
stop = tk.Button(self.master, text="Stop", command = self.stop_simulation)
start.place(x=10, y=10, w=100, h=45)
stop.place(x=240, y=10, w=100, h=45)
...
root = tk.Tk()
app = Application(master=root)
app.mainloop()
Start/ Stop simulation
def run_simulation(self):
self.sim_window = tk.Toplevel(self.master)
embed = tk.Frame(self.sim_window, width = Main.window_width, height = Main.window_height)
embed.pack()
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'
run()
self.sim_window.update()
def stop_simulation(self):
Main.exit_flag = True
self.sim_window.destroy()
self.sim_window.update()
links to pastebins of full code for replicating:
pics for reference: