Automatic stop watch in python - python

I have the following code for stop watch. when you run it, you can see an stop watch with start button.
I have another code for calculation of long equations which takes a long time to solve. How can I put that code inside of the following code: when I run the code the stop watch start counting automatically and when the code finished its calculation, stopwatch stop counting.
import tkinter
import time
class StopWatch(tkinter.Frame):
#classmethod
def main(cls):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
root.title('Stop Watch')
root.resizable(True, False)
root.grid_columnconfigure(0, weight=1)
padding = dict(padx=5, pady=5)
widget = StopWatch(root, **padding)
widget.grid(sticky=tkinter.NSEW, **padding)
root.mainloop()
def __init__(self, master=None, cnf={}, **kw):
padding = dict(padx=kw.pop('padx', 5), pady=kw.pop('pady', 5))
super().__init__(master, cnf, **kw)
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(1, weight=1)
self.__total = 0
self.__label = tkinter.Label(self, text='Total Time:')
self.__time = tkinter.StringVar(self, '0.000000')
self.__display = tkinter.Label(self, textvariable=self.__time)
self.__button = tkinter.Button(self, text='Start', command=self.__click)
self.__label.grid(row=0, column=0, sticky=tkinter.E, **padding)
self.__display.grid(row=0, column=1, sticky=tkinter.EW, **padding)
self.__button.grid(row=1, column=0, columnspan=2,
sticky=tkinter.NSEW, **padding)
def __click(self):
if self.__button['text'] == 'Start':
self.__button['text'] = 'Stop'
self.__start = time.clock()
self.__counter = self.after_idle(self.__update)
else:
self.__button['text'] = 'Start'
self.after_cancel(self.__counter)
def __update(self):
now = time.clock()
diff = now - self.__start
self.__start = now
self.__total += diff
self.__time.set('{:.6f}'.format(self.__total))
self.__counter = self.after_idle(self.__update)
if __name__ == '__main__':
StopWatch.main()
thank you so much

Related

mainloop() getting stuck on GUI on pyamaze library

