Program hanging while using Tkinter in Python - python

I am making a python program to track various user merits and ranks. It needs to have a graphical user interface. However, when I add a while loop, it hangs! The while loop is needed to hold up the program until input is given. Here is the code:
def __init__(self):
global master, mainCanvas;
tree.write('./oldUsrData.xml')
god = self
#Create Base Window
master=Tk()
master.title("Briar Woods Falcon Robotics Merit Tracker 2.0")
master.maxsize(500,500)
#Create the Credit Label
creditLabel = Label(master, text="Developed by Falcon Robotics. Powered by Python.")
creditLabel.grid(row = 1, column= 1)
creditLabel.pack()
#Make the Main Canvas
mainCanvas = Canvas(master, width = 500, height=500, fill = None)
#Password Entry
inputPass = StringVar()
passwordEntry = Entry(master, textvariable=inputPass, show="$")
passwordEntry.grid(row=2, column=1)
#Define a few Action Functions
def startSetUp():
god.setUp()
def checkPassword(self):
if inputPass.get() == encryptionKey:
passwordEntry.destroy()
mainCanvas.create_text(250,250,text="CORRECT PASSWORD", tags="correctPassword")
continueButton = Button(master, text="Continue", command=startSetUp)
mainCanvas.create_window(270,270, window=continueButton, tags="correctPassword")
else:
exit()
passwordEntry.bind('<Key-Return>', checkPassword)
passwordEntry.pack()
mainCanvas.pack()
master.mainloop()
#define the merit ranks
global meritDict;
meritDict = { -4: 'Untouchable',
-3: 'Scum',
-2: 'Criminal',
-1: 'Mindless Grunt',
0: 'Citizen',
1: 'Vigilante',
2: 'Generic Hero',
3: 'Sharkboy/ Lavagirl',
4: 'Wonderwomen/Matter-eating lad',
5: 'Member of the Justice League',
6: 'X-men',
7: 'Avenger'}
def setUp(self):
#Verify Merit Dictionary
mainCanvas.delete("correctPassword")
mainCanvas.create_text(30,30,text="This is the Merit Ranking System. Change Program Source Code to edit",anchor="nw", tags="merit")
for x in range(-4,8,1):
mainCanvas.create_text(200,(x+4)*20+50, text= str(x) + ": " + str(meritDict[x]), anchor='w')
#create Quitter function
quitted = False
def quitter():
quitted = True
exit()
quit()
quitterButton = Button(master, text="Quit", command=quitter)
mainCanvas.create_window(50, 330, window=quitterButton, tag="quitter")
#Create User Name Entry
userEntryFinished = False;
def getUserEntry():
userVar = StringVar()
user = ""
def userEnter(self):
user = userVar.get()
mainCanvas.create_text(250, 350, text="User Inputted: " + user, tags="userEnter");
userEntryFinished=True;
userEntry = Entry(master, textvariable=userVar)
mainCanvas.create_window(250, 330, window=userEntry, tags="userEnter")
userEntry.bind('<Key-Return>', userEnter)
getUserEntry();
while not userEntryFinished:
pass
... #<--Further, irrelevant code
The code continues, but through trial and error, I determined that the while loop was the source of error. Also, I will need to take input until the quit button is pressed, so how can I go about that? Also, why do all while loops cause this strange problem?
I am using tkinter with python 2.6.
Note: Everything is already defined, just not included in this snippet of code. tree and root are global.
Clarification: Code Hangs when the "Continue" Button is pressed
Also: Is there a way to just wait for user input? That would help a lot.

Your code already has a "while loop" -- that is the loop created when you call mainloop. In GUI programming, you shouldn't be creating your own loops in code to wait for user input. Instead, you create widgets and then respond to events that occur in/on those widgets.
The specific reason your program hangs is because your while loop prevents the event loop from doing what is supposed to do, which is to respond to events. Not just user events, but requests from the system to redraw itself.
The solution is simply to remove your while not userEntryFinished loop, and instead redesign your code to respond to events. Put all the code that is after that loop into a function. Then, in getUserEntry, instead of / in addition to setting the flag, you can call this function.

