I have a Tkinter GUI, which I have copy pasted from one of my other files.
The two GUI's are exact copies, 1:1. The first one works, the second doesn't.
This is the second file, with the TKinter GUI:
import mysql.connector
import threading
import tkinter as tk
import pip
import time
import mysql.connector
from time import sleep
global score
global countdown
en = "1"
score = 0
countdown = 1
tidMål = 0
tidScoreNu = 0
print("Hiya!")
mydb = mysql.connector.connect(
host="",
user="",
password="",
database='',
auth_plugin=''
)
mycursor = mydb.cursor(prepared=True)
#MysQl commands til at interface det hele
class Mysql(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
self.en = 1
self.læsTidScoreNu = "SELECT tidSCoreNu FROM bois WHERE id = 1"
self.læsTidMål = "SELECT tidMål FROM bois WHERE id = 1"
self.opdaterTidMål = "UPDATE bois SET tidMål = %s WHERE id = %s"
self.læsStopKnap = "SELECT stopKnap FROM bois WHERE id = 1"
self.run()
def run(self) -> None:
global mycursor
global mydb
mycursor.execute(self.læsTidScoreNu)
self.råTidScoreNu = mycursor.fetchone()
self.tidScoreNu = float("{}".format('%.2f' % self.råTidScoreNu))
mycursor.execute(self.læsTidMål)
self.råTidMål = mycursor.fetchone()
self.tidMål = float("{}".format('%.2f' % self.råTidMål))
mycursor.execute(self.læsStopKnap)
self.stopKnap = mycursor.fetchone()
mydb.commit()
#Control GUI til admin portalen
class Tkinter(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
self.root = 0
self.entry = 0
self.label = 0
self.button = 0
self.timerValue = 2
self.stopButton = 0
self.start()
self.spilSlut = 0
def run(self) -> 0:
self.root = tk.Tk()
global countdown
#Baggrund
self.root.geometry("+2+0")
self.root.config(background="Grey")
#Timervalue selectors
self.label = tk.Label(self.root, bg="white", fg="black", font=("Fixedsys", 28))
self.entry = tk.Entry(self.root, bg="white", fg="black", font=("Fixedsys", 28))
#Start/Stop Knapper
self.stopTiden = tk.Button(self.root, bg="red", fg="white", text="Stop Spillet", command=self.stopTid)
self.startTiden = tk.Button(self.root, bg="green", fg="white", text="Start Spillet", command=self.startTid)
#Timeren
self.timerDisplay = tk.Label(self.root, bg="black", fg="red", text="Spillet er ikke startet")
self.timerDisplay.grid(row=2, column=50)
self.startTiden.grid(row=0, column=1)
self.stopTiden.grid(row=0, column=10)
self.entry.grid(row=1, column=1)
self.label.grid(row=1, column=10)
self.root.bind("<KeyPress>", self.read)
self.Update(self)
self.root.mainloop()
def read(self, event):
key = event.keysym
try:
if key == "Return":
self.getA()
self.visTid()
except:
self.fejlTidvalg()
def startTid(self):
self.stopButton = 0
def getA(self):
try:
self.timerValue = float(self.entry.get().format("%.2f", 1.23456))
print(self.timerValue)
return self.timerValue
except:
print(fejl)
def stopTid(self):
self.stopButton = 1
print("Spillet er stoppet nu")
def visTid(self):
self.label.config(text="Det her er timerens slutværdi: {}".format(self.timerValue))
def fejlTidvalg(self):
self.label.config(text="FEJL -Vælg Venligst Et Tal")
def opdaterCountdown(self):
if self.stopButton != 1:
self.spilSlut = 0
self.tidTilbage = self.timerValue - countdown
self.tidTilbage_minutter = int(self.tidTilbage/60)
self.tidTilbage_sekunder = (self.tidTilbage) - (self.tidTilbage_minutter * 60)
self.timerDisplay.config(text="{} minutter, {:.2f} sekunder tilbage".format(self.tidTilbage_minutter, self.tidTilbage_sekunder))
if self.tidTilbage < 0 or self.tidTilbage == 0 and self.timerValue > 0:
self.spilSlut = 1
elif self.stopButton == 1:
self.timerDisplay.config(text="Spillet er sat på pause")
def opdaterCountdownSpilSlut(self):
self.timerDisplay.config(text="Spillet er slut")
class Update(threading.Thread):
def __init__(self, tkinter):
threading.Thread.__init__(self)
self.daemon = True
self.tkinter = tkinter
self.start()
def run(self) -> None:
while True:
time.sleep(0.1)
self.tkinter.opdaterCountdown()
if self.tkinter.spilSlut == 1:
self.tkinter.opdaterCountdownSpilSlut()
time.sleep(1)
tk = Tkinter()
data = Mysql()
while True:
print()
The error I get is this:
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\Mandem\AppData\Local\Programs\Python\Python38-32\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "C:/Users/Mandem/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/mysql/connector/PC-ADMIN-Camper.py", line 81, in run
self.label = tk.Label(self.root, bg="white", fg="black", font=("Fixedsys", 28))
AttributeError: 'Tkinter' object has no attribute 'Label'
I have been looking around the forum for solutions, and it usually turns out to be something about running the function/variable before defining it. Thing is, I HAVE defined it before running it, and, the exact same code runs perfectly well in my first program.
GUI from my first program:
import threading
import tkinter as tk
import pip
import time
import mysql.connector
from time import sleep
global score
global countdown
en = "1"
score = 0
countdown = 1
print("Hiya!")
class Tkinter(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
self.root = 0
self.entry = 0
self.label = 0
self.button = 0
self.timerValue = 2
self.stopButton = 0
self.start()
self.spilSlut = 0
def run(self) -> 0:
self.root = tk.Tk()
global countdown
#Baggrund
self.root.geometry("+2+0")
self.root.config(background="Grey")
#Timervalue selectors
self.label = tk.Label(self.root, bg="white", fg="black", font=("Fixedsys", 28))
self.entry = tk.Entry(self.root, bg="white", fg="black", font=("Fixedsys", 28))
#Start/Stop Knapper
self.stopTiden = tk.Button(self.root, bg="red", fg="white", text="Stop Spillet", command=self.stopTid)
self.startTiden = tk.Button(self.root, bg="green", fg="white", text="Start Spillet", command=self.startTid)
#Timeren
self.timerDisplay = tk.Label(self.root, bg="black", fg="red", text="Spillet er ikke startet")
self.timerDisplay.grid(row=2, column=50)
self.startTiden.grid(row=0, column=1)
self.stopTiden.grid(row=0, column=10)
self.entry.grid(row=1, column=1)
self.label.grid(row=1, column=10)
self.root.bind("<KeyPress>", self.read)
self.Update(self)
self.root.mainloop()
def read(self, event):
key = event.keysym
try:
if key == "Return":
self.getA()
self.visTid()
except:
self.fejlTidvalg()
def startTid(self):
self.stopButton = 0
def getA(self):
try:
self.timerValue = float(self.entry.get().format("%.2f", 1.23456))
print(self.timerValue)
return self.timerValue
except:
print(fejl)
def stopTid(self):
self.stopButton = 1
print("Spillet er stoppet nu")
def visTid(self):
self.label.config(text="Det her er timerens slutværdi: {}".format(self.timerValue))
def fejlTidvalg(self):
self.label.config(text="FEJL -Vælg Venligst Et Tal")
def opdaterCountdown(self):
if self.stopButton != 1:
self.spilSlut = 0
self.tidTilbage = self.timerValue - countdown
self.tidTilbage_minutter = int(self.tidTilbage/60)
self.tidTilbage_sekunder = (self.tidTilbage) - (self.tidTilbage_minutter * 60)
self.timerDisplay.config(text="{} minutter, {:.2f} sekunder tilbage".format(self.tidTilbage_minutter, self.tidTilbage_sekunder))
if self.tidTilbage < 0 or self.tidTilbage == 0 and self.timerValue > 0:
self.spilSlut = 1
elif self.stopButton == 1:
self.timerDisplay.config(text="Spillet er sat på pause")
def opdaterCountdownSpilSlut(self):
self.timerDisplay.config(text="Spillet er slut")
class Update(threading.Thread):
def __init__(self, tkinter):
threading.Thread.__init__(self)
self.daemon = True
self.tkinter = tkinter
self.start()
def run(self) -> None:
while True:
time.sleep(0.1)
self.tkinter.opdaterCountdown()
if self.tkinter.spilSlut == 1:
self.tkinter.opdaterCountdownSpilSlut()
time.sleep(1)
app = Tkinter()
How come the same (exact same) GUI works in the first, but not in the second?
Have I made a typo, that I for some reason cannot find? Or is there something else I have missed?
The two GUI's are exact copies, 1:1.
That is a false statement. One does app = Tkinter() and the other does tk = Tkinter().
You are using tk for two different things:
import tkinter as tk
...
tk = Tkinter()
You need to change that last line to use a different variable name.
Related
I'm trying to control (enable/disable) the buzzer of my UHF RFID Reader (CT-I809) by RS-232 serial port in raspberry pi with python. My app works well in detecting RFID tag, but when i click the "STOP READING" button, the buzzer is still buzzing and I feel it's so annoying.
Below is how my RFID Reader looks like.
I have found a Windows app that is able to control it, but it was in C#. I try to open it in my raspberry pi (OS Raspbian) with mono, but it failed because the app use native windows dll SDK. So, I decided to write my own app in python and here is my code.
import tkinter as tk
import tkinter.ttk as ttk
import threading, serial, binascii
ser = serial.Serial()
ser.port = "COM1"
# ser.port = "/dev/ttyUSB0"
ser.baudrate = 57600
ser.timeout = None
header = "00ee00"
epc = []
count = []
index = 0
class AppBase(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent=parent
self.initialize_user_interface()
def initialize_user_interface(self):
self.parent.title("COMEL Reader")
self.parent.grid_rowconfigure(0, weight=1)
self.parent.grid_columnconfigure(0, weight=1)
title = ttk.Label(self.parent, text="COMEL Reader", font=("Arial 20 bold"))
title.grid(column=0, row=1, sticky=tk.W, padx=10, pady=10)
self.read_btn = tk.Button(self.parent, text="READ", state=tk.NORMAL, height=2, width=10,
command=self.switch)
self.read_btn.grid(row=1, column=1, sticky=tk.E, padx=10)
# Set the treeview
self.tree = ttk.Treeview(self.parent,
columns=('TagID', 'Count'))
self.tree.grid(padx=10, pady=10)
self.tree.heading('#0', text='No.')
self.tree.heading('#1', text='TagID')
self.tree.heading('#2', text='Count')
self.tree.column('#0', width=40, stretch=tk.YES)
self.tree.column('#1', width=200, stretch=tk.YES)
self.tree.column('#2', width=100, stretch=tk.YES, anchor=tk.CENTER)
self.tree.grid(row=4, columnspan=4, sticky='nsew')
vsb = ttk.Scrollbar(orient="vertical", command=self.tree.yview)
vsb.place(x=335, y=90, height=202)
self.tree.configure(yscrollcommand=vsb.set)
self.treeview = self.tree
self.i = 0
self.active = False
self.progressbar = ttk.Progressbar(self.parent, mode='indeterminate')
self.progressbar.grid(column=1, padx=10, pady=10, sticky=tk.E)
def switch(self):
global index
if self.active == True:
self.active = not self.active
self.read_btn["text"] = "READ"
ser.close()
else:
self.treeview.delete(*self.treeview.get_children())
index = 0
self.i = 0
epc.clear()
count.clear()
self.read_btn["text"] = "STOP"
self.active = not self.active
ser.open()
self.start_submit_thread(None)
def read_tag(self):
global index
global count
while self.active == True:
if self.active == False:
break
ser.flushInput()
read_result = ser.read(8)
hex_string = binascii.hexlify(read_result).decode('utf-8')
data = hex_string[hex_string.index(header) + len(header):].upper()
if "B0" not in data:
continue
else:
if index==0:
self.i = self.i + 1
epc.append(data)
count.append(1)
self.treeview.insert('', 'end', text=str(self.i),
values=(epc[index],
str(count[index])))
index = index + 1
else:
if data in epc:
data_index = epc.index(data)
count[data_index] = count[data_index]+1
x = self.treeview.get_children()[data_index]
self.treeview.item(x,
values=(epc[data_index],
str(count[data_index])))
else:
self.i = self.i + 1
epc.append(data)
count.append(1)
self.treeview.insert('', 'end', text=str(self.i),
values=(epc[index],
str(count[index])))
index = index + 1
def start_submit_thread(self,event):
self.submit_thread = threading.Thread(target=self.read_tag)
self.submit_thread.daemon = True
self.progressbar.start()
self.submit_thread.start()
root.after(20, self.check_submit_thread)
def check_submit_thread(self):
if self.submit_thread.is_alive():
root.after(20, self.check_submit_thread)
else:
self.progressbar.stop()
if __name__ == '__main__':
root=tk.Tk()
AppBase(root)
root.mainloop()
I also have decompiled the C# SDK, but for me it's too complex, here is some code:
if(lstrcmpA(lpProcName,"Writebaud")==0)
return (FARPROC)UHFReader18_RVA(0x4570);
if(lstrcmpA(lpProcName,"SetPowerDbm")==0)
return (FARPROC)UHFReader18_RVA(0x4830);
if(lstrcmpA(lpProcName,"BuzzerAndLEDControl")==0)
return (FARPROC)UHFReader18_RVA(0x4920);
and from header file:
void* __stdcall UHFReader18_RVA(DWORD rvaAddr);
Back to my question, is it possible to control the buzzer of RFID reader by serial in python? Every answer will be highly appreciated. Thank you.
I am meeting up a window and hide it with withdraw() in it's original class. And then I opened a new window, I want to redisplay the first one when I close the second one.
from tkinter import *
from tkinter import Frame
import time
import tkinter as tk
class Return_Value_In_Entry:
def __init__(self, Master):
self.question_num = 0
self.answer_list = []
self.survey_num = 1
self.survey_dict = dict()
self.question_list = ["START", "FODO_easy", "CIBAN_hard", "AUBLM_easy", "GROLY_hard", "EMONV", "MAHES", "AORDI",
"LENUC", "RYORS", "BMHUT"]
self.Master = Master
self.Master.title("Welcome")
self.Frame = tk.Frame(self.Master)
self.Master.lbl = Label(self.Frame, text=self.question_list[self.question_num], font=("Courier", 44), width=30,
height=10)
self.Master.lbl.pack()
self.Entry = Entry(self.Frame)
self.Entry.pack()
self.Button = Button(self.Frame, text="Submit", command=self.Return, height=2)
self.Button.pack()
self.clock = Label(self.Frame, height=5)
self.clock.pack()
self.start_time = time.time()
self.Button_2 = Button(self.Frame, text="Exit", command=self.Exit, height=2)
self.Button_2.pack()
self.Frame.pack()
def tick():
time2 = time.strftime('%H:%M:%S')
self.clock.config(text=time2)
self.clock.after(200, tick)
tick()
def Return(self):
print("time used = ", time.time() - self.start_time)
self.question_num += 1
self.TempVar = self.Entry.get()
print(self.TempVar)
self.answer_list.append(self.TempVar)
if (self.question_num - 1) % 2 == 0 and (self.question_num - 1) != 0 and (self.question_num - 1) % 4 != 0:
self.newWindow_1 = tk.Toplevel(self.Master)
self.app_1 = survey_hard(self.newWindow_1)
#Trying to hide the first window with withdraw() at here:
self.Master.withdraw()
if (self.question_num - 1) % 4 == 0 and (self.question_num - 1) != 0:
self.newWindow_2 = tk.Toplevel(self.Master)
self.app_2 = survey_set(self.newWindow_2)
self.start_time = time.time()
self.Master.lbl.configure(text=self.question_list[self.question_num])
self.Entry.delete(0, 'end')
def Exit(self):
print(self.answer_list)
self.Master.destroy()
class survey_hard:
def __init__(self, Master):
self.survey_num = 1
self.survey_dict = dict()
self.Master = Master
self.Frame = tk.Frame(self.Master)
self.Master.title("survey_hard")
self.hard_label_1 = Label(self.Frame, text="Question_1")
self.hard_entry_1 = Entry(self.Frame)
self.hard_label_2 = Label(self.Frame, text="Question_2")
self.hard_entry_2 = Entry(self.Frame)
self.hard_button = Button(self.Frame, text="Submit", command=self.Next, height=2)
self.hard_label_1.pack()
self.hard_entry_1.pack()
self.hard_label_2.pack()
self.hard_entry_2.pack()
self.hard_button.pack()
self.Frame.pack()
def Next(self):
self.survey_dict[self.survey_num] = [self.hard_entry_1.get(), self.hard_entry_2.get()]
self.survey_num += 1
print(self.survey_dict)
self.Master.destroy()
#Want to show up the first window again here:
the_main = Return_Value_In_Entry()
the_main.Pop()
class survey_set:
...... ......
def main():
root = tk.Tk()
app = Return_Value_In_Entry(root)
root.mainloop()
if __name__ == '__main__':
main()
It always gives me an error and warning message like this:
Exception in Tkinter callback
Traceback (most recent call last):
File"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 1705, in __call__return
self.func(*args)
File "/Users/HarryWuuu/PycharmProjects/untitled17/venv/111.py", line 89, in Next
the_main = Return_Value_In_Entry()
TypeError: __init__() missing 1 required positional argument: 'Master'
EDIT:
Read this comment: TypeError: __init__() missing 1 required positional argument
While calling the_main = Return_Value_In_Entry(), means you want to create an instance of Return_Value_In_Entry and assign this newly created instance to the_main.
Creating an instance of a class will call its __init__ method.
In your case, Return_Value_In_Entry.__init__ take two positional arguments. The first is self, which is omitted by Python, and the second is Master, which you forgot to set.
I get an error similar to: invalid command name ".91418712.91418792" when I click the Quit button in my program. I have googled this but an unsure how to fix the issue.
The issue apparently is that my thread is trying to update GUI elements that no longer exists which is why I put a sleep in before doing the destroy.
The following is closely related to my issue _tkinter.TclError: invalid command name ".4302957584"
A condensed version of the code:
#!/usr/bin/python
import Adafruit_GPIO as GPIO
import Adafruit_GPIO.FT232H as FT232H
from time import sleep
from threading import Thread
import Tkinter as tk
import tkFont
# Temporarily disable the built-in FTDI serial driver on Mac & Linux platforms.
FT232H.use_FT232H()
# Create an FT232H object that grabs the first available FT232H device found.
device = FT232H.FT232H()
d0 = 0
d1 = 1
device.setup(d0, GPIO.IN)
device.setup(d1, GPIO.IN)
class Application():
def __init__(self):
self.root = tk.Tk()
self.root.title("Show Voltage")
self.root.grid()
self.createWidgets()
self.stop = False
self.watcher = Thread(target = self.watcher, name="watcher")
self.watcher.start()
self.root.mainloop()
def changeBackground(self, cell):
if cell == 0:
self.la_d0.config(bg="green")
elif cell == 1:
self.la_d1.config(bg="green")
def returnBackground(self, cell):
if cell == 0:
self.la_d0.config(bg="black")
elif cell == 1:
self.la_d1.config(bg="black")
def quit(self):
self.stop = True
self.watcher.join()
sleep(0.3)
self.root.destroy()
def watcher(self):
while not self.stop:
self.wa_d0 = device.input(d0)
self.wa_d1 = device.input(d1)
if self.wa_d0 == GPIO.HIGH:
self.changeBackground(0)
else:
self.returnBackground(0)
if self.wa_d1 == GPIO.HIGH:
self.changeBackground(1)
else:
self.returnBackground(1)
sleep(0.0125)
def createWidgets(self):
self.font = tkFont.Font(family='Helvetica', size=50, weight='bold')
self.bt_font = tkFont.Font(family='Helvetica', size=18, weight='bold')
self.fr_d0 = tk.Frame(height=100, width=100)
self.la_d0 = tk.Label(self.fr_d0, text="d0", bg="black", fg="red", font=self.font)
self.fr_d1 = tk.Frame(height=100, width=100)
self.la_d1 = tk.Label(self.fr_d1, text="d1", bg="black", fg="red", font=self.font)
self.fr_quit = tk.Frame(height=40, width=200)
self.bt_quit = tk.Button(self.fr_quit, text="Quit!", bg="white", command=self.quit, font=self.bt_font)
self.fr_d0.grid(row=0, column=0)
self.fr_d0.pack_propagate(False)
self.la_d0.pack(fill="both", expand=1)
self.fr_d1.grid(row=0, column=2)
self.fr_d1.pack_propagate(False)
self.la_d1.pack(fill="both", expand=1)
self.fr_quit.grid(row=1, column=0, columnspan=3)
self.fr_quit.pack_propagate(False)
self.bt_quit.pack(fill="both", expand=1)
app = Application()
not sure exactly what fixed it but this no longer creates the error
#!/usr/bin/python
import Adafruit_GPIO as GPIO
import Adafruit_GPIO.FT232H as FT232H
from time import sleep
from threading import Thread
import Tkinter as tk
import tkFont
# Temporarily disable the built-in FTDI serial driver on Mac & Linux platforms.
FT232H.use_FT232H()
# Create an FT232H object that grabs the first available FT232H device found.
device = FT232H.FT232H()
d0 = 0
d1 = 1
device.setup(d0, GPIO.IN)
device.setup(d1, GPIO.IN)
class Application():
def __init__(self):
self.root = tk.Tk()
self.root.title("Show Voltage")
self.root.grid()
self.createWidgets()
self.stop = False
self.watcherThread = Thread(target = self.watcher, name="watcher")
self.watcherThread.start()
self.root.mainloop()
def changeBackground(self, cell):
if cell == 0:
self.la_d0.config(bg="green")
elif cell == 1:
self.la_d1.config(bg="green")
def returnBackground(self, cell):
if cell == 0:
self.la_d0.config(bg="black")
elif cell == 1:
self.la_d1.config(bg="black")
def destroy(self):
self.root.destroy()
def quit(self):
self.stop = True
self.watcherThread.join()
self.root.after(300, self.destroy)
def watcher(self):
while not self.stop:
self.wa_d0 = device.input(d0)
self.wa_d1 = device.input(d1)
if self.wa_d0 == GPIO.HIGH:
self.changeBackground(0)
else:
self.returnBackground(0)
if self.wa_d1 == GPIO.HIGH:
self.changeBackground(1)
else:
self.returnBackground(1)
sleep(0.0125)
def createWidgets(self):
self.font = tkFont.Font(family='Helvetica', size=50, weight='bold')
self.bt_font = tkFont.Font(family='Helvetica', size=18, weight='bold')
self.fr_d0 = tk.Frame(height=100, width=100)
self.la_d0 = tk.Label(self.fr_d0, text="d0", bg="black", fg="red", font=self.font)
self.fr_d1 = tk.Frame(height=100, width=100)
self.la_d1 = tk.Label(self.fr_d1, text="d1", bg="black", fg="red", font=self.font)
self.fr_quit = tk.Frame(height=40, width=200)
self.bt_quit = tk.Button(self.fr_quit, text="Quit!", bg="white", command=self.quit, font=self.bt_font)
self.fr_d0.grid(row=0, column=0)
self.fr_d0.pack_propagate(False)
self.la_d0.pack(fill="both", expand=1)
self.fr_d1.grid(row=0, column=2)
self.fr_d1.pack_propagate(False)
self.la_d1.pack(fill="both", expand=1)
self.fr_quit.grid(row=1, column=0, columnspan=3)
self.fr_quit.pack_propagate(False)
self.bt_quit.pack(fill="both", expand=1)
app = Application()
thank you all for all the input!! :)
i have made a double countdown timer with python and tkinter but it seemed that it cannot be run if the tkinter window is not on the foreground and it cannot simultaneously run. This is my code:
import tkinter as tk
import tkinter.ttk as ttk
import time
class app:
def __init__(self):
self = 0
def mainGUIArea():
def count_down_1():
for i in range(79, -1, -1):
timeCount = "{:02d}:{:02d}".format(*divmod(i, 60))
time_str.set(timeCount)
root.update()
time.sleep(1)
def count_down_2():
for j in range(10, -1, -1):
timeCount = "{:02d}:{:02d}".format(*divmod(j, 60))
time_str1.set(timeCount)
root.update()
time.sleep(1)
#Main Window
root = tk.Tk()
root.title("Super Timer V1.0")
root.minsize(300,300)
root.geometry("500x300")
#Timer1
time_str = tk.StringVar()
label_font = ('Courier New', 40)
tk.Label(root, textvariable = time_str, font = label_font, bg = 'white', fg = 'blue', relief = 'raised', bd=3).pack(fill='x', padx=5, pady=5)
tk.Button(root, text=' Start Timer! ',bg='lightgreen',fg='black', command=count_down_1).pack()
tk.Button(root, text='Stop and Exit',bg='red',fg='white', command=root.destroy).pack()
#Timer2
time_str1 = tk.StringVar()
label_font = ('Courier New', 40)
tk.Label(root, textvariable = time_str1, font = label_font, bg = 'white', fg='blue', relief='raised', bd=3).pack(fill='x', padx=5, pady=5)
tk.Button(root, text=' Start Timer! ',bg='lightblue',fg='black', command=count_down_2).pack()
tk.Button(root, text='Stop and Exit',bg='red',fg='white', command=root.destroy).pack()
def main():
app.mainGUIArea()
main()
Do you have any suggestion? Thank You :)
The calls to time.sleep are at least part of the problem. When you call sleep it does literally that -- it puts the application to sleep. No events can be processed and the GUI freezes. This is the wrong way to do a countdown timer.
The other problem is the calls to update inside the loops alongside the calls to time.sleep. This call will process events, which means that when one of the loops is running and you click a button, you may end up calling the other function, interleaving your two loops.
The proper way to do something periodically is to use after to repeatedly call a function. The general pattern is this:
def update_display(self):
<do whatever code you want to update the display>
root.after(1000, self.update_display)
You can have as many of these running in parallel that you want (up to practical limits, obviously), and your GUI will be completely responsive between updates.
Here's a quick example:
class Countdown(tk.Label):
def __init__(self, parent):
tk.Label.__init__(self, parent, width=5, text="00:00")
self.value = 0
self._job_id = None
def tick(self):
self.value -= 1
text = "{:02d}:{:02d}".format(*divmod(self.value, 60))
self.configure(text=text)
if self.value > 0:
self._job_id = self.after(1000, self.tick)
def start(self, starting_value=60):
if self._job_id is not None: return
self.value = starting_value
self.stop_requested = False
self.after(1000, self.tick)
def stop(self):
self.after_cancel(self._job_id)
self._job_id = None
This is a simple tkinter(gui) stopwatch I made which works perfectly. Check it out
__author__ = 'Surya'
from tkinter import *
import time
class StopWatch(Frame):
def __init__(self, parent = None, ** kw):
Frame.__init__(self, parent, kw)
self._timeelapsed = 0.0
self._start = 0.0
self._run = 0
self.timestr = StringVar()
self.makeWidgets()
def makeWidgets(self):
l = Label(self, textvariable=self.timestr)
self._setTime(self._timeelapsed)
l.pack(fill=X, expand=NO, pady=2, padx=2)
def _update(self):
self._timeelapsed = time.time() - self._start
self._setTime(self._timeelapsed)
self._timer = self.after(50, self._update)
def _setTime(self, elap):
minutes = int(elap/60)
seconds = int(elap - minutes*60.0)
hseconds = int((elap - minutes*60.0 - seconds)*100)
self.timestr.set('%02d:%02d:%02d' % (minutes, seconds, hseconds))
def Start(self):
if not self._run:
self._start = time.time() - self._timeelapsed
self._update()
self._run = 1
def Stop(self):
if self._run:
self.after_cancel(self._timer)
self._timeelapsed = time.time() - self._start
self._setTime(self._timeelapsed)
self._run = 0
def Reset(self):
self._start = time.time()
self._timeelapsed = 0.0
self._setTime(self._timeelapsed)
def main():
root = Tk()
sw = StopWatch(root)
sw.pack(side=TOP)
Button(root, text='Start!', command=sw.Start).pack(side=LEFT)
Button(root, text='Stop!', command=sw.Stop).pack(side=LEFT)
Button(root, text='Reset!!!', command=sw.Reset).pack(side=LEFT)
Button(root, text='Quit!!!', command=root.quit).pack(side=LEFT)
root.mainloop()
if __name__ == '__main__':
main()
I am running Tkinter 3.5 on Win machine and when I run this code, I get two windows . I was expecting just one . BTW, I got the code form the web.It is working fine, except that bothers me the second(in backgorund) window .
Basically is a widget to navigate trough different windows(pages) with buttons .
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
try:
import Tkinter as tk # Python2
except ImportError:
import tkinter as tk # Python3
class Wizard(tk.Toplevel):
def __init__(self, npages, master=None):
self.pages = []
self.current = 0
tk.Toplevel.__init__(self)
self.attributes('-topmost', True)
for page in range(npages):
self.pages.append(tk.Frame(self))
self.pages[0].pack(fill='both', expand=1)
self.__wizard_buttons()
def onQuit(self):
pass
def __wizard_buttons(self):
for indx, frm in enumerate(self.pages):
btnframe = tk.Frame(frm, bd=1, bg='#3C3B37')
btnframe.pack(side='bottom', fill='x')
nextbtn = tk.Button(btnframe, bd=0, bg='#F2F1F0', activebackground='#F58151', highlightcolor='red', cursor='hand2', text="Siguiente >>", width=10, command=self.__next_page)
nextbtn.pack(side='right', anchor='e', padx=5, pady=5)
if indx != 0:
prevbtn = tk.Button(btnframe, bd=0, bg='#F2F1F0', activebackground='#F58151', highlightcolor='red', cursor='hand2', text="<< Atras", width=10, command=self.__prev_page)
prevbtn.pack(side='right', anchor='e', padx=5, pady=5)
if indx == len(self.pages) - 1:
nextbtn.configure(text="Terminar", bd=0, bg='#F2F1F0', activebackground='#F58151', highlightcolor='red', cursor='hand2', command=self.close)
def __next_page(self):
if self.current == len(self.pages):
return
self.pages[self.current].pack_forget()
self.current += 1
self.pages[self.current].pack(fill='both', expand=1)
def __prev_page(self):
if self.current == 0:
return
self.pages[self.current].pack_forget()
self.current -= 1
self.pages[self.current].pack(fill='both', expand=1)
def add_page_body(self, body):
body.pack(side='top', fill='both', padx=6, pady=12)
def page(self, page_num):
try:
page = self.pages[page_num]
except KeyError("Pagina Invalida! : %s" % page_num):
return 0
return page
def close(self):
if self.validate():
self.master.iconify()
print (' TK Wizard finished... ')
self.destroy()
self.master.destroy()
def validate(self):
return 1
if __name__ == "__main__":
root = tk.Tk()
root.title(' TK Wizards ')
wizard = Wizard(npages=3, master=root)
wizard.minsize(400, 350)
page0 = tk.Label(wizard.page(0), text='Pagina 1: ...Bienvenido al Wizard de TK !')
page1 = tk.Label(wizard.page(1), text='Pagina 2: Acepta las condiciones de la WTFPL ?')
page2 = tk.Label(wizard.page(2), text='Pagina 3: Felicitaciones, nada no se ha instalado correctamente.')
wizard.add_page_body(page0)
wizard.add_page_body(page1)
wizard.add_page_body(page2)
root.mainloop()
The additional, blank window is the root window. Add a call to
root.withdraw()
Just underneath the root.title(' TK Wizards ') line, should do the trick
In the main area, you create a tkinter object, which will produce a window:
root = tk.Tk()
Then, in the Wizard class's __init__, you create a Toplevel object:
tk.Toplevel.__init__(self)
So you're really creating the GUI in this new Toplevel window. You can change your program to create the app in the root window, which requires changing the Wizard class to inherit from the default object and changing the program to act on a saved self.master root object wherever it used to act on the Wizard object (which is no longer a Toplevel object).
try:
import Tkinter as tk # Python2
except ImportError:
import tkinter as tk # Python3
class Wizard(object):
def __init__(self, npages, master=None):
self.pages = []
self.current = 0
self.master = master
self.master.attributes('-topmost', True)
for page in range(npages):
self.pages.append(tk.Frame(self.master))
self.pages[0].pack(fill='both', expand=1)
self.__wizard_buttons()
def onQuit(self):
pass
def __wizard_buttons(self):
for indx, frm in enumerate(self.pages):
btnframe = tk.Frame(frm, bd=1, bg='#3C3B37')
btnframe.pack(side='bottom', fill='x')
nextbtn = tk.Button(btnframe, bd=0, bg='#F2F1F0', activebackground='#F58151', highlightcolor='red', cursor='hand2', text="Siguiente >>", width=10, command=self.__next_page)
nextbtn.pack(side='right', anchor='e', padx=5, pady=5)
if indx != 0:
prevbtn = tk.Button(btnframe, bd=0, bg='#F2F1F0', activebackground='#F58151', highlightcolor='red', cursor='hand2', text="<< Atras", width=10, command=self.__prev_page)
prevbtn.pack(side='right', anchor='e', padx=5, pady=5)
if indx == len(self.pages) - 1:
nextbtn.configure(text="Terminar", bd=0, bg='#F2F1F0', activebackground='#F58151', highlightcolor='red', cursor='hand2', command=self.close)
def __next_page(self):
if self.current == len(self.pages):
return
self.pages[self.current].pack_forget()
self.current += 1
self.pages[self.current].pack(fill='both', expand=1)
def __prev_page(self):
if self.current == 0:
return
self.pages[self.current].pack_forget()
self.current -= 1
self.pages[self.current].pack(fill='both', expand=1)
def add_page_body(self, body):
body.pack(side='top', fill='both', padx=6, pady=12)
def page(self, page_num):
try:
page = self.pages[page_num]
except KeyError("Pagina Invalida! : %s" % page_num):
return 0
return page
def close(self):
if self.validate():
self.master.iconify()
print (' TK Wizard finished... ')
self.destroy()
self.master.destroy()
def validate(self):
return 1
if __name__ == "__main__":
root = tk.Tk()
root.title(' TK Wizards ')
wizard = Wizard(npages=3, master=root)
wizard.master.minsize(400, 350)
page0 = tk.Label(wizard.page(0), text='Pagina 1: ...Bienvenido al Wizard de TK !')
page1 = tk.Label(wizard.page(1), text='Pagina 2: Acepta las condiciones de la WTFPL ?')
page2 = tk.Label(wizard.page(2), text='Pagina 3: Felicitaciones, nada no se ha instalado correctamente.')
wizard.add_page_body(page0)
wizard.add_page_body(page1)
wizard.add_page_body(page2)
root.mainloop()