How to stop my Tkinter window from freezing? - python

Below is the main function I use in order to run two files of python but once I click on the buttuon my window freezes.Please tell me a way to perform multi threaading so that I can click both the buttons at once.
import pandas as pd
import numpy as np
from tkinter import *
from tkinter.ttk import *
from tkinter import messagebox
import threading
import Test1
import Test2
# In[ ]:
def Load1():
Test1.func()
messagebox.showinfo( "Successful","Reconcilation Complete")
def Load2():
Test2.func()
try:
messagebox.showinfo( "Successful","Reconcilation Complete")
except Exception as inst:
messagebox.showinfo( "Unsuccessful",inst)
root = Tk()
root.geometry('375x100')
root.title("Reco")
root.configure(background="LightBlue2")
style = Style()
style.configure('TButton', background = 'SeaGreen2', font =
('calibri', 20, 'bold'))
btn1 = Button(root, text = 'Tier Recon', command =threading.Thread(target=Load1).start )
btn1.grid(row = 1, column = 3, pady = 10, padx = 100)
btn2 = Button(root, text = 'View Recon', command =threading.Thread(target=Load2).start)
btn2.grid(row = 2, column = 3, pady = 10, padx = 100)
root.mainloop()

I have assumed your Test1 and Test2 functions are somewhat infinite so I have created this as the format for my Test1.py and Test2.py:
# Test1.py / Test2.py
import tkinter as tk
def func():
while True:
root = tk.Tk()
root.mainloop()
Now with your code I would thoroughly recommend moving away from your current format and moving to Object Oriented Programming as it will save you many headaches in the future!
This here is the code I have written to make it work:
import tkinter as tk
import tkinter.ttk as ttk
import Test1
import Test2
class reco_win:
def __init__(self, master):
self.master = master
self.master.geometry('375x100')
self.master.configure(background="LightBlue2")
style = ttk.Style()
style.configure('TButton', background = 'SeaGreen2', font =
('calibri', 20, 'bold'))
btn1 = ttk.Button(self.master, text = 'Tier Recon', command = lambda: self.master.after(1, self.load1))
btn1.grid(row = 1, column = 3, pady = 10, padx = 100)
btn2 = ttk.Button(self.master, text = 'View Recon', command =lambda: self.master.after(1, self.load1))
btn2.grid(row = 2, column = 3, pady = 10, padx = 100)
def load1(self):
Test1.func()
def load2(self):
Test2.func()
def main():
root = tk.Tk()
reco_win(root)
root.mainloop()
if __name__ == '__main__':
main()
The important bit in this code:
self.master.after(1, self.load1)
What this line of code does is after 1 millisecond it will asynchronously start a new thread and execute the function Test1.func().
This means that you don't have to worry about the issues with managing the multithreading module in python and you can instead work on writing more code!
Hope this helps,
James
P.S.
If you are using a tk.Tk() window in your Test1/Test2.py you could instead use a tk.TopLevel window which would allow you to rewrite this code to read like so:
import tkinter as tk
import tkinter.ttk as ttk
import Test1
import Test2
class reco_win:
def __init__(self, master):
self.master = master
self.master.geometry('375x100')
self.master.configure(background="LightBlue2")
style = ttk.Style()
style.configure('TButton', background = 'SeaGreen2', font =
('calibri', 20, 'bold'))
btn1 = ttk.Button(self.master, text = 'Tier Recon', command = self.load1)
btn1.grid(row = 1, column = 3, pady = 10, padx = 100)
btn2 = ttk.Button(self.master, text = 'View Recon', command =self.load2)
btn2.grid(row = 2, column = 3, pady = 10, padx = 100)
def load1(self):
top = tk.Toplevel()
tk.Label(top, text="Hello").grid(row=0, column=0)
def load2(self):
top2 = tk.Toplevel()
tk.Label(top2, text="Hello 2").grid(row=0, column=0)
def main():
root = tk.Tk()
reco_win(root)
root.mainloop()
if __name__ == '__main__':
main()

Related

Tkinter: function starts when running tkinter code

