Python Forum
[Tkinter] How can I use Tkinter with pygame
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] How can I use Tkinter with pygame
#1
Hi everyone,

Can anyone help me so the code works with pygame and Tkinter (seemingly) simultaneously? Confused I'm also interested in formatting the text and using the appropriate methods, anything to assist would be greatly appreciated Angel .

I'm working on introducing Tkinter into my pygame project to make it easier to test and debug. I normally send the information to the Python shell window but thought it would be much cooler to have the information neatly displayed in a seperate window, ideally having the pygame window doing its thing, while keeping an eye on (some of) the variables in the Tkinter window.

I've done the pygame stuff already Smile , and have got as far as launching the Tkinterwindow Think (incorrectly I imagine).


import tkinter
import pygame

pygame.init()

pwbr_power = 0
pwbr_duration = 0
pwbr_scrn_refresh = 0
pwbr_elps_time = 0
pwbr_ttl_sec = 0


def fn_pbtkwin_update():
    """
    Updates the status information in the tkinter window.
    """
    
    global pwbr_power, pwbr_duration, pwbr_scrn_refresh, pwbr_elps_time
    global pwbr_ttl_sec
    
    pwbr_power += 1
    pwbr_duration += 0.15
    pwbr_elps_time += pwbr_duration
    pwbr_scrn_refresh = 0.333
    pwbr_ttl_sec += pwbr_elps_time

    if pwbr_elps_time > pwbr_scrn_refresh:
        pwbr_elps_time = 0
        pwbr_duration = 0

    caption_pwr = "Power: " + str(pwbr_power)
    caption_dur = "Duration: " + str(pwbr_duration)
    caption_rfrsh =  "Screen Refresh: " + str(pwbr_scrn_refresh)
    caption_etime = "Elapsed time: " + str(pwbr_elps_time)
    caption_ttl = "Total sec's: " + str(pwbr_ttl_sec)
    tkinter.Label(tkwin, text=caption_pwr, fg="black").grid(row=0, column=0)
    tkinter.Label(tkwin, text=caption_dur, fg="black").grid(row=1, column=0)
    tkinter.Label(tkwin, text=pwbr_scrn_refresh, fg="black").grid(row=2, column=0)
    tkinter.Label(tkwin, text=caption_etime, fg="black").grid(row=3, column=0)
    tkinter.Label(tkwin, text=caption_ttl, fg="black").grid(row=4, column=0)

    tkwin.after(1000, fn_pbtkwin_update)
# fn_pbtkwin_update() ----------------------------------------------------------


tkwin = tkinter.Tk()
tkwin.title("Power Bar")
tkinter.Label(tkwin, text = "Power: 0", fg = "black").grid(row=0, column=0)
tkinter.Label(tkwin, text = "Duration: 0", fg = "black").grid(row=1, column=0)
tkinter.Label(tkwin, text = "Screen Refresh: 0", fg = "black").grid(row=2, column=0)
tkinter.Label(tkwin, text = "Elapsed time: 0", fg = "black").grid(row=3, column=0)
tkinter.Label(tkwin, text = "Total sec's: 0", fg = "black").grid(row=4, column=0)

tkinter.Label(tkwin, text = "Fully charged: False", fg = "black").grid(row=0, column=3)
tkinter.Label(tkwin, text = "Reactor overloading: False", fg = "black").grid(row=1, column=3)
tkinter.Label(tkwin, text = "Power bar status: Normal", fg = "black").grid(row=2, column=3)

tkinter.Label(tkwin, text = "Press [Spacebar] to simulate firing phaser cannons.", fg = "black").grid(row=6, column=1)
tkinter.Label(tkwin, text = "Press [r] to initiate a reactor overload.", fg = "black").grid(row=7, column=1)
tkinter.Label(tkwin, text = "Press [Esc] to quit.", fg = "black").grid(row=7, column=1)
tkwin.after(1000, fn_pbtkwin_update)

pygame.time.wait(1000)
pygame.display.set_mode((640, 480))

