Tkinter Stop Frame from Overlapping - python

I am trying to display the data from a file and a button and then once the button is clicked, display the new data from a new file along with a button. You can see my print statements in my attempt to debug this. When I run the program, there is output, and it correctly displays a # and a button. However, the # that is displayed is from the last file I have (file #3) instead of from file #1. I believe that file #1 was covered by file #2 which then got covered by file #3. All of this happened without any button being clicked. How can I make the program wait until the button is clicked before displaying the new # and button?
window = Tk()
def clicked():
top = Toplevel(window)
top.geometry('300x300')
popLabel = Label(top, text = "E")
popLabel.place(relx = 0.5, rely = 0.5, anchor = 'center')
for widgets in frame1.winfo_children():
widgets.destroy()
for x in range(1,4):
fileName = "file" + str(x) + ".json"
print(fileName)
frame1 = LabelFrame(window, width = 300, height = 300, padx=10,pady=5)
frame1.grid(row= 0,column=0)
with open(fileName) as f:
data = json.load(f)
#print(data)
num = "#" + data.get("id")
print(num)
numLabel = Label(
frame1,
text = num
).grid(row = 1, column = 1)
firstButton = Button(
frame1,
text = "A",
command = clicked
).grid(row = 2, column = 1, sticky = 's')
window.mainloop()

I guess your real problem was that you overwrite the frame every time in the loop. So define your frame before the loop and set the column number as a variable.
import tkinter as tk
window = tk.Tk()
def clicked(number):
top = tk.Toplevel(window)
top.geometry('300x300')
fileName = "file" + str(number)+ ".json"
# with open(fileName) as f:
# data = json.load(f)
data = "data"
num = "#" # data.get("id")
popLabel = tk.Label(top, text = fileName)
popLabel.place(relx = 0.5, rely = 0.5, anchor = 'center')
#for widgets in frame1.winfo_children():
# widgets.destroy()
frame1 = tk.LabelFrame(window, width = 300, height = 300, padx=10,pady=5)
frame1.place(relwidth = 1, relheight= 1)
for x in range(1,4):
num = "#"
numLabel = tk.Label(
frame1,
text = num
).grid(row = 1, column = x)
firstButton = tk.Button(
frame1,
text = "A_{}".format(x),
command= lambda x =x: clicked(x)
).grid(row = 2, column = x, sticky = 's')
window.mainloop()
EDIT:
In this case, I would put the open command in the checked function and tell them the number of parameters to load.

Related

Create event log list from tkinter button presses

This is my first venture into tkinter programming, so far I have the following code that increases or decreases a number by pressing either button. As you may notice I have started adding an update definition that I'd like to update a results table with the label value each time a button is pressed. I've recently found the lambda expression to add two commands to each button press but can't find an example to build the list:
import tkinter as tk
window = tk.Tk()
def increase():
value = int(lbl_value["text"])
lbl_value["text"] = f"{value + 1}"
def decrease():
value = int(lbl_value["text"])
lbl_value["text"] = f"{value - 1}"
def update():
result_table = []
window.rowconfigure(0, minsize = 100, weight = 1)
window.columnconfigure([0,1,2], minsize = 100, weight = 1)
btn_decrease = tk.Button(master = window, text = "-", command = lambda:[decrease(), update()], bg = 'red', fg = 'white')
btn_decrease.grid(row = 0, column = 0, sticky = "nsew")
lbl_value = tk.Label(master = window, text = "0")
lbl_value.grid(row = 0, column = 1)
btn_increase = tk.Button(master = window, text = "+", command = lambda:[increase(), update()], bg = 'green', fg = 'white')
btn_increase.grid(row = 0, column = 2, sticky = "nsew")
window.mainloop()
, bg = 'black', fg = 'white')
btn_decrease.grid(row = 0, column = 0, sticky = "nsew")
lbl_value = tk.Label(master = window, text = "0")
lbl_value.grid(row = 0, column = 1)
btn_increase = tk.Button(master = window, text = "+", command = increase, bg = 'red', fg = 'white')
btn_increase.grid(row = 0, column = 2, sticky = "nsew")
window.mainloop()
I'd like to add a graph of the count to the display ultimately. Any help greatly appreciated.
Matt

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.