I have searched for similar questions but I can't seem to figure out what i am doing wrong. I have this code for a very simple gui. The code in googl1 is a scraper that extracts information from google. But I have this problem where when I run the code for the gui, the scraper starts before the gui is shown.
Could someone explain why this is?
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog, messagebox
from functools import partial
HEIGHT = 500
WIDTH = 600
import google1
#----Functions----------------------------------------------------------------
def fileDialog():
global filename
filename = filedialog.askopenfilename(initialdir = "/",title = "Select file",filetypes = (("excel workbook","*.xlsx"),("all files","*.*")))
label = ttk.Label(labelFrame, text = "")
label.grid(column = 1, row = 4)
label.configure(text = filename)
print(filename)
def start_program(filename):
if filename:
print("this is the filename", filename)
google1.start_program
else:
messagebox(title="No file detected", message="Please select file first")
#----Tkinter-setup------------------------------------------------------------
root = tk.Tk()
#initial placeholder for gui
canvas = tk.Canvas(root, height=HEIGHT, width=WIDTH)
canvas.pack()
#a frame within the canvas
frame = tk.Frame(root, bg='#80c1ff')
frame.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.8)
labelFrame = tk.LabelFrame(frame, text = "Select File")
labelFrame.grid(column = 0, row = 1, padx = 20, pady = 20)
labelFrame_start = tk.LabelFrame(frame, text = "Start Program")
labelFrame_start.grid(column = 0, row = 3, padx = 20, pady = 20)
button = tk.Button(labelFrame, text = "Browse Files", command = fileDialog)
button.grid(column = 1, row = 1)
button = tk.Button(labelFrame_start, text = "Click to start program", command = lambda: start_program(filename))
button.grid(column = 1, row = 1)
root.mainloop()
edit: this (the scraper starting before seeing the gui) also happens when I comment out the google1.start_program, but still have the import. When I also comment out the import, that is when i do get the gui first.

problem with tkinter under defined function

Can you please help me with follwing issue I face:
When I am creating radiobutton with tkinter, I don't have a problem to select from the list.
However, if I put the same script under a menu, then selected option is always the default one, ("Python",1) in this specific case. Do you have any idea how to overcome this? Thanks in advance!
import tkinter as tk
root_m = tk.Tk()
root_m.geometry("400x200")
frame_m = tk.Frame(root_m)
root_m.title("NUMERIC UNIVERSE")
frame_m.pack()
def chars_merging():
languages = [
("Python",1),
("Perl",2),
("Java",3),
("C++",4),
("C",5)
]
root = tk.Tk()
root.geometry("400x200")
frame = tk.Frame(root)
root.title("SELECT SOMETHING")
frame.pack()
v = tk.IntVar()
v.set(0) # initializing the choice, i.e. Python
label = tk.Label(frame,
text="""Choose your favourite
programming language:""",
justify = tk.LEFT,
padx = 20)
label.pack()
def ShowChoice():
global data_sel
data_sel = v.get()
print(data_sel)
for val, language in enumerate(languages):
tk.Radiobutton(frame,
text=language,
indicatoron = 0,
width = 20,
padx = 20,
variable=data_sel,
command=ShowChoice,
value=val).pack(anchor=tk.W)
root.mainloop()
#return(languages[v.get()])
print("You selected", languages[v.get()])
button3 = tk.Button(frame_m,
text="3.Prepare and merge chars",
command=chars_merging,
width=25)
button3.pack()
# CLOSING THE WINDOW ---------------------------------------------------------
def finish():
root_m.destroy()
button_n = tk.Button(frame_m,
text="Finish",
command=finish,
width=25)
button_n.pack()
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
root_m.mainloop()

tkinter frames not showing the widgets