quit_loop = False
while quit_loop is not True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:  # If user clicked close
            quit_loop = True  # Flag that we are done so we exit this loop
        elif event.type == pygame.MOUSEBUTTONUP:
            pass
        elif event.type == pygame.constants.KEYDOWN:
            if event.key == pygame.constants.K_ESCAPE:
                quit_loop = True
                break
            elif event.key == pygame.constants.K_LEFT:
                kbd["left"] = True
            elif event.key == pygame.constants.K_RIGHT:
                kbd["right"] = True
            elif event.key == pygame.constants.K_UP:
                kbd["up"] = True
            elif event.key == pygame.constants.K_DOWN:
                kbd["down"] = True
            elif event.key == pygame.constants.K_SPACE:  # Fire.
                kbd["fire"] = True
            elif event.key == pygame.constants.K_LCTRL:  # Thrust.
                kbd["thrust"] = True
            elif event.key == pygame.constants.K_r:
                kbd["overload"] = True
        elif event.type == pygame.constants.KEYUP:
            if event.key == pygame.constants.K_LEFT:
                kbd["left"] = False
            elif event.key == pygame.constants.K_RIGHT:
                kbd["right"] = False
            elif event.key == pygame.constants.K_UP:
                kbd["up"] = False
            elif event.key == pygame.constants.K_DOWN:
                kbd["down"] = False
            elif event.key == pygame.constants.K_SPACE:  # Fire.
                kbd["fire"] = False
            elif event.key == pygame.constants.K_LCTRL:  # Thrust.
                kbd["thrust"] = False
            elif event.key == pygame.constants.K_r:
                kbd["overload"] = False
            # end if
        # end if
    # end for loop

    # { Paint some graphics on the screen.
    #   ...
    # }.
    pygame.display.flip()
    
    tkwin.mainloop()
    
# end while loop
Reply
#2
Looks like I was way off Doh . I did read something about backward compatibility but I didn't realise by just how much.

I think I should have started off with something like this Think :
#!/usr/bin/env python
import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.grid()
        self.createwidgets()

    def createwidgets(self):
        self.quitButton = tk.Button(self, text='Quit', command=self.quit)
        self.quitButton.grid()

app = Application()
app.master.title('Sample application')
app.mainloop()
Now all I need to do add the extra controls as before, and learn how to update the label's text attribute, to get to where I was before.
Reply
#3
Making progress but still not there yet.

The examples i've see so far only use the method "mainloop" which looks like a wait until tkinter window has finished Undecided . I need the code to visit the window temporarily (and not close it) before doing more of my other stuff in pygame Sad .

import tkinter as tk
import pygame

pygame.init()

pwbr_power = 0
pwbr_duration = 0
pwbr_scrn_refresh = 0
pwbr_elps_time = 0
pwbr_ttl_sec = 0

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.grid()
        self.createwidgets()
    # __init__() ---------------------------------------------------------------

    def createwidgets(self):
        """
        Creates the numerous widgets that make up the form.
        """
        
        global pwbr_power, pwbr_duration, pwbr_scrn_refresh, pwbr_elps_time
        global pwbr_ttl_sec
        
        pwbr_power += 1
        pwbr_duration += 0.15
        pwbr_elps_time += pwbr_duration
        pwbr_scrn_refresh = 0.333
        pwbr_ttl_sec += pwbr_elps_time

        if pwbr_elps_time > pwbr_scrn_refresh:
            pwbr_elps_time = 0
            pwbr_duration = 0

        caption_pwr = "Power: " + str(pwbr_power)
        caption_dur = "Duration: " + str(pwbr_duration)
        caption_rfrsh =  "Screen Refresh: " + str(pwbr_scrn_refresh)
        caption_etime = "Elapsed time: " + str(pwbr_elps_time)
        caption_ttl = "Total sec's: " + str(pwbr_ttl_sec)
        
        self.lblpower = tk.Label(self, text=caption_pwr, fg="black")
        self.lblduration = tk.Label(self, text=caption_dur, fg="black")
        self.lblrefreshrate = tk.Label(self, text=caption_rfrsh, fg="black")
        self.lbletime = tk.Label(self, text=caption_etime, fg="black")
        self.lbltotalsec = tk.Label(self, text=caption_ttl, fg="black")
        
        self.quitButton = tk.Button(self, text='Quit', command=self.quit)
        
        self.lblpower.grid()
        self.lblduration.grid()
        self.lblrefreshrate.grid()
        self.lbletime.grid()
        self.lbltotalsec.grid()
        self.quitButton.grid()
        self.update()
        
        self.after(1000, self.update_info)
    # createwidgets() ----------------------------------------------------------
    

    def update_info(self):
        """
        Updates the status information in the tkinter window.
        """
        
        global pwbr_power, pwbr_duration, pwbr_scrn_refresh, pwbr_elps_time
        global pwbr_ttl_sec
        
        pwbr_power += 1
        pwbr_duration += 0.15
        pwbr_elps_time += pwbr_duration
        pwbr_scrn_refresh = 0.333
        pwbr_ttl_sec += pwbr_elps_time

        if pwbr_elps_time > pwbr_scrn_refresh:
            pwbr_elps_time = 0
            pwbr_duration = 0

        caption_pwr = "Power: " + str(pwbr_power)
        caption_dur = "Duration: " + str(pwbr_duration)
        caption_rfrsh =  "Screen Refresh: " + str(pwbr_scrn_refresh)
        caption_etime = "Elapsed time: " + str(pwbr_elps_time)
        caption_ttl = "Total sec's: " + str(pwbr_ttl_sec)

        self.lblpower.config(text=caption_pwr)
        self.lblduration.config(text=caption_dur)
        self.lblrefreshrate.config(text=caption_rfrsh)
        self.lbletime.config(text=caption_etime)
        self.lbltotalsec.config(text=caption_ttl)

        self.after(1000, self.update_info)
    # update_info() ----------------------------------------------------------