Random tkinter window opening on if/else statement

I'm wondering if I got my if else statement wrong or if its a tkinter issue. I want it so that if a 0 is left in any or all boxes, it gives an error message. But after the error message is closed, it opens a random blank window. This is my code. The specific area is the if else statement within the function valueget()
import tkinter as tk
def mainwindow():
mainwindow = tk.Tk()
mainwindow.title('Enter values')
mainwindow.geometry('160x110')
mainwindow.config(bg='#aaf0d1')
tk.Label(mainwindow, text = 'Enter a', font = ('verdana'), bg='#aaf0d1').grid(row=0)
tk.Label(mainwindow, text = 'Enter b', font = ('verdana'), bg='#aaf0d1').grid(row=1)
tk.Label(mainwindow, text = 'Enter c', font = ('verdana'), bg='#aaf0d1').grid(row=2)
getA = tk.IntVar()
aBox = tk.Entry(mainwindow, textvariable = getA, width=3, bg='#aaf0d1')
aBox.grid(row=0, column=1)
aBox.config(highlightbackground='#aaf0d1')
getB = tk.IntVar()
bBox = tk.Entry(mainwindow, textvariable = getB, width=3, bg='#aaf0d1')
bBox.grid(row=1, column=1)
bBox.config(highlightbackground='#aaf0d1')
getC = tk.IntVar()
cBox = tk.Entry(mainwindow, textvariable = getC, width=3, bg='#aaf0d1')
cBox.grid(row=2, column=1)
cBox.config(highlightbackground='#aaf0d1')
button = tk.Button(mainwindow, text='Obtain roots', command = lambda: valueget(), font = ('verdana'), highlightbackground='#aaf0d1')
button.grid(row=4)
button.config(bg='#aaf0d1')
def valueget():
readA = getA.get()
readB = getB.get()
readC = getC.get()
intA = int(readA)
intB = int(readB)
intC = int(readC)
negroot = (readB**2)-(4*readA*readC)
quadformulaplus = (-readB + (pow(negroot,0.5)))/(2*readA) #quad forumla
quadformulaminus = (-readB - (pow(negroot,0.5)))/(2*readA) #quad forumla
messagewindow = tk.Tk()
messagewindow.geometry('290x50')
messagewindow.title('Roots of the equation')
messagewindow.config(bg='#aaf0d1')
if readA == 0 or readB==0 or readC==0 or (readA==0 and readB==0 and readC==0):
errorwindow = tk.messagebox.showerror(message='none').pack()
else:
label = tk.Label(messagewindow, text = f'The roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}', bg='#aaf0d1', font = ('verdana'))
label.grid(row=1)
closebutton = tk.Button(messagewindow, text='Close', command = lambda: messagewindow.destroy(), font = ('verdana'), highlightbackground='#aaf0d1')
closebutton.grid(row=2)
closebutton.config(bg='#aaf0d1')
messagewindow.mainloop()
# print(f'the roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}')
mainwindow.mainloop()
def startup():
startpage = tk.Tk()
startpage.title('Solver')
photo = tk.PhotoImage(file = r"/Users/isa/Desktop/DiffEqns/cover.png") #image load
coverbutton = tk.Button(startpage, image = photo, command = lambda: [startpage.destroy(), mainwindow()])
coverbutton.pack()
coverbutton.configure(highlightbackground='#aaf0d1')
startpage.mainloop()
startup()
Here's a basic idea of what I would do:
import tkinter as tk
from tkinter import messagebox
def mainwindow(root):
# Creates a toplevel window
mainwindow = tk.Toplevel()
mainwindow.protocol("WM_DELETE_WINDOW", root.destroy) # This overrides the "X" being clicked to also destroy the root window.
root.withdraw() # "Hides" the root window, leaving it (and mainloop) running in the background.
mainwindow.title('Enter values')
mainwindow.geometry('160x110')
mainwindow.config(bg='#aaf0d1')
# Since all three of the labels/entries are the same
# we can save space by generating them in a loop
entry_items = ('Enter a', 'Enter b', 'Enter c')
values = []
for x, item in enumerate(entry_items): # Using enumerate and x to assign rows
tk.Label(mainwindow, text = item,
font = ('verdana'), bg='#aaf0d1').grid(row=x) # Row assigned to x.
values.append(tk.StringVar()) # Appended StringVar to list.
tk.Entry(mainwindow,
textvariable = values[-1], # Uses the last value appended to the values list.
highlightbackground='#aaf0d1',
width=3,
bg='#aaf0d1').grid(row=x, column=1) # Row assigned to x.
tk.Button(mainwindow,
text='Obtain roots',
command = lambda vals = values: valueget(vals), # Here the button command is assigned with the values list
font = ('verdana'), bg='#aaf0d1',
highlightbackground='#aaf0d1').grid(row=3) # we know there are 3 items before this.
mainwindow.lift() # This is a method of bringing a window to the front
def valueget(vals):
# This line gets the values from the StringVars, converts them to ints,
# and returns them to their respective variables.
try:
readA, readB, readC = [int(val.get()) for val in vals]
except ValueError:
messagebox.showerror(title="Number Error", message='Values must be numbers')
return
# Here the variables are checked to see if they are 0
# Since each one is being checked if it is 0, there is no need to check if they are all 0.
for val in (readA, readB, readC):
if val == 0:
# If they are 0, shows an error message
messagebox.showerror(title="Zero Error", message='Values must not be zero')
return
# Creates a toplevel to display the results
messagewindow = tk.Toplevel()
messagewindow.title('Roots of the equation')
messagewindow.config(bg='#aaf0d1')
negroot = (readB**2)-(4*readA*readC)
quadformulaplus = (-readB + (pow(negroot,0.5)))/(2*readA) #quad forumla
quadformulaminus = (-readB - (pow(negroot,0.5)))/(2*readA) #quad forumla
tk.Label(messagewindow,
text = f'The roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}',
bg='#aaf0d1',
font = ('verdana')).pack(padx = 5, pady = 2)
tk.Button(messagewindow,
text='Close',
command = messagewindow.destroy, # There is no need for a lambda for this.
font = ('verdana'),
bg = '#aaf0d1',
highlightbackground='#aaf0d1').pack(padx = 5, pady = 2)
# print(f'the roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}')
messagewindow.lift() # This is a method of bringing a window to the front
def startup():
startpage = tk.Tk()
startpage.title('Solver')
# COMMENTED OUT FOR TESTING
#photo = tk.PhotoImage(file = r"/Users/isa/Desktop/DiffEqns/cover.png") #image load
coverbutton = tk.Button(startpage,
# COMMENTED OUT FOR TESTING
#image = photo,
text = "TESTING", # HERE FOR TESTING
highlightbackground='#aaf0d1',
command = lambda root = startpage: mainwindow(root)).pack() # Passes the startpage to the mainwindow function.
startpage.mainloop() # The only mainloop you need.
startup()
I would recommend to improve the readability of the if-else statement for a start.
coefficients = [readA, readB, readC]
if sum(coefficients): # If they all are all zeros this will be False
if min(coefficients): # If any one is zero, this will be False
label = tk.Label(messagewindow, text = f'The roots are {quadformulaplus:.1f} and {quadformulaminus:.1f}', bg='#aaf0d1', font = ('verdana'))
label.grid(row=1)
closebutton = tk.Button(messagewindow, text='Close', command = lambda: messagewindow.destroy(), font = ('verdana'), highlightbackground='#aaf0d1')
closebutton.grid(row=2)
closebutton.config(bg='#aaf0d1')
else:
errorwindow = tk.messagebox.showerror(message='none').pack()
else:
errorwindow = tk.messagebox.showerror(message='none').pack()