from tkinter import *
import tkinter.messagebox
def message():
text='''sfjkasjdfkjasdfjsdjfjsdlfjasd
fjsdkfjksadjfsajdjfl
sdfasdjflsjdlfsldjflsjd'''
tkinter.messagebox.showinfo("showing",text)
def _price_inputs():
win2 = Tk()
win2.title("Transactions for the project Botique")
win2.geometry("1600x800+0+0")
win2.configure(bg="black")
framex = Frame(win2,width=1600,bg="RoyalBlue4",height=100,relief=GROOVE).pack(side=TOP)
frame1 = Frame(win2,width=1000, height=400,bg="white", relief=SUNKEN).pack(side=RIGHT,fill=Y)
frame2 = Frame(win2, width=775,height=100,bg="white", relief=FLAT).pack(side=BOTTOM)
frame3 = Frame(win2,width=600,height=430,bg="gray",relief=FLAT).pack(side=LEFT,fill=X)
#framex == heading
#frame1 == showing the infos
#frame2 == bottom_infos
#frme3 == adding the buttons and widgets
#==++++===========================title=============================
lbl1 = Label(framex,font=("arial", 30, "bold"),bg="powder blue",fg="green",text="Hello this is the title of the page",bd=10,relief=GROOVE).pack(side=TOP)
btn1 = Button(frame1,font=("arial",20,"bold"),bg="powder blue",fg="white",text="click me").pack()
win2.mainloop()
I am trying to create the gui with tkinter.I am using python3.6
I made frames using tkinter and now when i try to add buttons , Labels etc it doesen't show the buttons or Labels in the output screen.
And how to i use pack for frames and grid for widgets in that frame using the pack.
You haven't call function in which you have defined properties. Just call function by adding _price_inputs() to your code at last:
from tkinter import *
import tkinter.messagebox
def message():
text='''sfjkasjdfkjasdfjsdjfjsdlfjasd
fjsdkfjksadjfsajdjfl
sdfasdjflsjdlfsldjflsjd'''
tkinter.messagebox.showinfo("showing",text)
def _price_inputs():
win2 = Tk()
win2.title("Transactions for the project Botique")
win2.geometry("1600x800+0+0")
win2.configure(bg="black")
framex = Frame(win2,width=1600,bg="RoyalBlue4",height=100,relief=GROOVE).pack(side=TOP)
frame1 = Frame(win2,width=1000, height=400,bg="white", relief=SUNKEN).pack(side=RIGHT,fill=Y)
frame2 = Frame(win2, width=775,height=100,bg="white", relief=FLAT).pack(side=BOTTOM)
frame3 = Frame(win2,width=600,height=430,bg="gray",relief=FLAT).pack(side=LEFT,fill=X)
#framex == heading
#frame1 == showing the infos
#frame2 == bottom_infos
#frme3 == adding the buttons and widgets
#==++++===========================title=============================
lbl1 = Label(framex,font=("arial", 30, "bold"),bg="powder blue",fg="green",text="Hello this is the title of the page",bd=10,relief=GROOVE).pack(side=TOP)
btn1 = Button(frame1,font=("arial",20,"bold"),bg="powder blue",fg="white",text="click me").pack()
win2.mainloop()
_price_inputs()
You can't see new items, lbl1 and btn1 as they're:
Children to win2, not any frames
Blocked by another frame, frame3
1
lbl1 and btn1 are children to win2, because passing None as the first positional argument or by default, the widget's parent is assigned as the Tk instance.
lbl1 and btn1 are instantiated with parent arguments as None, because:
framex = Frame(win2,width=1600,bg="RoyalBlue4",height=100,relief=GROOVE).pack(side=TOP)
...
frame1 = Frame(win2,width=600,height=430,bg="red",relief=FLAT).pack(side=LEFT,fill=X)
lines are identical to that of:
Frame(win2,width=1600,bg="RoyalBlue4",height=100,relief=GROOVE).pack(side=TOP)
framex = None
...
Frame(win2,width=600,height=430,bg="red",relief=FLAT).pack(side=LEFT,fill=X)
frame1 = None
Because both framex and frame3 are the return of the method pack which is always None.
One could fix this by separating the geometry manager line with the widget instantiation line:
framex = Frame(win2,width=1600,bg="RoyalBlue4",height=100,relief=GROOVE)
framex.pack(side=TOP)
...
frame1 = Frame(win2,width=600,height=430,bg="red",relief=FLAT)
frame1.pack(side=LEFT,fill=X)
2
Comment out frame3 line to see that lbl1 and btn1 actually exists:
#frame3 = Frame(win2,width=600,height=430,bg="red",relief=FLAT).pack(side=LEFT,fill=X)
from tkinter import *
import tkinter.messagebox
"""def message():
text='''sfjkasjdfkjasdfjsdjfjsdlfjasd
fjsdkfjksadjfsajdjfl
sdfasdjflsjdlfsldjflsjd'''
tkinter.messagebox.showinfo("showing",text)"""
def _price_inputs():
win2 = Tk()
win2.title("Transactions for the project Botique")
win2.geometry("1600x800+0+0")
win2.configure(bg="white")
framex = Frame(win2,width=1600,bg="RoyalBlue4",height=100,relief=GROOVE).pack(side=TOP)
#frame1 = Frame(win2,width=1000, height=400,bg="white", relief=SUNKEN).pack(side=RIGHT,fill=Y)
frame2 = Frame(win2, width=775,height=100,bg="black", relief=FLAT).pack(side=BOTTOM)
frame3 = Frame(win2,width=800,height=450,bg="gray",relief=FLAT).pack(side=LEFT,fill=X)
#framex == heading
#frame1 == showing the infos
#frame2 == bottom_infos
#frme3 == adding the buttons and widgets
#==++++===========================title=============================
lbl1 = Label(framex,font=("arial", 30, "bold"),bg="black",fg="green",text="Hello this is the title of the page",bd=10,relief=GROOVE).pack(side=TOP)
btn1 = Button(frame3,font=("arial",15,"bold"),bd=8,bg="black",fg="white",text="before 60 hrs",relief=GROOVE).pack(side=BOTTOM)
btn2 = Button(frame3,font=("arial",15,"bold"),bd=8,bg="black",fg="white",text="full_stock",relief=GROOVE).pack(side=BOTTOM)
btn3 = Button(frame3,font=("arial",15,"bold"),bd=8,bg="black",fg="white",text="delivery_report",relief=GROOVE).pack(side=BOTTOM)
before = IntVar()
stock_full = IntVar()
delivery_report = IntVar()
btn4 = Button(win2,font=("arial",15,"bold"),bd=8,bg="black",fg="white",text="hello",relief=GROOVE).pack(side=BOTTOM)
'''import Tkinter as tk
import ImageTk
FILENAME = 'image.png'
root = tk.Tk()
canvas = tk.Canvas(root, width=250, height=250)
canvas.pack()
tk_img = ImageTk.PhotoImage(file = FILENAME)
canvas.create_image(125, 125, image=tk_img)
quit_button = tk.Button(root, text = "Quit", command = root.quit, anchor = 'w',
width = 10, activebackground = "#33B5E5")
quit_button_window = canvas.create_window(10, 10, anchor='nw', window=quit_button)
root.mainloop()
'''
win2.mainloop()