# Application() ----------------------------------------------------------------


pygame.display.set_mode((640, 480))

app = Application()
app.master.title("Power Bar")
app.mainloop()



quit_loop = False
while quit_loop is not True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:  # If user clicked close
            quit_loop = True  # Flag that we are done so we exit this loop
        elif event.type == pygame.MOUSEBUTTONUP:
            pass
        elif event.type == pygame.constants.KEYDOWN:
            if event.key == pygame.constants.K_ESCAPE:
                quit_loop = True
                break
            elif event.key == pygame.constants.K_LEFT:
                kbd["left"] = True
            elif event.key == pygame.constants.K_RIGHT:
                kbd["right"] = True
            elif event.key == pygame.constants.K_UP:
                kbd["up"] = True
            elif event.key == pygame.constants.K_DOWN:
                kbd["down"] = True
            elif event.key == pygame.constants.K_SPACE:  # Fire.
                kbd["fire"] = True
            elif event.key == pygame.constants.K_LCTRL:  # Thrust.
                kbd["thrust"] = True
            elif event.key == pygame.constants.K_r:
                kbd["overload"] = True
        elif event.type == pygame.constants.KEYUP:
            if event.key == pygame.constants.K_LEFT:
                kbd["left"] = False
            elif event.key == pygame.constants.K_RIGHT:
                kbd["right"] = False
            elif event.key == pygame.constants.K_UP:
                kbd["up"] = False
            elif event.key == pygame.constants.K_DOWN:
                kbd["down"] = False
            elif event.key == pygame.constants.K_SPACE:  # Fire.
                kbd["fire"] = False
            elif event.key == pygame.constants.K_LCTRL:  # Thrust.
                kbd["thrust"] = False
            elif event.key == pygame.constants.K_r:
                kbd["overload"] = False
            # end if
        # end if
    # end for loop

    # { Paint some graphics on the screen.
    #   ...
    # }.
    pygame.display.flip()
# end while loop
Reply
#4
I think I've acquired enough here in this prototype. I'm going to go ahead and plug this bad boy into my game and start testing Dance .

Thank you all for your patience Smile .

import tkinter as tk
import pygame

pygame.init()

pwbr_power = 0
pwbr_duration = 0
pwbr_scrn_refresh = 0
pwbr_elps_time = 0
pwbr_ttl_sec = 0

pwbr_fcharged = False
pwbr_overload = False   # Reactor overload status.
pwbr_status = None


