Embedding a Pygame window into a Tkinter or WxPython frame
Solution 1
(Note this solution does not work on Windows systems with Pygame 2. See Using 'SDL_WINDOWID' does not embed pygame display correctly into another application #1574. You can currently download older versions of Pygame here.)
According to this SO question and the accepted answer, the simplest way to do this would be to use an SDL drawing frame.
This code is the work of SO user Alex Sallons.
import os
import pygame
import Tkinter as tk
from Tkinter import *
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)
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'
screen = pygame.display.set_mode((500,500))
screen.fill(pygame.Color(255,255,255))
pygame.display.init()
pygame.display.update()
def draw():
pygame.draw.circle(screen, (0,0,0), (250,250), 125)
pygame.display.update()
button1 = Button(buttonwin,text = 'Draw', command=draw)
button1.pack(side=LEFT)
root.update()
while True:
pygame.display.update()
root.update()
This code is cross-platform, as long as the windib
SDL_VIDEODRIVER line is omitted on non Windows systems. I would suggest
# [...]
import platform
if platform.system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
# [...]
Solution 2
Here are some links.
- For embedding in WxPython An Article on
pygame.org
- For Embedding in WxPython An Article on the
WxPython wiki
- For embedding in Tkinter see this SO question
Basically, there are many approaches.
- On Linux, you can easily
embed
any application in a frame inside another. Simple. - Direct Pygame output to a WkPython Canvas
Some research will provide the relevant code.
Solution 3
According to the tracebacks, the program crashes due to TclErrors. These are caused by attempting to access the same file, socket, or similar resource in two different threads at the same time. In this case, I believe it is a conflict of screen resources within threads. However, this is not, in fact, due to an internal issue that arises with two gui programs that are meant to function autonomously. The errors are a product of a separate thread calling root.update() when it doesn't need to because the main thread has taken over. This is stopped simply by making the thread call root.update() only when the main thread is not doing so.
Related videos on Youtube
Comments
-
AHuman over 2 years
A friend and I are making a game in pygame. We would like to have a pygame window embedded into a tkinter or WxPython frame, so that we can include text input, buttons, and dropdown menus that are supported by WX or Tkinter. I have scoured the internet for an answer, but all I have found are people asking the same question, none of these have been well answered.
What would be the best way implement a pygame display embedded into a tkinter or WX frame? (TKinter is preferable)
Any other way in which these features can be included alongside a pygame display would also work.
-
AHuman about 10 yearsI have looked at all of these if you are wondering. However, none answer the simple question of how to make a very basic window with a frame with pygame in it.
-
PythonNut about 10 yearsI'm going to assume you use Windows, because you don't say. Does the code example (for windows) on the WxPython page work? If not, what does happen?
-
AHuman about 10 yearsFYI: The guy offering the bounty won't reward it to anyone unless the answer is REALLY good.
-
PythonNut about 10 yearsYea, I kinda guessed that. In fact, I think it would be wrong for me to get a lot of rep for a pathetic answer. This is however, the only answer ATM. I'm trying to help anyway.
-
PythonNut about 10 yearsAlso, AFAIK, someone-or-other has already found this which pretty much does what you want.
-
AHuman about 10 yearsStill, if you just post that code you will get 150 rep.
-
trevorKirkby about 10 yearsThe code in the second answer (and on a rather informative other stack overflow question) actually has raised some strange errors. While this works for some time, after a while the program either stops responding with no exceptions raised, or closes with either "Fatal Python error: (pygame parachute) Segmentation Fault " or various TclErrors associated with calling root.update()
-
PythonNut about 10 yearsHm... I was warned that
pygame
does not like running in any thread other than the main thread, which could very well be what's going on. I'll look into it, but it may be an inherent flaw in thepygame
code. p.s. You are using Windows, right? I never really got info on your current setup. -
PythonNut about 10 yearsTry replacing the loop at the end with
root.after(0,pygame.display.update)
. -
trevorKirkby about 10 yearsWould I then use root.mainloop()? I may have some other things I need to do in the mainloop, but I could use root.after on them too. I'll try this, though I am not sure how root.update would cause errors...
-
trevorKirkby about 10 yearsYes the platform is windows
-
trevorKirkby about 10 yearsAlso, unless some of the problems pertain to event handling, which I changed, there shouldn't be any issues with the code, as the same code works fine outside of tkinter...
-
PythonNut about 10 yearsNo, it should replace it. You can create a function that calls
pygame.display.update
and pass that toroot.after
instead. I'm not clear howroot.update
is causing errors either. It's strange... -
PythonNut about 10 yearsAh, no I meant code in the pygame core... aka. out of your control.
-
trevorKirkby about 10 yearsI understand that this will call update (along with any other functions I may want to call) however, will that really function to update root as well as call these things? I admit to having more experience with setting timers like this in wx, but in wx you set up the timer and start root.mainloop(). I'll try a few ways ofdoing it though. It is strange that root.update() causes problems, but one or two other pages hint at this.
-
trevorKirkby about 10 yearsSo it seems that root.after will schedule a timer for the function. This won't really replace root.update, however, unless there is a way to make it repeatedly reset the timer and run periodically, making it able to use root.mainloop()
-
trevorKirkby about 10 yearsI have the a function called by after that calls itself in after. I am getting an error, "TclStackFree: incorrect freePtr. Call out of sequence?" I notice that this happened immediately when I had no delay on the timer, but when I set it to run at the rate I want the everything to update, it took a few seconds while it seemed to work. Is this error something like a maximum recursion error then?
-
PythonNut about 10 yearsIf you suspect recursion, just print the recursion depth at every invocation.
-
trevorKirkby about 10 yearsIt crashed at recursion #309. The recursion limit of python in general is 1000, and I don't think tkinter has a special recursion limit of exactly 309 times.
-
PythonNut about 10 years
-
trevorKirkby about 10 yearsI do, in fact, have a second thread running, though it is not what would cause the TclError. I believe what is happening is that the functions are being called close enough together back to back that they are both trying to update the screen at the same time.
-
trevorKirkby about 10 yearsBy the way why would the use of after() and root.mainloop() be better than calling root.update()?
-
trevorKirkby about 10 yearsI tried doubling the wait between running the function again. The error still happened. It actually happened after fewer recursions.
-
trevorKirkby about 10 yearsI am, in fact, also working with a great many sockets, however, I know for a fact that they are not causing the problem, as this particular error only arose from "root.after()"
-
PythonNut about 10 years1. It was a suggestion from the original SO thread. The treads may be internal Tcl/pygame etc. threads that you do not control. Call the functions every other update, then just for laughs and see if that fixes anything. At think point, I'm not going to be very helpful... :(
-
trevorKirkby about 10 yearsThe program stopped responding on the time when I did not call my display.updates and event.pumps. This is only one of the errors that can happen, however, it appears that it is caused no matter what in the combination in pygame. This seems strange, because I would have thought that the person who used the code posted on the above answer would not have had this problem, or they would have mentioned it or perhaps fixed it, as they were the one who had also answered their question.
-
PythonNut about 10 yearsIs the issue specific to your code? I take it the posted code verbatim also has issues.
-
PythonNut about 10 yearsHave you seen this? It takes a different approach and may be worth a look.