Style not working in class for any object?

Why doesn't my style change the background of any of these objects? I got annoyed and just assigned them to everything. Also why does it make two windows? I see that it's something to do with style being different then the style in the object's options... I feel like it's also with my class, am I suppose to def _init_(self) it? the class?
import tkinter as tk
import tkinter.ttk as ttk
style = ttk.Style()
style.configure("color1.TFrame", foreground = "black", background = "red")
class main:
parent = tk.Tk()
n = ttk.Notebook(parent,style = "color1.TFrame")
f1 = ttk.Frame(n,style = "color1.TFrame") # first page tab
f2 = ttk.Frame(n,style = "color1.TFrame") # second page 2nd tab
window = f1
frame1 = ttk.Frame(window,style = "color1.TFrame")
frame1.grid(row = 1, column = 1, padx = 200, pady = 150)
frame2 = ttk.Frame(window)
frame2.grid(row = 2, column = 1,padx = 200, pady = 150)
main()
The reason why nothing seems to appear and your styles don't work is because you're not actually drawing all of your widgets.
You never tell the below widgets to actually draw on your window:
n
f1
f2
Additionally, a second window loads when you're calling ttk.Style() you haven't yet created a root window. This is explained much better than I could explain it here.
By changing your program to the below you can see that the styles do actually work:
import tkinter as tk
import tkinter.ttk as ttk
class main:
parent = tk.Tk()
style = ttk.Style()
style.configure("color1.TFrame", foreground = "black", background = "red")
n = ttk.Notebook(parent,style = "color1.TFrame")
n.pack()
f1 = ttk.Frame(n,style = "color1.TFrame") # first page tab
f2 = ttk.Frame(n,style = "color1.TFrame") # second page 2nd tab
window = f1
f1.pack()
f2.pack()
frame1 = ttk.Frame(window,style = "color1.TFrame")
frame1.grid(row = 1, column = 1, padx = 200, pady = 150)
frame2 = ttk.Frame(window)
frame2.grid(row = 2, column = 1,padx = 200, pady = 150)
main()
Arguably a better way of doing this would be something like the below:
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
style = ttk.Style()
style.configure("color1.TFrame", foreground = "black", background = "red")
class main:
def __init__(self, root):
n = ttk.Notebook(root, style = "color1.TFrame")
f1 = ttk.Frame(n, style = "color1.TFrame")
f2 = ttk.Frame(n, style = "color1.TFrame")
n.pack()
f1.pack()
f2.pack()
frame1 = ttk.Frame(f1, style = "color1.TFrame")
frame2 = ttk.Frame(f1, style = "color1.TFrame")
frame1.grid(row = 1, column = 1, padx = 200, pady = 150)
frame2.grid(row = 2, column = 1,padx = 200, pady = 150)
main(root)
root.mainloop()
Although this is subjective and accomplishes the same goal.