class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.grid()
        self.createwidgets()
    # __init__() ---------------------------------------------------------------


    def _cmd_quit(self):
        """
        Terminates the Tkwindow.
        """
        
        global quit_loop
        
        self.master.destroy()
        quit_loop = True
    # _cmd_quit() --------------------------------------------------------------

    
    def createwidgets(self):
        """
        Creates the numerous widgets that make up the form.
        """
        
        global pwbr_power, pwbr_duration, pwbr_scrn_refresh, pwbr_elps_time
        global pwbr_ttl_sec

        global pwbr_fcharged, pwbr_overload, pwbr_status

        col_width = None
        
        pwbr_power += 1
        pwbr_duration += 0.15
        pwbr_elps_time += pwbr_duration
        pwbr_scrn_refresh = 0.333
        pwbr_ttl_sec += pwbr_elps_time

        pwbr_fcharged = False
        pwbr_overload = False   # Reactor overload status.
        pwbr_status = "Normal"

        if pwbr_elps_time > pwbr_scrn_refresh:
            pwbr_elps_time = 0
            pwbr_duration = 0

        caption_pwr = "Power: " + str(pwbr_power)
        caption_dur = "Duration: " + str(pwbr_duration)
        caption_rfrsh =  "Screen Refresh: " + str(pwbr_scrn_refresh)
        caption_etime = "Elapsed time: " + str(pwbr_elps_time)
        caption_ttl = "Total sec's: " + str(pwbr_ttl_sec)

        caption_fcharged = "Fully charged: " + str(pwbr_fcharged)
        caption_overload = "Reactor overloading: " + str(pwbr_overload)
        caption_status = "Power bar status: " + str(pwbr_status)

        caption_hint1 = "Press [Spacebar] to simulate firing phaser cannons."
        caption_hint2 = "Press [r] to initiate a reactor overload."
        caption_hint3 = "Press [Esc] to quit"
        
        self.lblpower = tk.Label(self, text=caption_pwr, fg="black")
        self.lblduration = tk.Label(self, text=caption_dur, fg="black")
        self.lblrefreshrate = tk.Label(self, text=caption_rfrsh, fg="black")
        self.lbletime = tk.Label(self, text=caption_etime, fg="black")
        self.lbltotalsec = tk.Label(self, text=caption_ttl, fg="black")

        self.lblfcharged = tk.Label(self, text=caption_fcharged, fg="black")
        self.lbloverload = tk.Label(self, text=caption_overload, fg="black")
        self.lblstatus = tk.Label(self, text=caption_status, fg="black")

        self.lblhint1 = tk.Label(self, text=caption_hint1, fg="black")
        self.lblhint2 = tk.Label(self, text=caption_hint2, fg="black")
        self.lblhint3 = tk.Label(self, text=caption_hint3, fg="black")
        
        self.quitButton = tk.Button(self, text='Quit', command=self._cmd_quit)
        
        self.lblpower.grid(row=0, column=0, sticky="w")     #tk.W)
        self.lblduration.grid(row=1, column=0)
        self.lblrefreshrate.grid(row=2, column=0)
        self.lbletime.grid(row=3, column=0)
        self.lbltotalsec.grid(row=4, column=0)

        self.lblfcharged.grid(row=0, column=3)
        self.lbloverload.grid(row=1, column=3)
        self.lblstatus.grid(row=2, column=3)

        self.lblhint1.grid(row=6, column=2)
        self.lblhint2.grid(row=7, column=2)
        self.lblhint3.grid(row=8, column=2)

        # { Set the width for all the labels in column #1.
        col_width = 20
        self.lblpower["width"] = col_width
        self.lblduration["width"] = col_width
        self.lblrefreshrate["width"] = col_width
        self.lbletime["width"] = col_width
        self.lbltotalsec["width"] = col_width
        # }.

        # { Set the width for all the labels in column #3.
        col_width = 23
        self.lblfcharged["width"] = col_width
        self.lbloverload["width"] = col_width
        self.lblstatus["width"] = col_width
        # }.

        # { Set the text alignment for all the labels in column #1 & #2.
        self.lblpower["anchor"] = "w"
        self.lblduration["anchor"] = "w"
        self.lblrefreshrate["anchor"] = "w"
        self.lbletime["anchor"] = "w"
        self.lbltotalsec["anchor"] = "w"

        self.lblfcharged["anchor"] = "w"
        self.lbloverload["anchor"] = "w"
        self.lblstatus["anchor"] = "w"
        # }.

        # { Send the doc string information of the label object to the
        #   Python shell.
        print(help(self.lblpower))
        # }.
        
        self.quitButton.grid(row=6, column=3)

        # { Paint the image of the root / main TKinter window on the screen.
        self.update()
        # }.

        # { Set a timeout of a second to callback the routine
        #   update_info, so the labels are updated with the current (up to
        #   date) data values.
        self.after(1000, self.update_info)
        # }.
    # createwidgets() ----------------------------------------------------------
    

    def update_info(self):
        """
        Updates the status information in the tkinter window.
        """
        
        global pwbr_power, pwbr_duration, pwbr_scrn_refresh, pwbr_elps_time
        global pwbr_ttl_sec
        
        pwbr_power += 1
        pwbr_duration += 0.15
        pwbr_elps_time += pwbr_duration
        pwbr_scrn_refresh = 0.333
        pwbr_ttl_sec += pwbr_elps_time

        if pwbr_elps_time > pwbr_scrn_refresh:
            pwbr_elps_time = 0
            pwbr_duration = 0

        caption_pwr = "Power: " + str(pwbr_power)
        caption_dur = "Duration: " + str(pwbr_duration)
        caption_rfrsh =  "Screen Refresh: " + str(pwbr_scrn_refresh)
        caption_etime = "Elapsed time: " + str(pwbr_elps_time)
        caption_ttl = "Total sec's: " + str(pwbr_ttl_sec)

        self.lblpower.config(text=caption_pwr)
        self.lblduration["text"] = caption_dur
        self.lblrefreshrate.config(text=caption_rfrsh)
        self.lbletime.config(text=caption_etime)
        self.lbltotalsec.config(text=caption_ttl)

        self.after(1000, self.update_info)
    # update_info() ----------------------------------------------------------
