Where can I store an image on Tkinter using grid() method? - python

I am creating a login system with Tkinter and the grid() method but I have no idea where I can put the image. As i did not use classes and functions, it was pretty easy to embed the path for the image (img = PhotoImage(file = r"C:\\Users\\admin\\Desktop\\Foto\\Haken.png") img1 = img.subsample(10,10), but, since I am new in Python, I donĀ“t really know where to put the path in this code when the code is more organized. Here is what I tried:
from tkinter import *
from tkinter.ttk import *
class Login_system(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Login System Prova")
Label(text = "Surname").grid(row=0, column=0, sticky=W, pady=2)
Label(text = "Your Password").grid(row=1, column=0, sticky=W, pady=2)
Label(text = "Your E-Mail").grid(row=2, column=0,sticky=W, pady=2)
Entry().grid(row = 0, column=1, pady=2)
Entry().grid(row = 1, column=1, pady=2)
Entry().grid(row = 2, column=1, pady=2)
Entry().grid(row = 3, column=1, pady=2)
Checkbutton(text = "Keep me on-line").grid(row = 4, sticky = W, columnspan= 1)
def main():
root = Tk()
root.geometry("200x150+400+300")
root.resizable(True, True)
global image
image = Frame.PhotoImage(file = r"C:\\Users\\admin\\Desktop\\Foto\\Haken.png")
app = Login_system(root)
root.mainloop()
if __name__ == "__main__":
main()
But I get this error:
Traceback (most recent call last):
File "C:\Users\admin\Desktop\Python\GUI APP\login_system_new.py", line 40, in <module>
main()
File "C:\Users\admin\Desktop\Python\GUI APP\login_system_new.py", line 34, in main
image = Frame.PhotoImage(file = r"C:\\Users\\admin\\Desktop\\Foto_Marco\\Haken.png")
AttributeError: type object 'Frame' has no attribute 'PhotoImage'
[Finished in 0.5s]
Have you got any suggestion? I would like to put the image on the far right column.

If the image is part of the Login_system, then it is better put it inside the class. Also you forget to specify the parent of widgets inside the class, so the widgets will be children of root instead.
Also avoid importing modules like below:
from tkinter import *
from tkinter.ttk import *
In this case, you cannot use some of the widgets from tkinter because they are override by those from ttk.
Below is a modified sample based on your code:
import tkinter as tk
from tkinter import ttk
class Login_system(ttk.Frame):
def __init__(self, parent):
ttk.Frame.__init__(self, parent)
self.initUI()
def initUI(self):
self.master.title("Login System Prova")
ttk.Label(self, text="Surname").grid(row=0, column=0, sticky=tk.W, pady=2)
ttk.Label(self, text="Your Password").grid(row=1, column=0, sticky=tk.W, pady=2)
ttk.Label(self, text="Your E-Mail").grid(row=2, column=0, sticky=tk.W, pady=2)
ttk.Entry(self).grid(row=0, column=1, pady=2)
ttk.Entry(self).grid(row=1, column=1, pady=2)
ttk.Entry(self).grid(row=2, column=1, pady=2)
ttk.Entry(self).grid(row=3, column=1, pady=2)
ttk.Checkbutton(self, text="Keep me on-line").grid(row=4, sticky=tk.W, columnspan=2)
self.image = tk.PhotoImage(file=r"C:\\Users\\admin\\Desktop\\Foto\\Haken.png").subsample(10,10)
ttk.Label(self, image=self.image).grid(row=0, column=2, rowspan=5, padx=(20,0))
def main():
root = tk.Tk()
#root.geometry("200x150+400+300")
#root.resizable(True, True)
app = Login_system(root)
app.pack(fill='both', expand=1, padx=10, pady=10)
root.mainloop()
if __name__ == "__main__":
main()

Related

Getting multi-tabbed tkinter application with buttons to work properly

I have a small test application using Python tkinter that I got to work. The problem is that it does not exit properly when the "Quit" button is pressed. It is a two-frame tabbed application where I started with the StackOverflow question ttk tkinter multiple frames/windows.
It is now a full example that works, but needs work because it doesn't quit and exit properly. When I press the "Quit" button, it kills the frame for that tab, but the application doesn't quit and exit properly. I have to hit the Window "X" Close icon to close it.
My main question is how (and where?) do I test for the event on either the "Quit" button on the "Feet to Meters" calculator, or the "Cancel/Quit" button on the BMI calculator.
A second question I have is that the design of the application seems inefficient to me, because it creates two widgets "Frame" objects, each with their own set of buttons, including 2 "quit" buttons. How do I put these tabs and frames into a parent window and then add a quit button on that parent window to close the entire application.
I modified the buttons to properly destroy the Frame that the button is in:
Changed button2 "command=self.quit" to "command=self.destroy"
self.button2 = ttk.Button(self, text="Cancel/Quit", command=self.quit).grid(row=3, column=1, sticky=E)
to
self.button2 = ttk.Button(self, text="Cancel/Quit", command=self.destroy).grid(row=3, column=1, sticky=E)
""" Created on Thu Jul 11 17:20:22 2019 """
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
class App1(ttk.Frame):
""" This application calculates BMI and returns a value. """
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.createWidgets()
def createWidgets(self):
#text variables
self.i_height = StringVar()
self.i_weight = StringVar()
self.o_bmi = StringVar()
#labels
self.label1 = ttk.Label(self, text="Enter your weight:").grid(row=0, column=0, sticky=W)
self.label2 = ttk.Label(self, text="Enter your height:").grid(row=1, column=0, sticky=W)
self.label3 = ttk.Label(self, text="Your BMI is:").grid(row=2, column=0, sticky=W)
#text boxes
self.textbox1 = ttk.Entry(self, textvariable=self.i_weight).grid(row=0, column=1, sticky=E)
self.textbox2 = ttk.Entry(self, textvariable=self.i_height).grid(row=1, column=1, sticky=E)
self.textbox3 = ttk.Entry(self, textvariable=self.o_bmi).grid(row=2, column=1, sticky=E)
#buttons
self.button1 = ttk.Button(self, text="Ok", command=self.calculateBmi).grid(row=3, column=2, sticky=E)
## Changed button2 "command=self.quit" to "command=self.destroy"
# self.button2 = ttk.Button(self, text="Cancel/Quit", command=self.quit).grid(row=3, column=1, sticky=E)
self.button2 = ttk.Button(self, text="Cancel/Quit", command=self.destroy).grid(row=3, column=1, sticky=E)
#exitApplication = tk.Button(root, text='Exit Application', command=root.destroy)
#canvas1.create_window(85, 300, window=exitApplication)
def calculateBmi(self):
try:
self.weight = float(self.i_weight.get())
self.height = float(self.i_height.get())
self.bmi = self.weight / self.height ** 2.0
self.o_bmi.set(self.bmi)
except ValueError:
messagebox.showinfo("Error", "You can only use numbers.")
finally:
self.i_weight.set("")
self.i_height.set("")
class App2(ttk.Frame):
""" Application to convert feet to meters or vice versa. """
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""Create the widgets for the GUI"""
# 1 textbox (stringvar)
self.entry= StringVar()
self.textBox1= ttk.Entry(self, textvariable=self.entry).grid(row=0, column=1)
# 5 labels (3 static, 1 stringvar)
self.displayLabel1 = ttk.Label(self, text="feet").grid(row=0, column=2, sticky=W)
self.displayLabel2 = ttk.Label(self, text="is equivalent to:").grid(row=1, column=0)
self.result= StringVar()
self.displayLabel3 = ttk.Label(self, textvariable=self.result).grid(row=1, column=1)
self.displayLabel4 = ttk.Label(self, text="meters").grid(row=1, column=2, sticky=W)
# 2 buttons
self.calculateButton = ttk.Button(self, text="Calculate", command=self.convert_feet_to_meters).grid(row=2, column=2, sticky=(S,E))
self.quitButton = ttk.Button(self, text="Quit", command=self.destroy).grid(row=2, column=1, sticky=(S,E))
#exitApplication = tk.Button(root, text='Exit Application', command=root.destroy)
#canvas1.create_window(85, 300, window=exitApplication)
def convert_feet_to_meters(self):
"""Converts feet to meters, uses string vars and converts them to floats"""
self.measurement = float(self.entry.get())
self.meters = self.measurement * 0.3048
self.result.set(self.meters)
### CODE BELOW COMMENTED OUT WHEN JOINING ORIGINAL POSTER CODE WITH HIS SOLUTION
### It seems no longer relevant since App1 and App2 have their own buttons.
#def button1_click():
# """ This is for the BMI Calculator Widget """
# root = Tk()
# app = App1(master=root)
# app.mainloop()
#
#def button2_click():
# """ This is for the Feet to Meters Conversion Widget """
# root = Tk()
# app = App2(master=root)
# app.mainloop()
#def main():
# window = Tk()
# button1 = ttk.Button(window, text="bmi calc", command=button1_click).grid(row=0, column=1)
# button2 = ttk.Button(window, text="feet conv", command=button2_click).grid(row=1, column=1)
# window.mainloop()
def main():
#Setup Tk()
window = Tk()
#Setup the notebook (tabs)
notebook = ttk.Notebook(window)
frame1 = ttk.Frame(notebook)
frame2 = ttk.Frame(notebook)
notebook.add(frame1, text="BMI Calc")
notebook.add(frame2, text="Feet to Meters")
notebook.grid()
#Create tab frames
app1 = App1(master=frame1)
app1.grid()
app2 = App2(master=frame2)
app2.grid()
#Main loop
window.mainloop()
if __name__ == '__main__':
main()
The application doesn't quit when the "Quit" button is pressed. Only the individual frames quit.
Thanks to Martineau for the hint that helped me get this example to work. I declared 'window as a global variable, since it was defined in the name space of the class constructors. Without that, there was an error raised of undefined window. This method breaks the encapsulation and modularity of the classes by passing in the window as a global. If there is a better way to do this, I would like to know.
# -*- coding: utf-8 -*-
""" Created on Thu Jul 11 17:20:22 2019
Filename: tkinter-multiple-frames-windows_v3.py
From question on StackOverflow question "ttk tkinter multiple frames/windows"
at https://stackoverflow.com/questions/6035101/ttk-tkinter-multiple-frames-windows?rq=1
Now a full example that works but it needed some modification to clarify how it works.
"""
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
class BMICalcApp(ttk.Frame):
""" This application calculates BMI and returns a value. """
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.createWidgets()
def createWidgets(self):
#text variables
self.i_height = StringVar()
self.i_weight = StringVar()
self.o_bmi = StringVar()
#labels
self.label1 = ttk.Label(self, text="Enter your weight:").grid(row=0, column=0, sticky=W)
self.label2 = ttk.Label(self, text="Enter your height:").grid(row=1, column=0, sticky=W)
self.label3 = ttk.Label(self, text="Your BMI is:").grid(row=2, column=0, sticky=W)
#text boxes
self.textbox1 = ttk.Entry(self, textvariable=self.i_weight).grid(row=0, column=1, sticky=E)
self.textbox2 = ttk.Entry(self, textvariable=self.i_height).grid(row=1, column=1, sticky=E)
self.textbox3 = ttk.Entry(self, textvariable=self.o_bmi).grid(row=2, column=1, sticky=E)
#buttons
self.button1 = ttk.Button(self, text="Ok", command=self.calculateBmi).grid(row=3, column=2, sticky=E)
self.button2 = ttk.Button(self, text="Cancel/Quit", command=window.destroy).grid(row=3, column=1, sticky=E)
def calculateBmi(self):
try:
self.weight = float(self.i_weight.get())
self.height = float(self.i_height.get())
self.bmi = self.weight / self.height ** 2.0
self.o_bmi.set(self.bmi)
except ValueError:
messagebox.showinfo("Error", "You can only use numbers.")
finally:
self.i_weight.set("")
self.i_height.set("")
class ConvertFeetMeters(ttk.Frame):
""" Application to convert feet to meters or vice versa. """
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""Create the widgets for the GUI"""
# 1 textbox (stringvar)
self.entry= StringVar()
self.textBox1= ttk.Entry(self, textvariable=self.entry).grid(row=0, column=1)
# 5 labels (3 static, 1 stringvar)
self.displayLabel1 = ttk.Label(self, text="feet").grid(row=0, column=2, sticky=W)
self.displayLabel2 = ttk.Label(self, text="is equivalent to:").grid(row=1, column=0)
self.result= StringVar()
self.displayLabel3 = ttk.Label(self, textvariable=self.result).grid(row=1, column=1)
self.displayLabel4 = ttk.Label(self, text="meters").grid(row=1, column=2, sticky=W)
# 2 buttons
self.calculateButton = ttk.Button(self, text="Calculate", command=self.convert_feet_to_meters).grid(row=2, column=2, sticky=(S,E))
self.quitButton = ttk.Button(self, text="Quit", command=window.destroy).grid(row=2, column=1, sticky=(S,E))
def convert_feet_to_meters(self):
"""Converts feet to meters, uses string vars and converts them to floats"""
self.measurement = float(self.entry.get())
self.meters = self.measurement * 0.3048
self.result.set(self.meters)
def main():
#Setup Tk()
global window
window = Tk()
#Setup the notebook (tabs)
notebook = ttk.Notebook(window)
frame1 = ttk.Frame(notebook)
frame2 = ttk.Frame(notebook)
notebook.add(frame1, text="BMI Calc")
notebook.add(frame2, text="Feet to Meters")
notebook.grid()
#Create tab frames
bmi_calc = BMICalcApp(master=frame1)
bmi_calc.grid()
feet_meters_calc = ConvertFeetMeters(master=frame2)
feet_meters_calc.grid()
#Main loop
window.mainloop()
if __name__ == '__main__':
main()

Tkinter entry insert from another class

I am learning a bit of tkinter at the moment and have come across a problem I can't seem to solve.
I have 1 class (named 'GUI') in which I first declare an object of another class (named 'client') then create a simple tkinter GUI with an entry field in which the user enters an address.
I then have a button that when pressed, gets the address and passes it to a function of the client class. This function calls another function from a library, which goes out to an external source (the 'client') and gets the value of a boolean register at that address.
Up to here I have working.
I now would like to update another entry field in the tkinter GUI with the value of that Boolean register.
Here is a code sample:
class GUI:
def __init__(self, master):
device = client()
self.master = master
#Define size (x,y) and position (top left is 0,0) of window
master.geometry("800x400+300+300")
#Disable window resize
master.resizable(width=False, height=False)
#GUI Controls
lbl_read_discrete_output = Label(self.master, text="Read boolean register")
lbl_read_discrete_output_address = Label(self.master, text="Address:")
ent_read_discrete_output_address = Entry(self.master)
btn_read_discrete_output_address = Button(self.master, text='READ', command=lambda: device.read_discrete_output(int(ent_read_discrete_output_address.get())))
ent_read_discrete_output_value = Entry(self.master, state='disabled')
#GUI Layout
lbl_read_discrete_output.grid(column=0, row=6, padx=5, pady=5)
lbl_read_discrete_output_address.grid(column=0, row=7, padx=5, pady=5)
ent_read_discrete_output_address.grid(column=1, row=7, padx=5, pady=5)
btn_read_discrete_output_address.grid(column=2, row=7, padx=5, pady=5)
ent_read_discrete_output_value.grid(column=3, row=7, padx=5, pady=5)
class client:
def __init__(self):
pass
def read_discrete_output(self, address):
data = self._client.read_coils(address-1, 1).bits[0:1]
if not data[0]:
#Update entry field 'ent_read_discrete_output_value' with "FALSE"
else:
#Update entry field 'ent_read_discrete_output_value' with "TRUE"
def main():
#Create GUI object
root = Tk()
app = GUI(root)
root.mainloop()
if __name__ == '__main__':
main()
Any help would be greatly appreciated!
You can solve that problem, this way:
import tkinter as tk
from tkinter import *
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
class GUI:
def __init__(self, master):
self.master = master
#GUI Controls
lbl_read_discrete_output = Label(self.master, text="Read boolean register")
lbl_read_discrete_output_address = Label(self.master, text="Address:")
self.ent_read_discrete_output_address = Entry(self.master)
btn_read_discrete_output_address = Button(self.master, text='READ', command=lambda: device.read_discrete_output(int(self.ent_read_discrete_output_address.get())))
self.ent_read_discrete_output_value = Entry(self.master, state='disabled')
#GUI Layout
lbl_read_discrete_output.grid(column=0, row=6, padx=5, pady=5)
lbl_read_discrete_output_address.grid(column=0, row=7, padx=5, pady=5)
self.ent_read_discrete_output_address.grid(column=1, row=7, padx=5, pady=5)
btn_read_discrete_output_address.grid(column=2, row=7, padx=5, pady=5)
self.ent_read_discrete_output_value.grid(column=3, row=7, padx=5, pady=5)
self.x=self.ent_read_discrete_output_address.get()
print(self.x)
device=clientx(self.ent_read_discrete_output_value,self.ent_read_discrete_output_address.get())
class clientx():
def __init__(self,ent,address):
self.address=address
self.ent=ent
def read_discrete_output(self, address):
with ModbusClient('127.0.0.1') as client:
data = self.client.read_coils(address-1, 1).bits[0:1]
if not data[0]:
self.ent.config(state="disabled")
else:
self.ent.config(state="disabled")
def main():
#Create GUI object
root = tk.Tk()
app = GUI(root)
root.mainloop()
if __name__ == '__main__':
main()
Let me know if this works.

Python 3 tkinter image displayed in wrong column

I want my label to be displayed in the same column as the picture. Both of them are generated with a click. I place them in the same column of the grid, but the image is displayed in the neighbour column. What's the reason and how to correct it?
Here's my simplified code.
from tkinter import *
from tkinter import ttk
class App(Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master, padding='20')
self.grid(column=0, row=0, sticky=(N, W, E, S))
self.create_button()
def create_button(self):
self.button = ttk.Button(self,
text="Click",
width=12,
command=lambda: self.display_name_and_picture()
).grid(column=2, columnspan=2, row=1, sticky=NW)
def display_name_and_picture(self):
random_label = ttk.Label(self, font=(None, 16), text='random random')
random_label.grid(row=0, column=5, sticky=N)
random_image = PhotoImage(file='random.gif')
label = Label(image=random_image)
label.image = random_image
label.grid(row=1, column=5, sticky=NW)
root = Tk()
root.title("Random something...")
root.geometry("600x300")
app = App(root)
root.mainloop()
The culprit is this line
label = Label(image=random_image)
You create label without specifying its parent, so its parent defaults to root. But random_label has app as its parent, and app in turn has root as its parent. So label is gridded side by side with app --- inside root --- and not inside app as you wished. Just change the above line to
label = Label(self, image=random_image)
and you should be fine.
(Well, not totally fine. You should also fix the things people pointed out in comments.)
I monkeyed around with this for a while and produced something that does what you are asking. I would love to have somebody explain why this works. The columns look goofy.
Check it out:
from tkinter import *
from tkinter import ttk
class App(Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master, padding='20')
self.grid(column=0, row=0, sticky=(N, W, E, S))
self.create_button()
def create_button(self):
self.button = ttk.Button(self,
text="Click",
width=12,
command=self.display_name_and_picture
)
self.button.grid(column=0, columnspan=2, row=0, sticky=NW)
def display_name_and_picture(self):
random_label = ttk.Label(self, font=(None, 16), text='random random')
random_label.grid(row=0, column=2)
random_image = PhotoImage(file='random.gif')
label = Label(image=random_image)
label.image = random_image
label.grid(row=1, column=0)
root = Tk()
root.title("Random something...")
root.geometry("600x300")
app = App(root)
root.mainloop()

Python tkinter add new field by a button

It is python 3.4 here, and the program import tkinter module to build gui interface.
I am wondering how to make a button that is able to add new field for user to fill.
Try to apply built-in method vars() and getattr() but it doesn't work.
I just cannot figure out why AttributeError always pop up.
The following is a part of my code:
import tkinter as Tk
from tkinter import ttk
class dictionary(Tk.Frame):
def __init__(self, master=None):
Tk.Frame.__init__(self, master)
#......other line here........
def createWidgets(self):
self.row_c = 0
self.new_0 = Tk.StringVar(self)
self.new_0field = ttk.Entry(self, textvariable=self.new_0)
self.new_0field.grid(row=self.row_c, column=0, columnspan=2, padx=4, pady=6, sticky="NEWS")
self.add_lang = ttk.Button(self, text="add language", command=self.add_field)
self.add_lang.bind("<Return>", self.add_field)
self.add_lang.grid(row=self.row_c, column=3, padx=4, pady=6, sticky="W")
self.row_c += 1
def add_field(self):
#count is a number (string type)
count = str(self.row_c)
vars()["self.new_" + count] = Tk.StringVar(self)
vars()["self.new_" + count + "field"] = ttk.Entry(self, textvariable=getattr(self, "self.new_"+count))
vars()["self.new_" + count + "field"].grid(row=self.row_c+1, column=0, columnspan=2, padx=4, pady=6, sticky="NEWS")
self.add_lang.grid(row=self.row_c+1, column=3, padx=4, pady=6, sticky="W")
if __name__ == '__main__':
root = Tk.Tk()
app = dictionary(master=root)
app.mainloop()
Is it possible to add a field by a button in tkinter?
I would be grateful if there is any suggestion to make it work,
Thanks!
So this is my solution:
import tkinter as tk
from tkinter import ttk
class dictionary(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.fields = []
self.createWidgets()
self.grid(column=0, sticky="NEWS")
def createWidgets(self):
self.add_field()
self.add_lang = ttk.Button(self, text="add language", command=self.add_field)
self.add_lang.bind("<Return>", self.add_field)
self.add_lang.grid(row=len(self.fields), column=3, padx=4, pady=6, sticky="W")
def add_field(self):
self.fields.append({})
n = len(self.fields)-1
self.fields[n]['var'] = tk.StringVar(self)
self.fields[n]['field'] = ttk.Entry(self, textvariable=self.fields[n]['var'])
self.fields[n]['field'].grid(row=n, column=0, columnspan=2, padx=4, pady=6, sticky="NEWS")
if n:
self.add_lang.grid(row=n + 1, column=3, padx=4, pady=6, sticky="W")
if __name__ == '__main__':
root = tk.Tk()
app = dictionary(master=root)
app.mainloop()
I hope this is what you wanted.

python, tkinter: how all variables can be obtained by single button from all notebook tabs?

I need to return all variables from all tabs by clicking on ok button.
I have two tabs. What I want is that when I enter some value in 2nd tab, it should automatically appear in first tab in 'height' entry.
Then if I click 'ok' in first tab, it should return all variables(from first tab and 2nd tab) to my 'main' program for further use.
Thanks
from tkinter import *
from tkinter import ttk
class App1(ttk.Frame):
def createWidgets(self):
#text variables
self.i_height = StringVar()
self.i_weight = StringVar()
self.o_bmi = StringVar()
#labels
self.label1 = ttk.Label(self, text="Enter your weight:").grid(row=0, column=0, sticky=W)
self.label2 = ttk.Label(self, text="Enter your height:").grid(row=1, column=0, sticky=W)
self.label3 = ttk.Label(self, text="Your BMI is:").grid(row=2, column=0, sticky=W)
#text boxes
self.textbox1 = ttk.Entry(self, textvariable=self.i_weight).grid(row=0, column=1, sticky=E)
self.textbox2 = ttk.Entry(self, textvariable=self.i_height).grid(row=1, column=1, sticky=E)
self.textbox3 = ttk.Entry(self, textvariable=self.o_bmi).grid(row=2, column=1, sticky=E)
#buttons
self.button1 = ttk.Button(self, text="Cancel/Quit", command=self.quit).grid(row=3, column=1, sticky=E)
self.button1 = ttk.Button(self, text="Ok", command=self.calculateBmi).grid(row=3, column=2, sticky=E)
def calculateBmi(self):
try:
self.weight = float(self.i_weight.get())
self.height = float(self.i_height.get())
self.bmi = self.weight / self.height ** 2.0
self.o_bmi.set(self.bmi)
except ValueError:
messagebox.showinfo("Error", "You can only use numbers.")
finally:
self.i_weight.set("")
self.i_height.set("")
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.createWidgets()
class App2(ttk.Frame):
def create_widgets(self):
"""Create the widgets for the GUI"""
#1 textbox (stringvar)
self.entry= StringVar()
self.textBox1= ttk.Entry(self, textvariable=self.entry).grid(row=0, column=1)
#5 labels (3 static, 1 stringvar)
self.displayLabel1 = ttk.Label(self, text="feet").grid(row=0, column=2, sticky=W)
self.displayLabel2 = ttk.Label(self, text="is equivalent to:").grid(row=1, column=0)
self.result= StringVar()
self.displayLabel3 = ttk.Label(self, textvariable=self.result).grid(row=1, column=1)
self.displayLabel4 = ttk.Label(self, text="meters").grid(row=1, column=2, sticky=W)
#2 buttons
self.quitButton = ttk.Button(self, text="Quit", command=self.quit).grid(row=2, column=1, sticky=(S,E))
self.calculateButton = ttk.Button(self, text="Calculate", command=self.convert_feet_to_meters).grid(row=2, column=2, sticky=(S,E))
def convert_feet_to_meters(self):
"""Converts feet to meters, uses string vars and converts them to floats"""
self.measurement = float(self.entry.get())
self.meters = self.measurement * 0.3048
self.result.set(self.meters)
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.create_widgets()
def button1_click():
root = Tk()
app = App1(master=root)
app.mainloop()
def button2_click():
root = Tk()
app = App2(master=root)
app.mainloop()
def main():
#Setup Tk()
window = Tk()
#Setup the notebook (tabs)
notebook = ttk.Notebook(window)
frame1 = ttk.Frame(notebook)
frame2 = ttk.Frame(notebook)
notebook.add(frame1, text="BMI Calc")
notebook.add(frame2, text="Feet to Meters")
notebook.grid()
#Create tab frames
app1 = App1(master=frame1)
app1.grid()
app2 = App2(master=frame2)
app2.grid()
#Main loop
window.mainloop()
main()
You have some fundamental mistakes in your program -- you cannot have three mainloops running at the same. You should always only have exactly one instance of Tk, and call mainloop exactly once.
Regardless of that, the solution is that you need to create a method or public variable in the app, and then your button callback needs to be able to call that method or access that variable.
For example, you would do it like this:
def callback():
value1 = app1.getValue()
value2 = app2.getValue()
...

Categories

Resources