Python tkinter: access child widgets of a widget

I have a string 'currentMessage' and a Label to display it.
I have a Toplevel widget, which contains a Text widget to provide new value for 'currentMessage':
from tkinter import *
from tkinter import ttk
root = Tk()
mainFrame = ttk.Frame(root)
mainFrame.grid()
currentMessage = 'current Message'
ttk.Label(mainFrame, text = currentMessage).grid(padx = 10, pady = 10)
def updateCurrentMessage(popupWindow):
currentMessage = popupWindow.textBox.get(0.0, END)
def changeValues():
popup = Toplevel(mainFrame)
popup.grid()
textBox = Text(popup, width = 20, height = 5)
textBox.grid(column = 0, row = 0)
textBox.insert(END, 'new message here')
b = ttk.Button(popup, command = lambda: updateCurrentMessage(popup))
b.grid(column = 0, row = 1, padx = 5, pady = 5)
b['text'] = 'Update'
theButton = ttk.Button(mainFrame, command = changeValues, text = 'Click')
theButton.grid(padx = 10, pady = 10)
mainFrame.mainloop()
I tried to get the content of 'textBox' Text widget of the Toplevel by using this function:
def updateCurrentMessage(popupWindow):
currentMessage = popupWindow.textBox.get(0.0, END)
But I got an error
'Toplevel' object has no attribute 'textBox'
So how do I access content of the widget 'textBox', which is a child widget of 'popup' (this Toplevel widget is only created when function changeValues() is called)?
I think probably this is what you are looking for -- although I'm just guessing, because you are asking for a solution for a specific problem you think you have, however if I were you I would rethink what exactly do I want to do:
from tkinter import *
from tkinter import ttk
# Create Tk Interface root
root = Tk()
# Initialize mainFrame
mainFrame = ttk.Frame( root )
mainFrame.grid()
# Initialize label of mainframe
theLabel = ttk.Label( mainFrame, text='Current Message' )
theLabel.grid( padx=10, pady=10 )
def createPopup():
# Initialize popup window
popup = Toplevel( mainFrame )
popup.grid()
# Initialize text box of popup window
textBox = Text( popup, width=20, height=5 )
textBox.grid( column = 0, row = 0 )
textBox.insert( END, 'New Message Here' )
# Initialize button of popup window
button = ttk.Button( master = popup,
command = lambda: theLabel.config(text=textBox.get(0.0, END)),
text = 'Update')
button.grid( column=0, row=1, padx=5, pady=5 )
# Initialize button of main frame
theButton = ttk.Button( mainFrame, command=createPopup, text='Click' )
theButton.grid( padx=10, pady=10 )
# Enter event loop
mainFrame.mainloop()
There is a way indeed, like this:
def updateCurrentMessage(popupWindow):
currentMessage = popupWindow.nametowidget('textBox').get(0.0, END)
def changeValues():
popup = Toplevel(mainFrame)
popup.grid()
textBox = Text(popup, width = 20, height = 5, name = 'textBox')
textBox.grid(column = 0, row = 0)
textBox.insert(END, 'new message here')
b = ttk.Button(popup, command = lambda: updateCurrentMessage(popup))
b.grid(column = 0, row = 1, padx = 5, pady = 5)
b['text'] = 'Update'
You can choose whatever you want for the 'name'.

Categories