I have a code made with pyamaze library which I perform 4 different types of search on maze and I want to display it with GUI (to make the user choose the type of search they want)
but the problem when I run the code the GUI gets stuck
from pyamaze import maze, COLOR, agent,textLabel
#Depth first search
def DFS(m1):
start=(m1.rows,m1.cols)
explored=[start]
frontier=[start]
dfsPath={}
while len(frontier)>0:
currCell=frontier.pop()
if currCell==(1,1):
break
for d in 'ESNW':
if m1.maze_map[currCell][d]==True:
if d=='E':
childCell=(currCell[0],currCell[1]+1)
elif d=='W':
childCell=(currCell[0],currCell[1]-1)
elif d=='S':
childCell=(currCell[0]+1,currCell[1])
elif d=='N':
childCell=(currCell[0]-1,currCell[1])
if childCell in explored:
continue
explored.append(childCell)
frontier.append(childCell)
dfsPath[childCell]=currCell
fwdPath={}
cell=(1,1)
while cell!=start:
fwdPath[dfsPath[cell]]=cell
cell=dfsPath[cell]
return fwdPath
#Breadth first search
def BFS(m2):
start=(m2.rows,m2.cols)
frontier=[start]
explored=[start]
bfsPath={}
while len(frontier)>0:
currCell=frontier.pop(0)
if currCell==(1,1):
break
for d in 'ESNW':
if m2.maze_map[currCell][d]==True:
if d=='E':
childCell=(currCell[0],currCell[1]+1)
elif d=='W':
childCell=(currCell[0],currCell[1]-1)
elif d=='N':
childCell=(currCell[0]-1,currCell[1])
elif d=='S':
childCell=(currCell[0]+1,currCell[1])
if childCell in explored:
continue
frontier.append(childCell)
explored.append(childCell)
bfsPath[childCell]=currCell
fwdPath={}
cell=(1,1)
while cell!=start:
fwdPath[bfsPath[cell]]=cell
cell=bfsPath[cell]
return fwdPath
# A-star search
from queue import PriorityQueue
def h(cell1,cell2):
x1,y1=cell1
x2,y2=cell2
return abs(x1-x2)+abs(y1-y2)
def aStar(m3):
start=(m3.rows,m3.cols)
g_score={cell:float('inf') for cell in m3.grid}
g_score[start]=0
f_score={cell:float('inf') for cell in m3.grid}
f_score[start]=h(start,(1,1))
open=PriorityQueue()
open.put((h(start,(1,1)),h(start,(1,1)),start))
aPath={}
while not open.empty():
currCell=open.get()[2]
if currCell==(1,1):
break
for d in 'ESNW':
if m3.maze_map[currCell][d]==True:
if d=='E':
childCell=(currCell[0],currCell[1]+1)
if d=='W':
childCell=(currCell[0],currCell[1]-1)
if d=='N':
childCell=(currCell[0]-1,currCell[1])
if d=='S':
childCell=(currCell[0]+1,currCell[1])
temp_g_score=g_score[currCell]+1
temp_f_score=temp_g_score+h(childCell,(1,1))
if temp_f_score < f_score[childCell]:
g_score[childCell]=temp_g_score
f_score[childCell]=temp_f_score
open.put((temp_f_score,h(childCell,(1,1)),childCell))
aPath[childCell]=currCell
fwdPath={}
cell=(1,1)
while cell!=start:
fwdPath[aPath[cell]]=cell
cell=aPath[cell]
return fwdPath
#uniform cost search.
def UCS(m,*h,start=None):
if start is None:
start=(m.rows,m.cols)
hurdles=[(i.position,i.cost) for i in h]
unvisited={n:float('inf') for n in m.grid}
unvisited[start]=0
visited={}
revPath={}
while unvisited:
currCell=min(unvisited,key=unvisited.get)
visited[currCell]=unvisited[currCell]
if currCell==m._goal:
break
for d in 'EWNS':
if m.maze_map[currCell][d]==True:
if d=='E':
childCell=(currCell[0],currCell[1]+1)
elif d=='W':
childCell=(currCell[0],currCell[1]-1)
elif d=='S':
childCell=(currCell[0]+1,currCell[1])
elif d=='N':
childCell=(currCell[0]-1,currCell[1])
if childCell in visited:
continue
tempDist= unvisited[currCell]+1
for hurdle in hurdles:
if hurdle[0]==currCell:
tempDist+=hurdle[1]
if tempDist < unvisited[childCell]:
unvisited[childCell]=tempDist
revPath[childCell]=currCell
unvisited.pop(currCell)
fwdPath={}
cell=m._goal
while cell!=start:
fwdPath[revPath[cell]]=cell
cell=revPath[cell]
return fwdPath,visited[m._goal]
from timeit import timeit
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import tkinter as tk
class MazeGUI:
def __init__(self, master):
self.master = master
self.master.title("Maze GUI")
self.master.geometry("700x500")
self.master.resizable(True, True)
self.master.configure(background='white')
self.create_widgets()
self.master.mainloop()
def create_widgets(self):
self.frame = tk.Frame(self.master, bg='black')
self.frame.pack(fill=tk.BOTH, expand=True)
self.frame.grid_rowconfigure(0, weight=1)
self.frame.grid_columnconfigure(0, weight=1)
self.frame.grid_propagate(False)
self.button1 = tk.Button(self.frame, text="BFS", command=self.bfs)
self.button1.grid(row=1, column=1, sticky="nsew", padx=10, pady=10)
self.button1.place(x=50,y=50)
self.button2 = tk.Button(self.frame, text="A*", command=self.aStar)
self.button2.grid(row=2, column=1, sticky="nsew", padx=10, pady=10)
self.button3 = tk.Button(self.frame, text="UCS", command=self.UCS)
self.button3.grid(row=3, column=1, sticky="nsew", padx=10, pady=10)
self.button4 = tk.Button(self.frame, text="DFS", command=self.dfs)
self.button4.grid(row=4, column=1, sticky="nsew", padx=10, pady=10)
self.button5 = tk.Button(self.frame, text="Exit", command=self.exit)
self.button5.grid(row=5, column=1, sticky="nsew", padx=10, pady=10)
def bfs(self):
m2=maze()
m2.CreateMaze()
path=BFS(m2)
b=agent(m2,footprints=True,filled=True)
m2.tracePath({b:path})
l2=textLabel(m2,'Length of Shortest Path',len(path)+1)
m2.mainloop()
def aStar(self):
m3=maze()
m3.CreateMaze()
path=aStar(m3)
c=agent(m3,footprints=True)
m3.tracePath({c:path})
l3=textLabel(m3,"A Star Path Length",len(path)+1)
m3.mainloop()
def UCS(self):
m4=maze(10,10)
m4.CreateMaze()
path,c=UCS(m4)
textLabel(m4,'Total Cost',c)
a=agent(m4,color=COLOR.cyan,filled=True,footprints=True,)
m4.tracePath({a:path},delay=100)
t1=timeit(stmt='UCS(m4)',number=100,globals=globals())
textLabel(m4,'UCS Time',t1)
m4.run()
m4.mainloop()
def dfs(self):
m1=maze()
m1.CreateMaze()
path=DFS(m1)
a=agent(m1,footprints=True)
m1.tracePath({a:path})
l1=textLabel(m1,'Length of Shortest Path',len(path)+1)
m1.mainloop()
def exit(self):
self.master.destroy()
if __name__ == '__main__':
root = tk.Tk()
app = MazeGUI(root)
I want to be displayed correctly and As it meant to be so if a press a button the search starts and agent moves.