Related

Running a loop inside a Radio button

How would I adjust my code to run the following loop while a radio button is selected? The idea is to create a program that clicks the left mouse button every 20 seconds or so to prevent idle. I think I'm so close I just don't quite understand how the mainloop() event stuff works. Does my loop code need to go in the main loop or something? Also, what is value=val).pack(anchor=tk.W)? I have a feeling that is a piece I don't get as well. Here is my current code:
import tkinter as tk, pyautogui, time # This is the prefered way to call tkinter, don't use wildcards.
my_ui_window = tk.Tk() # TK
my_ui_window.title('Radio Button Example')
v = tk.IntVar()
v.set(1) # initializing the choice
on_or_off = [
("Enabled"),
("Disabled")
]
def ExecuteChoice():
choice = (v.get())
while choice == 0:
time.sleep(20)
pyautogui.click()
else:
print ('waiting...')
time.sleep(3)
for val, i in enumerate(on_or_off):
tk.Radiobutton(my_ui_window,
text=i,
borderwidth = 2,
indicatoron= 0,
width = 20,
padx = 50,
variable=v,
command=ExecuteChoice(),
value=val).pack(anchor=tk.W)
my_ui_window.mainloop()
Here is my code re-written appropriate to tkinter. I was making several mistakes. The main one is you typically do not run loops inside tkinter and you definitely don't use sleep. Instead we use the .after class. Here is a better way. It's now heavily commented for anyone lost.
import tkinter as tk # This is the prefered way to call tkinter, don't use wildcards.
import pyautogui # This allows mouse stuff
import time # This allows sleep commands
my_ui_window = tk.Tk() # make tk.Tk() into just a single object.
my_ui_window.title('Radio Button Example')
v = tk.IntVar() # This becomes the index of sorts for our radio elements.
v.set(1) # initializing radio button to off
on_or_off = [ # Creates an array to represent the radio buttons needed.
("Enabled"),
("Disabled")
]
def every_20_seconds(): # Calls this function which clicks if the radio button is set to index 0. It then tells my_ui_window to wait 20 seconds using the .after method before calling itself again. In the meantime, it gives control back to the mainloop() which is always searching for an event change on the UI.
if v.get() == 0:
pyautogui.click()
my_ui_window.after(20000, every_20_seconds)
for val, i in enumerate(on_or_off): # This builds the UI for us.
tk.Radiobutton(my_ui_window,
text=i,
borderwidth = 2,
indicatoron= 0,
width = 20,
padx = 50,
variable=v,
value=val).pack(anchor=tk.W)
every_20_seconds()
my_ui_window.mainloop()
This should do pretty much what you want, even though it's not perfect yet:
import tkinter as tk,pyautogui,time
import threading
my_ui_window = tk.Tk() # TK
my_ui_window.title('Radio Button Example')
v = tk.IntVar()
v.set(0) # initializing the choice
on_or_off = [
(1, "Enabled"),
(0, "Disabled")
]
def ExecuteChoice():
choice = v.get()
if choice == 1:
print("CLICK")
threading.Timer(5.0, ExecuteChoice).start()
else:
print ('waiting...')
pass
for val, name in on_or_off:
tk.Radiobutton(my_ui_window,
text=name,
borderwidth = 2,
indicatoron= 0,
width = 20,
padx = 50,
variable=v,
command=ExecuteChoice,
value=val).pack(anchor=tk.W)
my_ui_window.mainloop()
There were two issues with your code:
You used command=ExecuteChoice() instead of command=ExecuteChoice. Thus, you call the function when initializing your RadioButtons instead of setting this function as a parameter
Yourwhile loop in ExecuteChoice was blocking, i.e. it is the only thing running. The GUI will not update anymore. Hence, you need to call my_ui_window.update() and choice = v.get() in the loop so to update the GUI and check whether the user has changed his choice of Radio-Buttons Thus, we exchange it with an if and an asynchronous timer instead of sleep()
/e: Comment is right. As mentioned, this is not best practice but the closest to the code of the poster to still make it work. I've made a little additional adjustment, to not block anymore. That doesn't mean its best practice. This would include rewriting the code more.

