3

I'm creating a game app and it has a menu window then a separate game window. I'm trying to get a Tkinter window to act as the menu and a pygame window for the game however if the game is running, I cant use the menu (can't even close it). If I try I get a fatal error message:

Fatal Python error: PyEval_RestoreThread: the function must be called with the GIL held, but the GIL is released (the current Python thread state is NULL)
Python runtime state: initialized

Current thread 0x00002afc (most recent call first):
  File "c:\Users\James\Documents\6th form\comp sci\NEA- A Level\code\gametst.py", line 12 in main
  File "c:\Users\James\Documents\6th form\comp sci\NEA- A Level\code\Menu.py", line 15 in chess
  File "C:\Users\James\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1884 in __call__
  File "C:\Users\James\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1421 in mainloop
  File "c:\Users\James\Documents\6th form\comp sci\NEA- A Level\code\Menu.py", line 22 in <module>

This is the minimum code to reproduce:

Menu:

from tkinter import *
import game

WIN = Tk()
WIN.geometry("200x200")

def f():
    game.main()

button = Button(WIN, text="button", command=f)
button.pack()

WIN.mainloop()

game:

def main():
    import pygame
    pygame.init()

    WIN = pygame.display.set_mode((200, 200))

    run = 1
    while run:
        pygame.display.update()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = 0
                pygame.quit()

Is there a way to do this so that I can use the menu and the game at the same time? thx for any help

also if you know a better way to import the game to the menu that would be great, not overly bothered about that though

7
  • 2
    I think you will be much better off if you just try building the whole UI in Pygame. Commented May 13, 2021 at 21:59
  • Or running the pygame part in a separate thread should suffice too Commented May 13, 2021 at 22:00
  • do you compile the codes? I think if you build both of them as .exe and then run it, it will be okay. Commented May 13, 2021 at 22:01
  • @James.L if you just run main() without anything else does it still produce the problem? Commented May 13, 2021 at 22:03
  • @TheLizzard If he just runs the main() there would be no menu to freeze up, to me it seems that main() with its while loop is blocking WIN.mainloop(), actually it would be rather unseen but he could try using after() loops to run pygame, couldn't he? Commented May 13, 2021 at 22:05

2 Answers 2

4

You can run the pygame part in a thread:

game.py

import pygame

def main():
    pygame.init()

    WIN = pygame.display.set_mode((200, 200))
    run = 1
    while run:
        pygame.display.update()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = 0
                pygame.quit()
    print("pygame done")

def terminate():
    if pygame.get_init():
        pygame.event.post(pygame.event.Event(pygame.QUIT))

Note that I have added terminate() function for stopping the pygame loop.

menu.py

from tkinter import *
import game

WIN = Tk()
WIN.geometry("200x200")

def f():
    import threading
    # execute the pygame stuff in a thread
    threading.Thread(target=game.main).start()

button = Button(WIN, text="button", command=f)
button.pack()

WIN.mainloop()
game.terminate()  # terminate pygame loop
Sign up to request clarification or add additional context in comments.

2 Comments

this is great thanks! but do you know if there is a way to check if the game window s running from the menu? this is because when you press the button while the game is running it stops responding. I tried using the terminate function but it still stops responding.
never-mind, i used the is_alive() function. so thanks for you help
2

Well you can try to start it in another process. That way pygame will have no idea that tkinter has started it. You can try something like this:

# menu.py
from tkinter import *
from subprocess import Popen
from sys import stdin, stdout, stderr

window = Tk()
window.geometry("200x200")

def f():
    proc = Popen("python game.py", stdin=stdin, stdout=stdout, stderr=stderr, shell=True)

button = Button(window, text="button", command=f)
button.pack()

window.mainloop()

and:

# game.py
# Please note this isn't in a function.
import pygame
pygame.init()

WIN = pygame.display.set_mode((200, 200))

run = True
while run:
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
            pygame.quit()

The problem is that it isn't going to work if you start it in IDLE. So solve that issue remove the stdin=stdin, stdout=stdout, stderr=stderr and it should work.

With this approach you wouldn't be able to send any data between menu.py and game.py. The only thing you can do is call proc_still_alive = (proc.poll() == None) to see if the process is still alive. For that you will need to make proc a global variable.

2 Comments

Note that .poll() returns None when the process is still running. So has_proc_ended = proc.poll() is not None should be used instead.
@acw1668 You are right. Thanks for the suggestion. Next time feel free to edit it :D. I think my brain died

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.