Tkinter: drag and drop app only drop if the dragged text is selected in not under the cursor and show error for all widget instead of one

I'm working on a tkinter drag and drop app, my code is working just fine but only at one condition:
that the dragged text widget, when selected to be moved, is not under the cursor (so if the text widget is dragged by a word it doesn't work).
I've tried to fix the issue by adding some negative value to the y axis to make the selection always a little bit above, but it kinda create a weird distance if the text widget is dragged by the bottom.
So I was wondering if there is a better way to add some space.
Also I'd like to show the "Not empty" error only when the text is dragged in the self.dad_text
and is not empty, while right now it appear for every text widget. Is there a way to fix that?
This is my code
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.first_list = ["11:00", "03:43", "22:04", "17:21", "22:35", "07:01", "16:11", "09:00"]
self.second_list = ["morning\nmorning\nmorning", "afternoon\nafternoon\nafternoon", "evening\nevening\nevening", "nigth\nnight\nnight"]
self.w_list = []
self.first_frame = tk.Frame(root)
self.first_frame.pack(padx=15, pady=15, fill="both", expand="true", side="left", anchor="w")
self.second_frame = tk.Frame(root)
self.second_frame.pack(padx=15, pady=15, fill="both", expand="true", side="left")
self.up()
def up(self):
for n, hour in enumerate(self.first_list):
self.list_one_frame = tk.LabelFrame(self.first_frame)
self.list_one_frame.grid(row=n, column=0, padx=10, pady=10)
self.one_text = tk.Text(self.list_one_frame, width=10, height=2)
self.one_text.grid(row=0, column=0,padx=10, pady=10)
self.one_text.insert("end", hour)
self.one_text.config(state="disabled")
self.dad_text = tk.Text(self.list_one_frame, width=20, height=1)
self.dad_text.grid(row=0, column=1, padx=10, pady=10, ipady=7)
for n, day in enumerate(self.second_list):
self.second_text = tk.Text(self.second_frame, width=9, height=3)
self.second_text.grid(row=n, column=1, pady=10, padx=10)
self.second_text.insert("end", day)
self.second_text.bind('<Button-1>', self.click)
self.second_text.bind('<B1-Motion>',self.drag)
self.second_text.bind('<ButtonRelease-1>',self.release)
def click(self, event):
self.widget_check = event.widget
self.text = event.widget.get("1.0",'end-1c')
root.clipboard_clear()
root.clipboard_append(self.text)
self.top = tk.Toplevel(root)
self.top.attributes('-alpha', 0.7)
self.top.overrideredirect(True)
self.top._offsetx = event.x
self.top._offsety = event.y
x = self.top.winfo_pointerx() - self.top._offsetx
y = self.top.winfo_pointery() - self.top._offsety - 50
self.top.geometry('+{x}+{y}'.format(x=x,y=y))
label = tk.Label(self.top, text=self.text)
label.grid(row=0, column=0)
def drag(self,event):
widget = event.widget.winfo_containing(event.x_root, event.y_root)
x = self.top.winfo_pointerx() - self.top._offsetx
y = self.top.winfo_pointery() - self.top._offsety - 50
self.top.geometry(f"+{x}+{y}")
def release(self, event):
widget = event.widget.winfo_containing(event.x_root, event.y_root)
try:
if widget.get('1.0', 'end-1c') != "":
messagebox.showerror("Error", "Not empty")
else:
reference_clipboard = root.clipboard_get()
widget.config(state="normal")
widget.insert("end", f"{reference_clipboard}")
widget.config(state="disabled")
self.top.destroy()
except:
self.top.destroy()
if __name__ == "__main__":
root = tk.Tk()
MainApplication(root).pack(side="top", fill="both", expand=True)
root.mainloop()
Thank you!

Why do my grid weights not affect the layout of window

I am writing some code for a program with a GUI, and part of this is this code:
self.chatbox = Text(self.chatframe)
self.messagebox = Entry(self.sendframe, textvariable=self.message)
self.sendbutton = Button(self.sendframe, text="Send", font=self.font(12))
self.chatframe.grid_rowconfigure(0, weight=1)
self.sendframe.grid_columnconfigure(0, weight=19)
self.sendframe.grid_columnconfigure(1, weight=1)
self.chatbox.grid(row=0, column=0)
self.messagebox.grid(row=0, column=0)
self.sendbutton.grid(row=0, column=1)
self.sendframe.grid(row=1, column=0)
self.mainframe.grid_columnconfigure(0, weight=1)
self.mainframe.grid_columnconfigure(1, weight=9)
self.mainframe.grid_rowconfigure(0, weight=1)
self.menu.grid(row=0, column=0)
self.chatframe.grid(row=0, column=1)
However when I run it, it always ends up only taking up some space and not filling the screen as I would expect. Any help appreciated.
Full Code:
from tkinter import *
import tkinter.messagebox
import os
class ServerInfo():
def __init__(self):
self.network = ""
self.host = False
self.name = StringVar()
self.name.set("")
class App(Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.master.state("zoomed")
#self.master.minsize(1200, 600)
self.master.title("Chatroom App")
self.serverinfo = ServerInfo()
self.buffer_length = 2048
self.message = StringVar()
self.message.set("")
self.mainmenu = Frame(self.master)
self.localframe = Frame(self.master)
self.publicframe = Frame(self.master)
self.mainframe = Frame(self.master)
self.chatframe = Frame(self.mainframe)
self.sendframe = Frame(self.chatframe)
self.choiceframe = Frame(self.master)
self.inputframe = Frame(self.master)
self.create_widgets()
def font(self, size):
return ("Alef", size)
def create_widgets(self):
self.title = Label(self.mainmenu, text="The Chatroom App", font=self.font(40))
self.localbutton = Button(self.mainmenu, text="Local Chatrooms", font=self.font(16), command=self.go_to_local)
self.publicbutton = Button(self.mainmenu, text="Public Chatrooms", font=self.font(16), command=self.go_to_public)
self.exitbutton = Button(self.mainmenu, text="Exit", font=self.font(16), command=self.master.destroy)
self.title.pack(fill=BOTH)
self.localbutton.pack(pady=20, fill=BOTH)
self.publicbutton.pack(pady=20, fill=BOTH)
self.exitbutton.pack(side=BOTTOM, fill=BOTH)
self.instruction = Label(self.choiceframe, text="Would you like to host a server or search for available servers", font=self.font(26))
self.hostbutton = Button(self.choiceframe, text="Host server", font=self.font(32), command=self.host_input)
self.joinbutton = Button(self.choiceframe, text="Join server", font=self.font(32), command=self.join_input)
self.backbutton = Button(self.choiceframe, text="Back", font=self.font(32), command=self.back_from_choice)
self.instruction.pack(pady=20, fill=BOTH)
self.hostbutton.pack(pady=10, fill=BOTH)
self.joinbutton.pack(pady=10, fill=BOTH)
self.backbutton.pack(pady=20, fill=BOTH)
self.instruction2 = Label(self.inputframe, text="", font=self.font(18))
self.server_input = Entry(self.inputframe, textvariable=self.serverinfo.name)
self.continuebutton = Button(self.inputframe, text="", font=self.font(28), command=self.take_input)
self.backbutton2 = Button(self.inputframe, text="Back", font=self.font(28), command=self.back_from_input)
self.instruction2.pack(pady=10, fill=BOTH)
self.server_input.pack(pady=40, fill=BOTH)
self.continuebutton.pack(pady=10, fill=BOTH)
self.backbutton2.pack(pady=20, fill=BOTH)
self.menu = Canvas(self.mainframe, bg="Black")
self.chatbox = Text(self.chatframe)
self.messagebox = Entry(self.sendframe, textvariable=self.message)
self.sendbutton = Button(self.sendframe, text="Send", font=self.font(12))
self.chatframe.grid_rowconfigure(0, weight=1)
self.sendframe.grid_columnconfigure(0, weight=19)
self.sendframe.grid_columnconfigure(1, weight=1)
self.chatbox.grid(row=0, column=0)
self.messagebox.grid(row=0, column=0)
self.sendbutton.grid(row=0, column=1)
self.sendframe.grid(row=1, column=0)
self.mainframe.grid_columnconfigure(0, weight=1)
self.mainframe.grid_columnconfigure(1, weight=9)
self.mainframe.grid_rowconfigure(0, weight=1)
self.menu.grid(row=0, column=0)
self.chatframe.grid(row=0, column=1)
self.mainmenu.pack()
def back_from_choice(self):
self.choiceframe.forget()
self.mainmenu.pack()
window.update()
def back_from_input(self):
self.inputframe.forget()
self.choiceframe.pack()
def take_input(self):
self.inputframe.forget()
self.mainframe.pack(fill=BOTH)
def go_to_local(self):
self.serverinfo.network = "local"
self.mainmenu.forget()
self.choiceframe.pack()
window.update()
def go_to_public(self):
self.serverinfo.network = "public"
tkinter.messagebox.showinfo("Message from the developer", "This feature is still under development")
def host_input(self):
self.serverinfo.host = True
self.instruction2.config(text="Type in the name of your server. When the server is created, a server ID will show in the top left. Share this to people who want to join the server")
self.continuebutton.config(text="Host Server")
self.choiceframe.forget()
self.inputframe.pack()
def join_input(self):
self.serverinfo.host = False
self.instruction2.config(text="Type in the server ID of the server you want to join")
self.continuebutton.config(text="Join Server")
self.choiceframe.forget()
self.inputframe.pack()
def host_server(self):
pass
def join_server(self):
pass
def write_message_to_screen(self, data):
print(data)
def encode_id(self, server_id):
return server_id
def decode_id(self, server_id):
return server_id
Weights only affect how grid allocates extra space once everything has been laid out, it doesn't describe the overall relative size of widgets.
You also don't seem to be using the sticky attribute, so space may be allocated to widgets but you aren't requesting that they stretch to fill the space given to them.

Trouble stopping a timer program in Python and Tkinter

I have this timer program in python with a Tkinter GUI. I am able to run the timer user inputs, but I am having trouble pausing or stopping the timer from a tkinter button. I tried creating a variable that changes when the stop button press to initiate time.sleep() in my if statement, but no luck. Any ideas?
from tkinter import Tk, Label, StringVar
from tkinter.ttk import Button, Entry
class Timer:
def __init__(self, master):
self.seconds = 0
self.f = False
self.time = StringVar()
self.time_label = Label(master, relief='flat', font=("Cambria", 20),
textvariable=self.time)
self.hr = StringVar()
self.hr_label = Label(master, text='Hours:').grid(row=1, column=1, padx=5, pady=1)
self.entry_hr = Entry(master, textvariable=self.hr, width=4)
self.entry_hr.grid(row=1, column=2)
self.mins = StringVar()
self.min_label = Label(master, text='Minutes:').grid(row=2, column=1, padx=5, pady=1)
self.entry_min = Entry(master, textvariable=self.mins, width=4)
self.entry_min.grid(row=2, column=2)
self.secs = StringVar()
self.secs_label = Label(master, text='Seconds:').grid(row=3, column=1, padx=5, pady=1)
self.entry_sec = Entry(master, textvariable=self.secs, width=4)
self.entry_sec.grid(row=3, column=2)
self.time.set('00:00:00')
self.start_button = Button(master, text='Start')
self.start_button.bind('<Button-1>', self.start_countdown)
self.stop_button = Button(master, text='Stop')
self.time_label.grid(row=0, columnspan=4, padx=30, pady=10)
self.start_button.grid(row=4, columnspan=4, pady=(10,20))
self.stop_button.grid(row=5, columnspan=4, pady=(10,20))
def set_time(self, hours, minutes, seconds):
self.seconds = hours * 3600 + minutes * 60 + seconds
self.time.set(self.format_time(self.seconds))
def start_countdown(self, event):
f = False
h = self.entry_hr.get()
m = self.entry_min.get()
s = self.entry_sec.get()
h,m,s = map(lambda x: int(x) if x else 0, (h,m,s))
self.set_time(h,m,s)
self.countdown()
def stop(self):
global f
f= True
def countdown(self):
if self.seconds <= 0:
return
else:
self.end_label = Label( text ="Time's up")
if self.f == True:
time.sleep()
self.time.set(self.format_time(self.seconds))
self.seconds -= 1
self.time_label.after(1000, self.countdown)
def format_time(self, seconds):
h = seconds // 3600
m = (seconds - h*3600) // 60
s = seconds - h*3600 - m*60
return '{:0>2}:{:0>2}:{:0>2}'.format(h,m,s)
if __name__ == '__main__':
root = Tk()
timer = Timer(root)
root.mainloop()
First of all your Button widget self.stop_button doesn't have a command or binding associated with it, so it doesn't actually do anything.
Secondly, even if it did call the function you're changing the value of the global variable f but in your if statement you're referencing the local variable self.f (Timer.f).
Thirdly, you're not calling time.sleep() correctly, it requires a value in seconds to sleep for.
And fourthly, time.sleep() would only delay the function from running for the period of time you specify and would eventually cause the timer to start ticking down again.
Instead, you should do something like the below (after associating the Button widget to the function self.stop()):
def stop(self):
self.f = True
def countdown(self):
if self.f == False:
print(self.f)
if self.seconds <= 0:
return
else:
self.end_label = Label( text ="Time's up")
self.time.set(self.format_time(self.seconds))
self.seconds -= 1
self.time_label.after(1000, self.countdown)
This will mean that every time we cycle through the function the first thing we do is check whether self.f is False, if it isn't then the timer stops where it is.

closing all windows in python tkinter

I am working with tkinter library in python. I have a main window which has several buttons and when clicked those buttons a new window will popup which also has a button called cancel. I want to make that cancel button to all the windows.
I tried the following solution, which only closes the current window.
from tkinter import *
from tkinter import ttk
import tkinter.messagebox
import datetime
import tkinter as tk
class AlertDialog:
def __init__(self):
self.invalidDiag = tk.Toplevel()
invalidInput = tk.Label(master=self.invalidDiag,
text='Error: Invalid Input').grid(row=1, column=1)
closeButton = tk.Button(master=self.invalidDiag,
text='Close',
command=self.invalidDiag.destroy).grid(row=2, column=1)
def start(self):
# self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
self.invalidDiag.wait_window()
class QuitDialog():
def __init__(self, ):
self.quitDialog = tk.Toplevel()
warnMessage = tk.Label(master=self.quitDialog,
text='Are you sure that you want to quit? ').grid(row=1, column=1)
cancelButton = tk.Button(master= self.quitDialog ,
text='Cancel',
command = self.quitALL).grid(row=2, column=1)
def start(self):
# self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
self.quitDialog.wait_window()
def quitALL(self):
self.quitDialog.destroy()
tc =TimeConverter()
tc.destroyit()
class TimeConverter:
def __init__(self):
self.mainWindow = tk.Tk()
self.mainWindow.title("Seconds Converter")
self.results = tk.StringVar()
self.inputSecs = tk.StringVar()
secLabel = tk.Label(master=self.mainWindow,
text="Seconds:").grid(row=0, sticky="W")
resultLabel = tk.Label(master=self.mainWindow,
text="Converted Time:\n(H:M:S)").grid(row=1, sticky="W")
calcResults = tk.Label(master=self.mainWindow,
background='light gray', width=20,
textvariable=self.results,
anchor="w").grid(row=1, column=1)
secEntry = tk.Entry(master=self.mainWindow,
width=24,
textvariable=self.inputSecs).grid(row=0, column=1)
calcButton = tk.Button(master=self.mainWindow,
text='Calculate',
command=self.SecondsToHours).grid(row=2,
column=0, sticky="w")
# quitButton = tk.Button(master=self.mainWindow,
# text='Quit',
# command=self.mainWindow.destroy).grid(row=2, column=1, sticky="E")
quitButton = tk.Button(master=self.mainWindow,
text='Quit',
command=self.showQuitDialog).grid(row=3, column=1, sticky="E")
def invalidInputEntered(self):
errorDiag = AlertDialog()
errorDiag.start()
def showQuitDialog(self):
quitdialog = QuitDialog()
quitdialog.start()
def startDisplay(self) -> None:
self.mainWindow.mainloop()
def destroyit(self):
self.mainWindow.destroy()
def SecondsToHours(self):
try:
inputseconds = int(self.inputSecs.get())
seconds = int(inputseconds % 60)
minutes = int(((inputseconds - seconds) / 60) % 60)
hours = int((((inputseconds - seconds) / 60) - minutes) / 60)
tempResults = str(hours) + ':' + str(minutes) + ':' + str(seconds)
self.results.set(tempResults)
return
except ValueError:
self.invalidInputEntered()
#self.showQuitDialog()
if __name__ == '__main__':
TimeConverter().startDisplay()
You are importing tkinter 2 times here. Onces with * and ones as tk.
Just use:
import tkinter as tk
this will help you avoid overriding anything that other libraries imports or having tkinter's functions overwritten by other imports.
You have a very unorthodox way of creating your tkinter app but if you wish to keep everything as is here is what you need to change:
Lets remove the cancel button from your quitDialog window and then add a yes and no button. This will server to allow you to either say yes to destroy all windows or to say no to only destroy the quitDialog window.
First we need to add an arguement to your QuitDialog class so we can pass the any window or frame we want to it.
So add the instance argument to your QuitDialog() class like below:
class QuitDialog():
def __init__(self, instance):
self.instance = instance
Now replace:
cancelButton = tk.Button(master= self.quitDialog ,
text='Cancel',
command = self.quitALL).grid(row=2, column=1)
With:
quitButton = tk.Button(master= self.quitDialog ,
text='Yes', command = self.quitALL).grid(row=2, column=1)
cancelButton = tk.Button(master= self.quitDialog,
text='No', command = lambda: self.quitDialog.destroy()).grid(row=2, column=2)
Then lets change your quitALL() method to:
def quitALL(self):
self.quitDialog.destroy()
self.instance.destroy()
This will use our instance argument to destroy a window we pass in.
Now change your showQuitDialog() method to:
def showQuitDialog(self):
quitdialog = QuitDialog(self.mainWindow)
quitdialog.start()
As you can see we are now passing the the tk window self.mainWindow to the QuitDialog class so we can decide on weather or not to close it.
Below is the copy past version of your code that should work as you need it to:
import tkinter as tk
from tkinter import ttk
import tkinter.messagebox
import datetime
class AlertDialog:
def __init__(self):
self.invalidDiag = tk.Toplevel()
invalidInput = tk.Label(master=self.invalidDiag,
text='Error: Invalid Input').grid(row=1, column=1)
closeButton = tk.Button(master=self.invalidDiag,
text='Close',
command=self.invalidDiag.destroy).grid(row=2, column=1)
def start(self):
# self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
self.invalidDiag.wait_window()
class QuitDialog():
def __init__(self, instance):
self.instance = instance
self.quitDialog = tk.Toplevel()
warnMessage = tk.Label(master=self.quitDialog,
text='Are you sure that you want to quit? ').grid(row=1, column=1, columnspan=2)
quitButton = tk.Button(master= self.quitDialog ,
text='Yes',
command = self.quitALL).grid(row=2, column=1)
cancelButton = tk.Button(master= self.quitDialog,
text='No',
command = lambda: self.quitDialog.destroy()).grid(row=2, column=2)
def start(self):
# self.invalidDiag.grab_set() #takes control over the dialog (makes it active)
self.quitDialog.wait_window()
def quitALL(self):
self.quitDialog.destroy()
self.instance.destroy()
class TimeConverter:
def __init__(self):
self.mainWindow = tk.Tk()
self.mainWindow.title("Seconds Converter")
self.results = tk.StringVar()
self.inputSecs = tk.StringVar()
secLabel = tk.Label(master=self.mainWindow,
text="Seconds:").grid(row=0, sticky="W")
resultLabel = tk.Label(master=self.mainWindow,
text="Converted Time:\n(H:M:S)").grid(row=1, sticky="W")
calcResults = tk.Label(master=self.mainWindow,
background='light gray', width=20,
textvariable=self.results,
anchor="w").grid(row=1, column=1)
secEntry = tk.Entry(master=self.mainWindow,
width=24,
textvariable=self.inputSecs).grid(row=0, column=1)
calcButton = tk.Button(master=self.mainWindow,
text='Calculate',
command=self.SecondsToHours).grid(row=2,
column=0, sticky="w")
quitButton = tk.Button(master=self.mainWindow,
text='Quit',
command=self.showQuitDialog).grid(row=3, column=1, sticky="E")
def invalidInputEntered(self):
errorDiag = AlertDialog()
errorDiag.start()
def showQuitDialog(self):
quitdialog = QuitDialog(self.mainWindow)
quitdialog.start()
def startDisplay(self) -> None:
self.mainWindow.mainloop()
def destroyit(self):
self.mainWindow.destroy()
def SecondsToHours(self):
try:
inputseconds = int(self.inputSecs.get())
seconds = int(inputseconds % 60)
minutes = int(((inputseconds - seconds) / 60) % 60)
hours = int((((inputseconds - seconds) / 60) - minutes) / 60)
tempResults = str(hours) + ':' + str(minutes) + ':' + str(seconds)
self.results.set(tempResults)
return
except ValueError:
self.invalidInputEntered()
#self.showQuitDialog()
if __name__ == '__main__':
TimeConverter().startDisplay()
Interesting question. As I know, you can also use just quit() in order to quit from program by closing everything.
quit()

Categories