Changing text of labels defined in a loop

I'm trying to make a scalable counter.
In the first window you enter how many counters you want.
In the second window there are labels and buttons used to add one to the label.
Here is my code:
from tkinter import *
root = Tk()
def newWindow():
window = Toplevel()
for i in range(int(textbox.get())):
exec("global label"+ str(i))
exec("label" + str(i) + " = Label(window, text = '0')")
exec("label" + str(i) + ".grid(row = 0, column = i)")
exec("global button"+ str(i))
exec("button" + str(i) + " = Button(window, text = 'Add', command = lambda: setText(label" + str(i) + "))")
exec("button" + str(i) + ".grid(row = 1, column = i)")
def setText(label):
label.config(text = str(int(label.cget("text")) + 1))
textbox = Entry(root)
textbox.grid(row = 0)
submitButton = Button(root, text = "Submit", command = newWindow)
submitButton.grid(row = 0, column = 1)
root.mainloop()
However this is the error I get:
name 'label_' is not defined
where _ is i.
Making them global didn't fix this either.
Help please!
If you're using exec in this way, you're doing something very wrong.
The simple solution is to add widgets to a list or dictionary. Though, in this specific case you don't need that because you're never referencing the label anywhere but in the button command.
Here's a working example:
from tkinter import *
root = Tk()
def newWindow():
global labels
window = Toplevel()
labels = {}
for i in range(int(textbox.get())):
label = Label(window, text='0')
button = Button(window, text='Add', command = lambda l=label: setText(l))
label.grid(row=0, column=i)
button.grid(row=1, column=i)
# this allows you to access any label later with something
# like labels[3].configure(...)
labels[i] = label
def setText(label):
label.config(text = str(int(label.cget("text")) + 1))
textbox = Entry(root)
textbox.grid(row = 0)
submitButton = Button(root, text = "Submit", command = newWindow)
submitButton.grid(row = 0, column = 1)
root.mainloop()
If you wanted to make use of labels, you could have your button pass in the index, and let setText get the widget from the dictionary:
def setText(i):
label = labels[i]
label.configure(...)
...
button = Button(..., command=lambda i=i: setText(i))