# Application() ----------------------------------------------------------------


pygame.display.set_mode((640, 480))

app = Application()
app.master.title("Power Bar")
#app.mainloop()




quit_loop = False
while quit_loop is not True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:  # If user clicked close
            quit_loop = True  # Flag that we are done so we exit this loop
        elif event.type == pygame.MOUSEBUTTONUP:
            pass
        elif event.type == pygame.constants.KEYDOWN:
            if event.key == pygame.constants.K_ESCAPE:
                quit_loop = True
                break
            elif event.key == pygame.constants.K_LEFT:
                kbd["left"] = True
            elif event.key == pygame.constants.K_RIGHT:
                kbd["right"] = True
            elif event.key == pygame.constants.K_UP:
                kbd["up"] = True
            elif event.key == pygame.constants.K_DOWN:
                kbd["down"] = True
            elif event.key == pygame.constants.K_SPACE:  # Fire.
                kbd["fire"] = True
            elif event.key == pygame.constants.K_LCTRL:  # Thrust.
                kbd["thrust"] = True
            elif event.key == pygame.constants.K_r:
                kbd["overload"] = True
        elif event.type == pygame.constants.KEYUP:
            if event.key == pygame.constants.K_LEFT:
                kbd["left"] = False
            elif event.key == pygame.constants.K_RIGHT:
                kbd["right"] = False
            elif event.key == pygame.constants.K_UP:
                kbd["up"] = False
            elif event.key == pygame.constants.K_DOWN:
                kbd["down"] = False
            elif event.key == pygame.constants.K_SPACE:  # Fire.
                kbd["fire"] = False
            elif event.key == pygame.constants.K_LCTRL:  # Thrust.
                kbd["thrust"] = False
            elif event.key == pygame.constants.K_r:
                kbd["overload"] = False
            # end if
        # end if
    # end for loop

    # { Paint some graphics on the screen.
    #   ...
    # }.
    pygame.display.flip()
    app.master.update()
# end while loop

pygame.quit()
PS. That was a lot harder than I thought it was going to be Cry . I found the hardest thing getting this protype built was finding a complete reference guide of TKinter Dodgy .
Reply
#5
The first one is made with pygame, which runs smooth and is straight forward efficient. The second version made with tkinter is slow and laggy. I even had to batch edit pixels which does not help much. Both of them function exactly the same but the tkinter version is just not as fast.

# Used to store debug file
#import os
#BASE_DIR = os.path.realpath(os.path.dirname(__file__))


# Some config width height settings
canvas_width = 640
canvas_height = 480

# Create a window
window = Tk()
# Set the window title
window.wm_title("Sine Wave")

# Put a canvas on the window
canvas = Canvas(window, width=canvas_width, height=canvas_height, bg="#000000")
canvas.pack()

# Create a image, this acts as the canvas
img = PhotoImage(width=canvas_width, height=canvas_height)

# Put the image on the canvas
canvas.create_image((canvas_width/2, canvas_height/2), image=img, state="normal")



def sine_wave_anim():

# Update sine wave
frequency = 4
amplitude = 50 # in px
speed = 1

# We create a blank area for what where we are going to draw
color_table = [["#000000" for x in range(0, canvas_width)] for y in range(0, amplitude*2)]

# And draw on that area
for x in range(0, canvas_width):
y = int(amplitude + amplitude*math.sin(frequency*((float(x)/canvas_width)*(2*math.pi) + (speed*time.time()))))
color_table[y][x] = "#ffff00"

# Don't individually put pixels as tkinter sucks at this
#img.put("#ffff00", (x, y))

# Then batch put it on the canvas
# tkinter is extremely inefficient doing it one by one
img.put(''.join("{" + (" ".join(str(color) for color in row)) + "} " for row in color_table), (0, int(canvas_height/2 - amplitude)))

# Debug the color_table
#with open(os.path.join(BASE_DIR, 'output.txt'), "w+") as text_file:
# text_file.write(''.join("{" + (" ".join(str(color) for color in row)) + "} " for row in color_table))


# Continue the animation as fast as possible. A value of 0 (milliseconds), blocks everything.
window.after(1, sine_wave_anim)


# Start off the anim
sine_wave_anim()
mainloop()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Want to dynamically update numbers using tkinter in pygame script k0gane 0 2,035 Feb-09-2020, 09:01 AM
Last Post: k0gane

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020