I'm attempting to write a program in tkinter where the user clicks on a button with their name and a verification page shows it to them. The problem I'm having is that the variable is either resetting or I'm accessing it wrong:
import tkinter as tk
from tkinter import *
from tkinter import ttk
LARGE_FONT = ("Times New Roman", 12)
NORM_FONT = ("Times New Roman", 10)
root = Tk()
root.withdraw()
class DIS(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default="")
tk.Tk.wm_title(self, "program")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for F in (StartPage, contactQues, nameVerify):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button2 = ttk.Button(self, text = "Name Select",
command=lambda: controller.show_frame(contactQues))
button2.pack()
class contactQues(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
global name
name = StringVar()
label1 = tk.Label(self, text = "Select Your Name", font = LARGE_FONT)
label1.pack(pady=10, padx=10)
button2 = ttk.Button(self, text = "Bojangles", command = self.bojangles)
button2.pack(pady=5)
def bojangles(self):
name.set("Mr. Bojangles")
self.controller.show_frame(nameVerify)
#
#Many other names to select
#
class nameVerify(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
namename = name.get()
label5 = tk.Label(self, text = "Your Name:", font = LARGE_FONT)
label5.pack(pady=10, padx=10)
labelcontact = tk.Label(self, text = namename, font = NORM_FONT)
labelcontact.pack()
app = DIS()
app.mainloop()
So, in essence, what I want to happen is:
- Program runs and user presses "Name select", user selects their name, and the final page shows their selection.
I've tried messing with globals, textvariables for the labelcontact label, StringVar(), etc. and can't seem to peg this one down.
Is there a better way to do this? Or am I doing something inherently wrong?
Thank you for any help.
I suggest making name an attribute of the DIS class. Then your StartPage and nameVerify instances can access it via their controller attributes. If you want labelcontact to update automatically whenever name does, use the textvariable attribute.
Additionally, you need to delete your root = Tk() and root.withdraw() lines. I don't know why, but as long as they're there, the labelcontact Label won't properly update. They don't appear to do anything in any case - hopefully they aren't crucial to your actual code.
import tkinter as tk
from tkinter import *
from tkinter import ttk
LARGE_FONT = ("Times New Roman", 12)
NORM_FONT = ("Times New Roman", 10)
class DIS(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default="")
tk.Tk.wm_title(self, "program")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.name = StringVar()
self.frames = {}
for F in (StartPage, contactQues, nameVerify):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
button2 = ttk.Button(self, text = "Name Select",
command=lambda: controller.show_frame(contactQues))
button2.pack()
class contactQues(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label1 = tk.Label(self, text = "Select Your Name", font = LARGE_FONT)
label1.pack(pady=10, padx=10)
button2 = ttk.Button(self, text = "Bojangles", command = self.bojangles)
button2.pack(pady=5)
def bojangles(self):
self.controller.name.set("Mr. Bojangles")
self.controller.show_frame(nameVerify)
#
#Many other names to select
#
class nameVerify(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label5 = tk.Label(self, text = "Your Name:", font = LARGE_FONT)
label5.pack(pady=10, padx=10)
labelcontact = tk.Label(self, textvariable = self.controller.name, font = NORM_FONT)
labelcontact.pack()
app = DIS()
app.mainloop()
Related
This is a part of my actual program. I am trying to write a code that will create few Buttons on loop.
My problem is I am passing a value to a tkinter class but it is not printing the right value instead just prints a ".".
I want to pass "chap" from class PageOne to "class ChapterOne" in the below code it isn't working. I don't have much experience in classes. A help here will be much appreciated.
import tkinter as tk
from PIL import ImageTk, Image
from os import listdir
import yaml
LARGE_FONT = ("Verdana", 12)
grey = "#808080"
offwhite = "#e3e3e3"
hintwa = False
x = ''
class MainBot(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for page in (StartPage, PageOne, ChapterOne):
frame = page(container, self)
print (container)
self.frames[page] = frame
frame.grid(row = 0, column = 0, sticky = 'nsew')
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def yaml_loader(self, filepath):
with open (filepath, "r") as fileread:
self.data = yaml.load(fileread)
return self.data
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, background = offwhite, text= "Start Page", font = LARGE_FONT)
label.pack(pady=10, padx=10)
button_start = tk.Button(self, text = 'NEXT', font = ("default", 15, "bold"), bg='orange', fg = 'white', border=2, height = 2, width = 8, command=lambda: controller.show_frame(PageOne))
button_start.pack()
button_start.place(x=650, y=500)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
index_label = tk.Label(self, text = "~~~~~INDEX~~~~~", font = ("Comicsans", 24, "bold"), background = offwhite)
index_label.pack()
index_label.place(x=200, y=50)
onlyfiles = ['chapter-1.yaml']
for yfiles in onlyfiles:
chap = (yfiles.split("."))[0].split("-")[1]
print (chap)
button_index_one = tk.Button(self, text='Chapter ' + str(chap), font=("default", 14, "bold"), bg='white',
fg='black', border=1, height=2, width=12,
command=lambda: controller.show_frame(ChapterOne(self, chap)))
button_index_one.pack(pady=30, padx=0)
class ChapterOne(tk.Frame):
def __init__(self, parent, chap):
tk.Frame.__init__(self, parent)
print (chap)
app = MainBot()
app.geometry("800x600")
app.mainloop()
I'm making an application using tkinter, and I want to access global variable that I assign a value to from a tkinter Entry by a user. I'm following an MVC pattern for the creation of the application, and every window is in it's own class and I'm struggling basically with using data from one class to the next. In this context, I want to print the username entered by the user into the label in the class PageThree I've made a minimum reproduceable version of the code here:
import tkinter as tk
from tkinter import font as tkfont
from tkinter import messagebox
stored_username = "Tessa"
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (PageTwo, PageThree):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("PageTwo")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.label_username_signup = tk.Label(self, text="Username")
self.label_password_signup = tk.Label(self, text="Password")
self.entry_username_signup = tk.Entry(self)
self.entry_password_signup = tk.Entry(self, show="*")
self.label_username_signup.grid(row=0, sticky=tk.E)
self.label_password_signup.grid(row=1, sticky=tk.E)
self.entry_username_signup.grid(row=0, column=1)
self.entry_password_signup.grid(row=1, column=1)
self.rgbtn = tk.Button(self, text="Register", command=self.log_details)
self.rgbtn.grid(columnspan=3)
button = tk.Button(self, text="Back",
command=lambda: controller.show_frame("StartPage"))
button.grid()
def log_details(self):
username = self.entry_username_signup.get()
global stored_username
stored_username = username
if username:
self.controller.show_frame("PageThree")
else:
tk.messagebox.showerror("Login Failure", "Incorrect username or password, please try again")
class PageThree(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
self.controller = controller
global stored_username
lbl = tk.Label(self,text=name_entry)
lbl.grid(row=0,column=0)
def name_entry():
global stored_username
string = stored_username.get()
return string
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
I think the closest thing to a related question I can find is: Taking input from the user in Tkinter
However they are not dealing with modular classes.
I am trying to make a fairly simple GUI with multiple windows. I have my windows built as classes just with a label in each one for now. I can't seem to figure out why when I run my program it packs all of the labels on the "StartPage" and none of the other windows have anything in them. It could be that I have my classes configured incorrectly?
import tkinter as tk
class application(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side = 'top', fill = 'both', expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for F in (StartPage, WeeklyBudget, LongtermSavings, Investments):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.ShowFrame(StartPage)
def ShowFrame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
start_label = tk.Label(self, text = 'Welcome to Finance Track!')
start_label.pack()
week_btn = tk.Button(self, text = 'Weekly Budgeting', command =lambda: controller.ShowFrame(WeeklyBudget))
savings_btn = tk.Button(self, text = 'Longterm Savings', command = lambda: controller.ShowFrame(LongtermSavings))
invest_btn = tk.Button(self, text = 'Investments', command = lambda: controller.ShowFrame(Investments))
week_btn.pack(pady = 10, padx = 10)
savings_btn.pack(pady = 10, padx = 10)
invest_btn.pack(pady = 10, padx = 10)
class WeeklyBudget(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text = 'Welcome to your Weekly Budget')
label.pack()
add_btn = tk.Button(text = 'add new week')
add_btn.pack()
class LongtermSavings(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text = 'Welcome to your Longterm Savings')
label.pack()
class Investments(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text = 'Welcome to your Investments')
label.pack()
app = application()
app.mainloop()
The current outcome as I described earlier is just one window with all the labels and all the buttons in it.
As jasonharper mention you aren't defining the parents (aka master) of many widgets.
class Investments(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text = 'Welcome to your Investments')
label.pack()
Using this Investments class for example, your label will be given the window as it's parents by default, to set it's parent to the newly created frame, just do the following:
class Investments(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = 'Welcome to your Investments')
label.pack()
I am quite new to python and tkinter and I was trying to open iamges to use them as icons on my program, so I found I have to use tk.Toplevel instead of tk.Tk. However, when I do this, the application opens two windows,the one where everything is programmed and a blank one.
Here is the full code in case anyone could help:
import tkinter as tk
from tkinter import ttk
from tkinter import PhotoImage
from PIL import Image, ImageTk
Large_Font = ("Times", 20)
class RobProject(tk.Toplevel):
def __init__(self):
tk.Toplevel.__init__(self)
tk.Tk.wm_title(self, "Com-Bot Control")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (MenuPage, PageOne, PageTwo, PageThree):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="NEWS")
self.show_frame(MenuPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class MenuPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text = "Menú", font=Large_Font)
label.pack(pady=10, padx=10)
RCB = ttk.Button(self, text="Control Remoto",
command= lambda: controller.show_frame(PageOne))
RCB.pack()
EOB = ttk.Button(self, text="EvitaObstáculos",
command= lambda: controller.show_frame(PageTwo))
EOB.pack()
SLB = ttk.Button(self, text="Siguelíneas",
command= lambda: controller.show_frame(PageThree))
SLB.pack()
img = Image.open("play-button.png")
photo = ImageTk.PhotoImage(img)
Show_Im = tk.Button(self, image=photo)
Show_Im.image = photo
Show_Im.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Control Remoto", font=Large_Font)
label.pack(pady=10, padx=10)
Back_B1 = ttk.Button(self, text="Atrás",
command= lambda: controller.show_frame(MenuPage))
Back_B1.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Evitaobstáculos", font=Large_Font)
label.pack(pady=10, padx=10)
Back_B2 = ttk.Button(self, text="Atrás",
command= lambda: controller.show_frame(MenuPage))
Back_B2.pack()
class PageThree(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Siguelíneas", font=Large_Font)
label.pack(pady=10, padx=10)
Back_B3 = ttk.Button(self, text="Atrás",
command= lambda: controller.show_frame(MenuPage))
Back_B3.pack()
app = RobProject()
app.mainloop()
Thank you in advance!
You do not need Topelevel() to use images.
Not sure where you got that info but it is not accurate.
Toplevel() is specifically to create new windows outside of the root window in tkinter.
What is happening is when you call tk.Toplevel() tkinter is creating an instance of Tk() in order to run Toplevel(). This is where the blank screen is coming from. The blank screen is actually the root window without anything in it.
To fix your problem Change:
class RobProject(tk.Toplevel):
def __init__(self):
tk.Toplevel.__init__(self)
To:
class RobProject(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
I am writing a GUI code that opens frame using Tkinter. I referred various websites. Now while testing I am facing problem. For example:
In 1st frame, I select MainController button.
in 2nd frame press MC_CONFIG button.
in 3rd frame I set XML PATH then clicked MC SYSTEM.xml button
If I go to Back to Home button and follow the same procedure, MC_CONFIG button gets disabled (i.e I cannot go further).
If I comment(delete) this line(126)
tk.Frame.__init__(self)
in method def nacxml(self): of class MC_CONFIG, it is working perfectly.
The below one is just part of my main code bu facing problem here.
Please guide me.
import Tkinter as tk
import xml.dom.minidom
from Tkinter import *
import tkMessageBox
from array import *
import tkFileDialog
import os
LARGE_FONT= ("Verdana", 12)
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Switch Installer window")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
#for F in (StartPage, PageOne, PageTwo):
for F in (StartPage, MainController,xmlpath,MC_CONFIG):
frame = F(container,self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.modules_label = ['MAINCONTROLLER']
self.modules_function = [MainController]
self.modules_label_index = len(self.modules_label)
self.modules_function_index = len(self.modules_function)
print("self.modules_label_index = %s" %self.modules_label_index)
label = Label(self, text="SWITCH INSTALLER", font=LARGE_FONT)
label.pack(pady=10,padx=10)
#button = Button(self, text="Visit Page 1",
button3 = Button(self, text="SELECT",
command=lambda: controller.show_frame(MainController))
button3.pack()
label3 = Label(self, text="MainController", font = LARGE_FONT)
label3.place(x= 50, y=100+10)
button8 = Button(self, text="Quit", command=self.quit)
button8.pack()
class xmlpath(tk.Frame):
#xfilename="+++"
def __init__(self, parent, controller):
self.xfilename="srinivasan"
tk.Frame.__init__(self, parent)
label = Label(self, text="Page One!!!", font=LARGE_FONT)
label.pack(pady=10,padx=10)
button1 = Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
button1 = Button(self, text="XML PATH",
command=self.newxmlpath)
button1.pack()
def newxmlpath(self,*args):
# ObjNAC= NacHandler()
self.filename = tkFileDialog.askopenfilename()
print(self.filename)
#ObjNAC.temp_method(self,self.filename)
return self.filename
class MainController(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = Label(self, text="|--Frame1 MainController --|", font = LARGE_FONT)
label.pack(pady=10,padx=10)
mc_button1 = Button(self, text="MC_CONFIG", command = lambda: controller.show_frame(MC_CONFIG))
mc_button1.pack()
mc_button2 = Button(self, text="MENU HOME", command = lambda: controller.show_frame(StartPage))
mc_button2.pack()
self.pack (fill = BOTH, expand = 1)
class MC_CONFIG(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
print "Inside MC_CONFIG"
self.database = []
# set root as parent
self.parent = parent
label1 = Label(self, text="|------------Frame2--MainController---------------|", font=LARGE_FONT)
label1.pack(pady = 10,padx = 10)
label2 = Label(self, text="Edit SYSTEM.xml File", font=LARGE_FONT)
label2.pack(pady = 10,padx = 10)
button1 = Button(self, text="XML PATH",
command=self.newxmlpath)
button1.pack(pady = 10,padx = 10)
button2 = Button(self, text = "MC SYSTEM.xml", command = self.nacxml)
button2.pack(pady = 10,padx = 10)
button3 = Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button3.pack(pady = 10,padx = 10)
def newxmlpath(self, *args):
self.filename = tkFileDialog.askopenfilename()
print(self.filename)
return self.filename
def nacxml(self):
tk.Frame.__init__(self)
print "===Inside Nacxml1==="
app = SeaofBTCapp()
app.geometry ("640x480+300+300")
app.mainloop()
The problem is this:
def nacxml(self):
tk.Frame.__init__(self)
You should only ever call the superclass constructor from within the constructor of the subclass. Doing so anywhere else will certainly not do whatever you think it's doing.
Finally code is working as intended
1.Deleted tk.Frame.__init__(self) as indicated by Bryan Oakley
def nacxml(self):
tk.Frame.__init__(self)
2.Controller is not intialized in self.But it is present in def __init__(self, parent, controller):.Hence added
self.controller = controller in MC_CONFIG class
class MC_CONFIG(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
print "Inside MC_CONFIG"
So can be used in below method as self.controller.show_frame(StartPage)
def nacxml(self):
tk.Frame.__init__(self)
print "===Inside Nacxml1==="
# xml read,edit,widget code will be added here
self.controller.show_frame(StartPage)