How to display output of print() in GUI python

I am new in creating GUI. I am doing it in Python with Tkinter. In my program I calculate following characteristics
def my_myfunction():
my code ...
print("Centroid:", centroid_x, centroid_y)
print("Area:", area)
print("Angle:", angle)
I would like to ask for any help/tips how to display those values in GUI window or how to save them in .txt file so that I can call them in my GUI
Thanks in advance
Tkinter is easy and an easy way to do a GUI, but sometimes it can be frustrating. But you should have read the docs before.
However, you can do in this way.
from tkinter import *
yourData = "My text here"
root = Tk()
frame = Frame(root, width=100, height=100)
frame.pack()
lab = Label(frame,text=yourData)
lab.pack()
root.mainloop()
There are several ways to display the results of any operation in tkiner.
You can use Label, Entry, Text, or even pop up messages boxes. There are some other options but these will probably be what you are looking for.
Take a look at the below example.
I have a simple adding program that will take 2 numbers and add them together. It will display the results in each kind of field you can use as an output in tkinter.
import tkinter as tk
from tkinter import messagebox
class App(tk.Frame):
def __init__(self, master):
self.master = master
lbl1 = tk.Label(self.master, text = "Enter 2 numbers to be added \ntogether and click submit")
lbl1.grid(row = 0, column = 0, columnspan = 3)
self.entry1 = tk.Entry(self.master, width = 5)
self.entry1.grid(row = 1, column = 0)
self.lbl2 = tk.Label(self.master, text = "+")
self.lbl2.grid(row = 1, column = 1)
self.entry2 = tk.Entry(self.master, width = 5)
self.entry2.grid(row = 1, column = 2)
btn1 = tk.Button(self.master, text = "Submit", command = self.add_numbers)
btn1.grid(row = 2, column = 1)
self.lbl3 = tk.Label(self.master, text = "Sum = ")
self.lbl3.grid(row = 3, column = 1)
self.entry3 = tk.Entry(self.master, width = 10)
self.entry3.grid(row = 4, column = 1)
self.text1 = tk.Text(self.master, height = 1, width = 10)
self.text1.grid(row = 5, column = 1)
def add_numbers(self):
x = self.entry1.get()
y = self.entry2.get()
if x != "" and y != "":
sumxy = int(x) + int(y)
self.lbl3.config(text = "Sum = {}".format(sumxy))
self.entry3.delete(0, "end")
self.entry3.insert(0, sumxy)
self.text1.delete(1.0, "end")
self.text1.insert(1.0, sumxy)
messagebox.showinfo("Sum of {} and {}".format(x,y),
"Sum of {} and {} = {}".format(x, y, sumxy))
if __name__ == "__main__":
root = tk.Tk()
myapp = App(root)
root.mainloop()

Categories