Python how to use Tkinter GUI without interfering the main code loop

I would like to implement a very simple GUI for my project. I was previously using just Print statements to output some text and data. However, that is not very conveneint and since a person will need to operate a device that I am coding, he needs to be clearly see the instructions that I am going to display on GUI.
my code:
main()
myConnection = mysql.connector.connect( host=hostname, user=username, passwd=password, db=database )
counter = 0
window = tk.Tk()
window.title("GUI")
window.geometry("400x200")
while(1):
# OPERACIJOS KODAI:
# 0 - PILDYMAS
# 1 - KOMPLEKTAVIMAS
# 2 - NETINKAMAS KODAS
tk.Label(window,text = "Scan barcode here:").pack()
entry = tk.Entry(window)
entry.pack()
var = tk.IntVar()
button = tk.Button(window,text="Continue",command = lambda: var.set(1))
button.pack()
print("waiting...")
button.wait_variable(var)
result = entry.get()
print("Entry string=",result)
var.set(0)
operacijos_kodas=Scanning_operation(myConnection,result)
print("operacijos kodas=",operacijos_kodas)
if(operacijos_kodas == 0):
tk.label(window,text = "PILDYMO OPERACIJA:").pack()
pildymo_operacija(myConnection)
elif(operacijos_kodas == 1):
tk.Label(window,text = "PAKAVIMO OPERACIJA:").pack()
insertData_komplektacija(myConnection,"fmb110bbv801.csv");
update_current_operation(myConnection);
picking_operation();
elif(operacijos_kodas == 2):
print("Skenuokite dar karta")
#break
window.mainloop();
Nothing is being displayed. It just opens up an empty GUI window.
First of all, I am unsure where should I call function window.mainloop().
Secondly, since my system runs in an infinite while loop ( the operation starts when a user scans a bar-code, then he completes an operation and the while loop starts over again (waiting for user to scan a bar-code). So I just simply have to display some text and allow user to input data in the text box.
Could someone suggest me whether this GUI is suitable for my needs or I should look for an alternatives?
UPDATE*********************
I have tried to use mainloop:
print ("Using mysql.connector…")
main()
GPIO_SETUP()
myConnection = mysql.connector.connect( host=hostname, user=username, passwd=password, db=database )
counter = 0
window = tk.Tk()
window.resizable(False,False)
window_height = 1000
window_width = 1200
#window.attributes('-fullscreen',True)
#window.config(height=500,width=500)
#can = Canvas(window,bg='red',height=100,width=100)
#can.place(relx=0.5,rely=0.5,anchor='center')
window.title("GUI")
screen_width = window.winfo_screenwidth()
screen_height= window.winfo_screenheight()
x = int((screen_width/ 2) - (window_width / 2))
y = int((screen_height/ 2) - (window_height / 2))
window.geometry("{}x{}+{}+{}".format(window_width,window_height,x,y))
label1=Label(window,text = "SKENUOKITE BARKODA(GUID) ARBA DAIKTO RIVILINI KODA:")
label1.pack()
entry = Entry(window)
entry.pack()
var = tk.IntVar()
button = Button(window,text="Testi operacija",width = 30,command = lambda: var.set(1))
button.pack()
#button2 = Button(window,text="RESTARTUOTI SISTEMA",width = 30,command = restart_devices())
#button2.pack()
print("waiting...")
button.wait_variable(var)
Scanned_serial = entry.get()
print("Entry string=",Scanned_serial)
var.set(0)
label2=Label(window,text = "Vykdoma operacija:")
label2.pack()
window.update()
window.after(1000,Full_operation(Scanned_serial,label2,window))
window.mainloop()
This is my code. As you can see. i call Full_operation function and then window.mainloop()
my Full_operation:
def Full_operation(Scanned_serial,label2,window):
operacijos_kodas=Scanning_operation(myConnection,Scanned_serial)
print("operacijos kodas=",operacijos_kodas)
if(operacijos_kodas == 0):
label2.config(text = "SPAUSKITE MYGTUKA ANT DEZES KURIA NORITE PILDYTI:")#update the label2
window.update()#call update to update the label
pildymo_operacija(myConnection,Scanned_serial,label2,window)
elif(operacijos_kodas == 1):
insertData_komplektacija(myConnection,"fmb110bbv801.csv");
update_current_operation(myConnection);
#label2.config(text = "IMKITE DAIKTUS IS ZALIOS DEZUTES:")#update the label2
picking_operation(myConnection,label2);
elif(operacijos_kodas == 2):
print("Skenuokite dar karta")
label2.config(text = "NUSKENUOTAS NEGALIMAS KODAS:")#update the label2
window.update()#call update to update the label
How can I ensure that everytime I enter FUll_operation function I start from clean GUI again and start another operation.
Now I am able to complete operation once. After that, the GUI is not responsive.
I have added a print statement at the beggining of my full_operation and it does not execute after I complete it once so my mainwindow does not seem to work properly.
You'll need to adapt your code to work with a GUI. You can't introduce infinite loops in to tkinter GUI's without causing all sorts of problems.
Mainloop should only be called once.
I'd suggest that you move all of your scanning/saving operations in to a separate function which you schedule to occur periodically using the tkinter after method.
For example if you call your function scan you would schedule it to occur after 1 second using
root.after(1000, scan)
A more advanced method would be to have your scanning code running on a separate thread.
Also, you are currently trying to create the label each time you go round the while loop rather than just creating and packing them once and updating the text of the labels when you perform the "scanning". You can update the text of a label using the config method, for example
## Create a label
label1 = tk.Label(window,text = "PAKAVIMO OPERACIJA:")
##Pack the label
label1.pack()
## Update the text later
label1.config(text="New Text")
Here is an example of updating tkinter widgets periodically from a function.
import tkinter as tk
import random
def scanning():
num = random.randint(0,100)
entryTemperature.delete(0, tk.END) #Delete the current contents
entryTemperature.insert(0, f"{num} K") #Add new text
root.after(1000, scanning) #Schedule the function to run again in 1000ms (1 second)
root = tk.Tk()
entryTemperature = tk.Entry(root)
entryTemperature.grid(padx=50,pady=50)
root.after(1000, scanning)
root.mainloop()

Close tkinter window after the script execution is complete

I am working an a tool where-in I am getting the initial user credentials and an unique identifier via Tkinter GUI interface. Post that after a lot of data fetching and processing I would get a report into an excel sheet using xlsxwriter package.
I generally exit/close the tkinter window using destroy() method on click of a button. Here, I want to show the user the status of the report creation in a Tkinter messagebox and then close the main window.
Note: I am using .pyw extension, so that the end user who is using the tool shouldn't see the console. So once the user hits the submit button, I will show a label at the footer of the window saying "Processing ..."
Sample code:
from tkinter import *
#Some other libraries are imported
mScrn = Tk()
mScrn.title("Report Generation Tool v1.0")
mScrn.geometry("200x180")
mScrn.resizable(False, False)
tk_uid_lbl = Label(mScrn, text="MVS1 Username")
tk_uid_lbl.pack()
tk_uid_lbl.place(x=20,y=20)
uid = StringVar()
tk_uid = Entry(mScrn, bd=3, textvariable=uid)
tk_uid.pack()
tk_uid.place(x=150, y=20)
tk_pwd_lbl = Label(mScrn, text="MVS1 Password")
tk_pwd_lbl.pack()
tk_pwd_lbl.place(x=20,y=60)
pwd = StringVar()
tk_pwd = Entry(mScrn, bd=3, show='*', textvariable=pwd)
tk_pwd.pack()
tk_pwd.place(x=150, y=60)
tk_ver_lbl = Label(mScrn, text="Version #")
tk_ver_lbl.pack()
tk_ver_lbl.place(x=20,y=100)
ver = StringVar()
tk_ver=Entry(mScrn, bd=3, textvariable=ver)
tk_ver.pack()
tk_ver.place(x=150, y=100)
tk_sub_button = Button(text='Submit', command = show_footer)
tk_sub_button.pack()
tk_sub_button.place(x=150, y=150)
mScrn.mainloop()
#The data provided in the GUI is used for access and a lot of process goes on
#Close the Tkinter window post the process is done
Thanks in Advance. I am using Python3
I am having a hard time understanding your question. My understanding is that using destroy() is exactly what you are looking for. Use destroy() when you are finished. You basically already answered your own question. I would find it helpful if you could explain your question more thoroughly. I agree with Goyo but I cannot comment.
I don't know how to get the data before closing the mainloop(). In
that aspect once that is closed I cannot show the label on the GUI and
then close with user consent (i.e. after clicking 'ok' in message box)
I don't undestand where is your problem, you can save your data with a lot ways, list, module, object, file, etc.
import tkinter as tk
import random
import threading
import time
# Simulate a process
def get_data(callback):
while True:
if len(data) == 10:
break
time.sleep(.5)
data.append(random.randint(1, 200))
callback()
def wait_end(label, tk_var_end, num=0):
label["text"] = "Processing " + " ." * num
num += 1
if num == 4:
num = 0
if not tk_var_end.get():
mScrn.after(500, wait_end, label, tk_var_end, num)
def execute():
for entry in (tk_uid, tk_pwd, tk_ver):
entry['state'] = tk.DISABLED
tk_sub_button.destroy()
tk_process_lbl = tk.Label(mScrn)
tk_process_lbl.pack()
tk_process_lbl.place(x=150,y=150)
tk_var_end = tk.BooleanVar(False)
wait_end(tk_process_lbl, tk_var_end)
process = threading.Thread(
target=get_data,
kwargs=(dict(callback=lambda: tk_var_end.set(True)))
)
process.start()
mScrn.wait_variable(tk_var_end)
mScrn.after(500, tk_process_lbl.config, dict(text='Process completed'))
mScrn.after(1500, mScrn.quit)
mScrn = tk.Tk()
data = []
mScrn.title("Report Generation Tool v1.0")
mScrn.geometry("400x180")
mScrn.resizable(False, False)
tk_uid_lbl = tk.Label(mScrn, text="MVS1 Username")
tk_uid_lbl.pack()
tk_uid_lbl.place(x=20,y=20)
uid = tk.StringVar()
tk_uid = tk.Entry(mScrn, bd=3, textvariable=uid)
tk_uid.pack()
tk_uid.place(x=150, y=20)
tk_pwd_lbl = tk.Label(mScrn, text="MVS1 Password")
tk_pwd_lbl.pack()
tk_pwd_lbl.place(x=20,y=60)
pwd = tk.StringVar()
tk_pwd = tk.Entry(mScrn, bd=3, show='*', textvariable=pwd)
tk_pwd.pack()
tk_pwd.place(x=150, y=60)
tk_ver_lbl = tk.Label(mScrn, text="Version #")
tk_ver_lbl.pack()
tk_ver_lbl.place(x=20,y=100)
ver = tk.StringVar()
tk_ver= tk.Entry(mScrn, bd=3, textvariable=ver)
tk_ver.pack()
tk_ver.place(x=150, y=100)
tk_sub_button = tk.Button(text='Submit', command = execute)
tk_sub_button.pack()
tk_sub_button.place(x=150, y=150)
mScrn.mainloop()
print(data)
But, you can also make your own class which will inherit of Tk, in this class you could override the quit or destroy method of Tk.

Making a label remove after a set time TkInter

My code currently checks the username and password entered my the user and then returns to the label with the corresponding text.
As shown below:
from tkinter import *
def Login():
global AnameEL
global ApwordEL # More globals :D
global ArootA
global f1
global f2
ArootA = Tk() # This now makes a new window.
ArootA.geometry('1280x720')
ArootA.title('Admin login') # This makes the window title 'login'
f1 = Frame(width=200, height=200, background="#D3D3D3")
f2 = Frame(ArootA, width=400, height=200)
f1.pack(fill="both", expand=True, padx=0, pady=0)
f2.place(in_=f1, anchor="c", relx=.5, rely=.5)
AnameL = Label(f2, text='Username: ') # More labels
ApwordL = Label(f2, text='Password: ') # ^
AnameL.grid(row=1, sticky=W)
ApwordL.grid(row=2, sticky=W)
AnameEL = Entry(f2) # The entry input
ApwordEL = Entry(f2, show='*')
AnameEL.grid(row=1, column=1)
ApwordEL.grid(row=2, column=1)
AloginB = Button(f2, text='Login', command=CheckLogin) # This makes the login button, which will go to the CheckLogin def.
AloginB.grid(columnspan=2, sticky=W)
ArootA.mainloop()
def CheckLogin():
checkP = Label(f2, text='')
checkP.grid(row=3, column=1)
if AnameEL.get() == "test" and ApwordEL.get() == "123": # Checks to see if you entered the correct data.
checkP.config(text='sucess')
else:
checkP.config(text='fail')
Login()
I would like to add another feature where after 2 seconds new lines of code are ran depending on the login failed/success.
For example when the user enters a wrong login I would like the text "fail" to disappear after 2 seconds and if the user enters the correct password I would like a new function to be ran after 2 seconds of the "success" being displayed.
So I tried this:
(also importing time at the top of my code)
if AnameEL.get() == "test" and ApwordEL.get() == "123": # Checks to see if you entered the correct data.
checkP.config(text='sucess')
time.sleep(2)
nextpage()
else:
checkP.config(text='fail')
time.sleep(2)
checkP.config(text='')
def nextpage():
f1.destroy()
However, this wasn't successful. After the login button was pressed it waited 2 seconds and then ran nextpage() instead of displaying "success" for 2 seconds and then running nextpage() and for incorrect logins it goes straight to checkP.config(text='') after 2 seconds of the button press.
How can I resolve this?
All help is appreciated,
Thanks.
You need to update root before using time.sleep(). Additionally, since you are dealing with a GUI, you should prefer using timers over pausing execution. In this case, Tkinter's own after() function should be preferred over time.sleep(), because it simply places the event on the event queue as opposed to pausing execution.
after(delay_ms, callback=None, *args)
Registers an alarm callback that is called after a given time.
So, per your example:
if AnameEL.get() == "test" and ApwordEL.get() == "123":
checkP.config(text='sucess')
ArootA.update()
time.sleep(2)
nextpage()
else:
checkP.config(text='fail')
ArootA.update()
time.sleep(2)
nextpage()
With after():
if AnameEL.get() == "test" and ApwordEL.get() == "123":
checkP.config(text='sucess')
ArootA.after(2000, nextpage)
else:
checkP.config(text='fail')
ArootA.after(2000, lambda : checkP.config(text=''))
You may also want to take a look at alternative ways to update the values of labels to avoid having to update root while you are in the mainloop (e.g. Making python/tkinter label widget update?).

Ending the program-Python

I'm trying to make this program end straight away without asking the question " The program is still running,Do you want to kill it? " if the wrong password entered for the third time. Tried using 'quit()' but the program become not responding. Please help me.
import Tkinter
global root
global s
# this is the main/root window
root = Tkinter.Tk()
root.title("Stock Plus system")
root.geometry('800x600')
b2Var=Tkinter.StringVar()
s = 1
def win2():
# this is the child window
labelcementin = Tkinter.Label(root,text='Cement quantity in:')
labelcementin.grid(row=1,column=1)
labelhammerin = Tkinter.Label(root,text='Hammer quantity in;')
labelhammerin.grid(row=2,column=1)
labelspannerin = Tkinter.Label(root,text='Spanner quantity in:')
labelspannerin.grid(row=3,column=1)
labelbrickin = Tkinter.Label(root,text='Brick quantity in:')
labelbrickin.grid(row=4,column=1)
labelmirrorin = Tkinter.Label(root,text='Mirror quantity in:')
labelmirrorin.grid(row=5,column=1)
labelcementout = Tkinter.Label(root,text='Cement quantity out:')
labelcementout.grid(row=1,column=3)
labelhammerout = Tkinter.Label(root,text='Hammer quantity out:')
labelhammerout.grid(row=2,column=3)
labelspannerout = Tkinter.Label(root,text='Spanner quantity out:')
labelspannerout.grid(row=3,column=3)
labelbrickout = Tkinter.Label(root,text='Brick quantity out:')
labelbrickout.grid(row=4,column=3)
labelmirrorout = Tkinter.Label(root,text='Mirror quantity out:')
labelmirrorout.grid(row=5,column=3)
def calc_val():
Total_StockIn=int(cementinVar.get())+int(hammerinVar.get())+int(spannerinVar.get())+int(brickinVar.get())+int(mirrorinVar.get())
StockInLabel=Tkinter.Label(root,text='The total stock in is '+str(Total_StockIn))
StockInLabel.grid(row=8,column=2)
Total_Expenses= (int(cementinVar.get())*16)+(int(hammerinVar.get())*10)+(int(spannerinVar.get())*8)+(int(brickinVar.get())*2)+(int(mirrorinVar.get())*22)
ExpensesLabel=Tkinter.Label(root,text='The total expenses is RM ' + str(Total_Expenses))
ExpensesLabel.grid(row=9,column=2)
Total_Income= (int(cementoutVar.get())*18)+(int(hammeroutVar.get())*12)+(int(spanneroutVar.get())*10)+(int(brickoutVar.get())*4)+(int(mirroroutVar.get())*25)
IncomeLabel = Tkinter.Label(root,text = 'The Total income is RM ' +str(Total_Income))
IncomeLabel.grid(row=8, column= 4)
Remaining_Stock =Total_StockIn-(int(cementoutVar.get())+int(hammeroutVar.get())+int(spanneroutVar.get())+int(brickoutVar.get())+int(mirroroutVar.get()))
RemainingLabel = Tkinter.Label(root,text = 'The remaining stock is ' + str(Remaining_Stock))
RemainingLabel.grid(row=9, column = 4)
Total_Profit = (Total_Income) - (Total_Expenses)
ProfitLabel = Tkinter.Label(root,text = 'The total profit is RM ' + str(Total_Profit))
ProfitLabel.grid(row=10, column = 3)
quit()
boxcementin = Tkinter.Entry(root,width=12,textvariable=cementinVar)
boxcementin.grid(row=1, column=2)
boxhammerin = Tkinter.Entry(root,width=12,textvariable=hammerinVar)
boxhammerin.grid(row=2, column=2)
boxspannerin = Tkinter.Entry(root,width=12,textvariable=spannerinVar)
boxspannerin.grid(row=3, column=2)
boxbrickin = Tkinter.Entry(root,width=12,textvariable=brickinVar)
boxbrickin.grid(row=4, column=2)
boxmirrorin = Tkinter.Entry(root,width=12,textvariable=mirrorinVar)
boxmirrorin.grid(row=5, column=2)
boxcementout = Tkinter.Entry(root,width=12,textvariable=cementoutVar)
boxcementout.grid(row=1, column=4)
boxhammerout = Tkinter.Entry(root,width=12,textvariable=hammeroutVar)
boxhammerout.grid(row=2, column=4)
boxspannerout = Tkinter.Entry(root,width=12,textvariable=spanneroutVar)
boxspannerout.grid(row=3, column=4)
boxbrickout = Tkinter.Entry(root,width=12,textvariable=brickoutVar)
boxbrickout.grid(row=4, column=4)
boxmirrorout = Tkinter.Entry(root,width=12,textvariable=mirroroutVar)
boxmirrorout.grid(row=5, column=4)
button = Tkinter.Button(root,text='Calculate',command=calc_val)
button.grid(row=7,column=3)
def textboxvalue():
#For password entry
global s
if (s!=3 ):
Password=b2Var.get()
Username=b1Var.get()
if Password ==('stock123'):
label4=Tkinter.Label(root,text='Welcome to stock plus system, press login again to start using')
label4.grid(row=0,column=3)
Button_1 = Tkinter.Button(root, text="Login", command=win2)
Button_1.grid(row=7,column=3)
else:
s =s+1
label3=Tkinter.Label(root,text='Try again')
label3.grid(row=3,column=1)
else:
label5=Tkinter.Label(root,text='bye')
label5.grid(row=4,column=4)
label6=Tkinter.Label(root,text='Thank You for using Stock Plus System ')
label6.grid(row=5,column=4)
#Widgets in main window
Button_1 = Tkinter.Button(root, text="Login", command=textboxvalue)
Button_1.grid(row=7, column=3)
b1Var = Tkinter.StringVar()
b2Var = Tkinter.StringVar()
box1Label = Tkinter.Label(root,text='Username:')
box1Label.grid(row=1,column=3)
box2Label = Tkinter.Label(root,text='Password:')
box2Label.grid(row=2,column=3)
box1Text = Tkinter.Entry(root,textvariable=b1Var,width=12)
box1Text.grid(row=1, column=4)
box2Text = Tkinter.Entry(root,textvariable=b2Var,width=12,show='*')
box2Text.grid(row=2, column=4)
cementinVar = Tkinter.IntVar()
hammerinVar = Tkinter.IntVar()
spannerinVar = Tkinter.IntVar()
brickinVar = Tkinter.IntVar()
mirrorinVar = Tkinter.IntVar()
cementoutVar = Tkinter.IntVar()
hammeroutVar = Tkinter.IntVar()
spanneroutVar = Tkinter.IntVar()
brickoutVar = Tkinter.IntVar()
mirroroutVar = Tkinter.IntVar()
root.mainloop()
You have two, or maybe three, problems with your use of quit.
First, you put it in the wrong place. You want to quit if the user fails to login three times. But your quit() call comes at the end of calcval, which only gets called after the user has successfully logged in and calculated a value, so of course it's not going to help.
Second, you called the wrong thing. The quit function is a special thing used for quitting the interactive interpreter. You usually shouldn't use it in applications at all (use sys.exit() for command-line programs), and especially not in GUI apps. The quit method is called on the same Tkinter window you called mainloop() on, and tells it to quit the main loop.
So, what you want to do is add this line inside the else block that has the Thank You for using Stock Plus System text:
root.quit()
That may not work, depending on your platform, and how you're running your program—or, if you're running from IDLE, it may cause IDLE to quit as well. Tkinter is finicky. If you have the first problem, add this line before the quit; if you have the second problem, use it instead of the quit.
root.destroy()
If you want to understand, see this thread. Briefly: destroy destroys any widget and all of its children. And when you call it on a root widget that owns the mainloop, it also ends the loop. quit sends a message to the mainloop that tells it to destroy all widgets it knows about and then kill the Tcl interpreter. Normally, it should always be safe to just quit, but there are some cases where it can miss a widget and freeze up—and when you're running under IDLE, you may be sharing the same Tcl interpreter as IDLE itself, so quit may kill or hang it as well.
Have you already tried to use
import sys
sys.exit()
or directly
raise SystemExit(0)

Categories