Posts: 63
Threads: 22
Joined: Aug 2017
Hi everyone,
Can anyone help me so the code works with pygame and Tkinter (seemingly) simultaneously? I'm also interested in formatting the text and using the appropriate methods, anything to assist would be greatly appreciated .
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 , and have got as far as launching the Tkinterwindow (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
Posts: 63
Threads: 22
Joined: Aug 2017
Looks like I was way off . 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 :
#!/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.
Posts: 63
Threads: 22
Joined: Aug 2017
May-01-2019, 06:13 PM
(This post was last modified: May-01-2019, 06:13 PM by microphone_head.)
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 . I need the code to visit the window temporarily (and not close it) before doing more of my other stuff in pygame .
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
Posts: 63
Threads: 22
Joined: Aug 2017
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 .
Thank you all for your patience .
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 . I found the hardest thing getting this protype built was finding a complete reference guide of TKinter .
Posts: 3
Threads: 0
Joined: May 2019
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()
|