I'm trying a simple experiment, I have 3 frames, frame 1 has two labels - "for page 2" and "for page 3", it also has 2 radio buttons corresponding to the labels. based on which radio button is selected, when the user hits the next page button, I want the button to bring the user to the selected page
this is the code -
import Tkinter as tk
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the main container that holds all the frames
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 = {}
# adding frames to the dictionary
for F in (Page1,Page2,Page3):
frame = F(container,self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "w")
self.show_frame(Page1)
def show_frame(self,page_name):
#SHOWS A FRAME WITH THE GIVEN NAME
for frame in self.frames.values():
frame.grid_remove()
frame = self.frames[page_name]
frame.grid()
#STACKING THE FRAMES
#frame = self.frames[cont]
#frame.tkraise()
class Page1(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lbl1 = tk.Label(self,text = "for page 2",font =("Helvetica",12,"bold"))
lbl1.grid(row=1,sticky="W")
lbl2 = tk.Label(self,text = "for page 3",font =("Helvetica",12,"bold"))
lbl2.grid(row=1,column=1,sticky="W")
btn1 = tk.Button(self, text="next page", font=('MS', 24, 'bold'))
btn1.grid(row=3,column = 0,columnspan=1)
#btn1['command'] = lambda: controller.show_frame(Page2)
self.var1 = tk.BooleanVar()
rButton1 = tk.Radiobutton(self,variable = self.var1,value=True)
rButton1.grid(row=2,sticky = "W")
rButton2 = tk.Radiobutton(self,variable = self.var1,value=False)
rButton2.grid(row=2,column=1,sticky = "W")
if self.var1.get() == 1:
btn1['command'] = lambda: controller.show_frame(Page3)
if self.var1.get() == 0:
btn1['command'] = lambda: controller.show_frame(Page2)
class Page2(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lbl = tk.Label(self,text="This is page 2",font=("Helvetica",12,"bold"))
lbl.pack()
class Page3(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lbl = tk.Label(self,text="This is page 3",font=("Helvetica",12,"bold"))
lbl.pack()
app = MainApp()
app.mainloop()
I assumed that by using a few basic conditions (located in my PageOne class) -
self.var1 = tk.BooleanVar()
rButton1 = tk.Radiobutton(self,variable = self.var1,value=True)
rButton1.grid(row=2,sticky = "W")
rButton2 = tk.Radiobutton(self,variable = self.var1,value=False)
rButton2.grid(row=2,column=1,sticky = "W")
if self.var1.get() == 1:
btn1['command'] = lambda: controller.show_frame(Page3)
if self.var1.get() == 0:
btn1['command'] = lambda: controller.show_frame(Page2)
I would be able to achieve this, but it doesn't seem to work. The conditions in my if statements are integers but to my knowledge 1 represents True and 0; False anyway? what am i doing wrong?
I think this is what you want. I didn't handle making sure the radiobutton isn't selected by default. I left that as an exercise to you. Although, if you're wanting to just switch pages like this I'd just use buttons (tk/ttk.Button), then you don't have to worry about handling the radiobutton. Although, that's just my preference either will work fine of course. You can just bind each button to switch the page. I commented the buttons out in your modified code below.
If you're wanting to create buttons / radiobuttons to have a forward / back option for each page. You can just iterate over the controllers frames to see which is the current, and create two buttons similar to the ones below to move to the other frames.
import tkinter as tk
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the main container that holds all the frames
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 = {}
# adding frames to the dictionary
for F in (Page1,Page2,Page3):
frame = F(container,self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "w")
self.show_frame(Page1)
def show_frame(self,page_name):
#SHOWS A FRAME WITH THE GIVEN NAME
for frame in self.frames.values():
frame.grid_remove()
frame = self.frames[page_name]
frame.grid()
#STACKING THE FRAMES
#frame = self.frames[cont]
#frame.tkraise()
class Page1(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
self.controller = controller
lbl1 = tk.Label(self,text = "for page 2",font =("Helvetica",12,"bold"))
lbl1.grid(row=1,sticky="W")
lbl2 = tk.Label(self,text = "for page 3",font =("Helvetica",12,"bold"))
lbl2.grid(row=1,column=1,sticky="W")
btn1 = tk.Button(self, text="next page", font=('MS', 24, 'bold'))
btn1.grid(row=3,column = 0,columnspan=1)
#btn1['command'] = lambda: controller.show_frame(Page2)
self.var1 = tk.BooleanVar()
#rButton1 = tk.Button(self, text='Show Page 2', command=lambda: self.controller.show_frame(Page2))
#rButton1.grid(row=2, sticky="W")
#rButton2 = tk.Button(self, text='Show Page 3', command=lambda: self.controller.show_frame(Page3))
#rButton2.grid(row=2, column=1, sticky="W")
rButton1 = tk.Radiobutton(self,variable = self.var1,value=True,
command=self.switch_pages)
rButton1.grid(row=2,sticky = "W")
rButton2 = tk.Radiobutton(self,variable = self.var1,value=False,
command=self.switch_pages)
rButton2.grid(row=2,column=1,sticky = "W")
def switch_pages(self):
if not self.var1.get():
self.controller.show_frame(Page3)
else:
self.controller.show_frame(Page2)
class Page2(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lbl = tk.Label(self,text="This is page 2",font=("Helvetica",12,"bold"))
lbl.pack()
class Page3(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lbl = tk.Label(self,text="This is page 3",font=("Helvetica",12,"bold"))
lbl.pack()
app = MainApp()
app.mainloop()
Related
I'm just learning Python and I don't know how to make this program to display result in label that I want and when I click button again I want to the new result replaces the previous one
I want to last class shows result in label or entry when i click 1st button and when i click it again the new result will replace previous.
This program is not finished yet. I don't want to write all code when i have problem with first function of program. Once I deal with this problem, writing the rest of the code will not be difficult
import tkinter as tk
from tkinter import ttk
class tkinterApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
windowWidth = 300
windowHeight = 200
offsetLeft = int( (self.winfo_screenwidth() - windowWidth) / 2 )
offsetTop = int( (self.winfo_screenheight() - windowHeight) / 2 )
self.geometry('{}x{}+{}+{}'.format(windowWidth, windowHeight, offsetLeft, offsetTop))
self.title('Konwerter systemów liczbowych')
self.minsize(300, 200)
container = tk.Frame(self, relief="ridge", width=300, height=200)
container.pack(expand = False)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for F in (StartPage, Decy, decBin):
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)
label = ttk.Label(self, text ="Wybierz system do którego należy Twoja liczba.")
label.grid()
button1 = ttk.Button(self, text ="Decymalny",
command = lambda : controller.show_frame(Decy))
button1.grid(padx = 5, pady = 5)
button2 = ttk.Button(self, text ="Binarny",
command = lambda : controller.show_frame(Binar))
button2.grid(padx = 5, pady = 5)
button3 = ttk.Button(self, text ="Oktalny",
command = lambda : controller.show_frame(Oktal))
button3.grid(padx = 5, pady = 5)
button4 = ttk.Button(self, text ="Heksadecymalny",
command = lambda : controller.show_frame(Heksal))
button4.grid(padx = 5, pady = 5)
class Decy(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text ="Wybierz system na jaki chcesz przekowertować")
label.grid()
label = ttk.Label(self, text ="swoją liczbę.")
label.grid()
button1 = ttk.Button(self, text ="Binarny",
command = lambda : controller.show_frame(decBin))
button1.grid(padx = 5, pady = 5)
button2 = ttk.Button(self, text ="Oktalny",
command = lambda : controller.show_frame(decOkt))
button2.grid(padx = 5, pady = 5)
button2 = ttk.Button(self, text ="Heksadecymalny",
command = lambda : controller.show_frame(decHex))
button2.grid(padx = 5, pady = 5)
button2 = ttk.Button(self, text ="Powrót",
command = lambda : controller.show_frame(StartPage))
button2.grid(padx = 5, pady = 5)
class decBin(tk.Frame):
def clearText(self):
self.entry1.confing(text='')
def oblicz():
dec = wpis.get()
dec = int(dec)
i = 0
bnum = []
while dec!=0:
rem = dec%2
bnum.insert(i, rem)
i = i+1
dec = int(dec/2)
i = i-1
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = ttk.Label(self, text ="Wprowadź liczbę i zatwierdź.")
label.grid()
wpis = ttk.Entry(self)
wpis.grid()
button1 = ttk.Button(self, text="Konwertuj", command = oblicz)
button1.grid(padx = 10, pady = 10)
button2 = ttk.Button(self, text ="Powrót", command = lambda : controller.show_frame(StartPage))
button2.grid(padx = 10, pady = 10)
app = tkinterApp()
app.mainloop()
If you want to update an existing Label widget, declare a tk.StringVar() to store the label text, then bind that to your Label's textvariable attribute. Then your Label will automatically update whenever you set() the StringVar.
label_var = tk.StringVar(self, 'Default Value') # both of these args are optional
label = ttk.Label(self, textvariable=label_var) # instantiate Label and bind the var
To update the label:
label_var.set('New String Value')
When you grid()/pack()/place() your Label it will start with the text you gave the StringVar, if any.
Building tkinter application that loads a selected .csv as a dataframe and prints the "Categories" of dataframe on second page listbox as selectable option.
Data from .csv in DataFrame Form
import pandas as pd
data = [['TNUAX', '1290 Diversified Bond A','Intermediate Core-Plus Bond'],
['ABSZX', 'AB Discovery Value Z','Small Value'],
['AUIAX', 'AB Equity Income A','Large Value']]
df = pd.DataFrame(data, columns=['Ticker', 'Fund Name','Category'])
df
Application Code:
import tkinter as tk
from tkinter import *
import tkinter.ttk as ttk
import pandas as pd
class MyApp(Tk):
def __init__(self):
Tk.__init__(self)
container = ttk.Frame(self)
container.pack(side="top", fill="both", expand=True)
self.frames = {}
for F in (PageOne, PageTwo):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky='NSEW')
self.show_frame(PageOne)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class PageOne(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.make_widget()
def make_widget(self):
#Sections of Page/Canvas
self.cvs = Canvas(self, width="500", height="60", background='#f0f0f0', bd=-2) #-2 to eliminate border
self.cvs2 = Canvas(self, width="500", height="500", background="white", bd=-2)
self.cvs3 = Canvas(self, width="500", height="60", background="#f0f0f0", bd=-2)
#Fonts and sizes
mainf = 'Arial'
headsz = 20
bodysz = 12
def databrowser():
root = tk.Tk()
root.withdraw()
data_f_path = filedialog.askopenfilename()
df = pd.read_csv(data_f_path)
x = df.Category.unique().tolist()
#Score Sort Header
lbl=tk.Label(self.cvs2, text="Score Sort", background= 'white',fg='#529e3f', font=(mainf, headsz))
lbl.place(relx=0.75, rely=0.01, relwidth=0.5, anchor='ne')
#Select Data File (.csv) label
datainlabel=Label(self.cvs2, text="Select Data File (.csv)", bg='white', fg='Black', font=(mainf,bodysz))
datainlabel.place(relx=0.55, rely=0.55, relwidth=0.31, anchor='ne')
#Select Data Input File Button
InSbtn = Button(self.cvs2, text='Browse', font=(mainf, bodysz),command=databrowser) #command=selected_item
InSbtn.place(relx=0.75, rely=0.55, relwidth=0.15, anchor='ne')
def func2():
print('Load List Function Here?')
#Next Page Button
btnChange = Button(self.cvs3, text="Next", font=(mainf,bodysz),command=lambda: [self.controller.show_frame(PageTwo),func2()],
bg="white") #'#529e3f' #acdcea
btnChange.place(relx=.775, rely=.15, width="80", height="40")
def change_page(self):
pass
#Pack Sections
self.cvs.pack()
self.cvs2.pack()
self.cvs3.pack()
class PageTwo(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.make_widget()
def make_widget(self):
#Fonts and sizes
mainf = 'Arial'
headsz = 20
bodysz = 12
#Sections of Page
self.cvs = Canvas(self, width="500", height="60", background='#f0f0f0', bd=-2) #-2 to eliminate border
self.cvs2 = Canvas(self, width="500", height="500", background="white", bd=-2)
self.cvs3 = Canvas(self, width="500", height="60", background="#f0f0f0", bd=-2)
self.cvslist = Canvas(self, width="500", height="300", background="#acdcea", bd=-2)
#Category Selection List
yscrollbar = Scrollbar(self.cvslist)
yscrollbar.pack(side = RIGHT, fill = Y)
#Create window label
label = Label(self.cvslist,text = "Select Assset Categories : ",font = (mainf, 13),bg='#acdcea', padx = 5, pady = 5)
label.pack()
# Create a listbox
listbox = Listbox(self.cvslist, width=40, height=15, selectmode=MULTIPLE, font=(mainf,11),yscrollcommand = yscrollbar.set)
#Expanse Option
listbox.pack(padx = 10, pady = 10,expand = YES, fill = "both")
#Part that Loads Assets categories from csv in list
for each_item in range(len(x)):
listbox.insert(END, x[each_item])
listbox.itemconfig(each_item, bg = "white")
#Back Page Button
backbutt = tk.Button(self.cvs3, text='Back',font=('Arial',12), bg='white',command=lambda: self.controller.show_frame(PageOne))
backbutt.place(relx=0.225, rely=0.15, anchor='ne', width="80", height="40")
#Pack Sections
self.cvs.pack()
self.cvs2.pack()
self.cvslist.place(relx=0.75, rely=0.2, relwidth=0.5, anchor='ne')
self.cvs3.pack()
if __name__ == '__main__':
app = MyApp()
app.title('Score Sort')
app.mainloop()
The Error:
name 'x' is not defined from the part that loads this listbox
for each_item in range(len(x)):
listbox.insert(END, x[each_item])
listbox.itemconfig(each_item, bg = "white")
My Attmept:
Is to bind a command that loads the list when next button is pressed.
def func2():
print('Load List Function Here?')
#Next Page Button
btnChange = Button(self.cvs3, text="Next", font=(mainf,bodysz),command=lambda: [self.controller.show_frame(PageTwo),func2()],
bg="white") #'#529e3f' #acdcea
btnChange.place(relx=.775, rely=.15, width="80", height="40")
Application with errant section #'out, to visually see app attempt:
import tkinter as tk
from tkinter import *
import tkinter.ttk as ttk
import pandas as pd
class MyApp(Tk):
def __init__(self):
Tk.__init__(self)
container = ttk.Frame(self)
container.pack(side="top", fill="both", expand=True)
self.frames = {}
for F in (PageOne, PageTwo):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky='NSEW')
self.show_frame(PageOne)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class PageOne(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.make_widget()
def make_widget(self):
#Sections of Page/Canvas
self.cvs = Canvas(self, width="500", height="60", background='#f0f0f0', bd=-2) #-2 to eliminate border
self.cvs2 = Canvas(self, width="500", height="500", background="white", bd=-2)
self.cvs3 = Canvas(self, width="500", height="60", background="#f0f0f0", bd=-2)
#Fonts and sizes
mainf = 'Arial'
headsz = 20
bodysz = 12
def databrowser():
root = tk.Tk()
root.withdraw()
data_f_path = filedialog.askopenfilename()
df = pd.read_csv(data_f_path)
x = df.Category.unique().tolist()
#Score Sort Header
lbl=tk.Label(self.cvs2, text="Score Sort", background= 'white',fg='#529e3f', font=(mainf, headsz))
lbl.place(relx=0.75, rely=0.01, relwidth=0.5, anchor='ne')
#Select Data File (.csv) label
datainlabel=Label(self.cvs2, text="Select Data File (.csv)", bg='white', fg='Black', font=(mainf,bodysz))
datainlabel.place(relx=0.55, rely=0.55, relwidth=0.31, anchor='ne')
#Select Data Input File Button
InSbtn = Button(self.cvs2, text='Browse', font=(mainf, bodysz),command=databrowser) #command=selected_item
InSbtn.place(relx=0.75, rely=0.55, relwidth=0.15, anchor='ne')
def func2():
print('Load List Function Here?')
#Next Page Button
btnChange = Button(self.cvs3, text="Next", font=(mainf,bodysz),command=lambda: [self.controller.show_frame(PageTwo),func2()],
bg="white") #'#529e3f' #acdcea
btnChange.place(relx=.775, rely=.15, width="80", height="40")
def change_page(self):
pass
#Pack Sections
self.cvs.pack()
self.cvs2.pack()
self.cvs3.pack()
class PageTwo(ttk.Frame):
def __init__(self, parent, controller):
self.controller = controller
ttk.Frame.__init__(self, parent)
self.make_widget()
def make_widget(self):
#Fonts and sizes
mainf = 'Arial'
headsz = 20
bodysz = 12
#Sections of Page
self.cvs = Canvas(self, width="500", height="60", background='#f0f0f0', bd=-2) #-2 to eliminate border
self.cvs2 = Canvas(self, width="500", height="500", background="white", bd=-2)
self.cvs3 = Canvas(self, width="500", height="60", background="#f0f0f0", bd=-2)
self.cvslist = Canvas(self, width="500", height="300", background="#acdcea", bd=-2)
#Category Selection List
yscrollbar = Scrollbar(self.cvslist)
yscrollbar.pack(side = RIGHT, fill = Y)
#Create window label
label = Label(self.cvslist,text = "Select Assset Categories : ",font = (mainf, 13),bg='#acdcea', padx = 5, pady = 5)
label.pack()
# Create a listbox
listbox = Listbox(self.cvslist, width=40, height=15, selectmode=MULTIPLE, font=(mainf,11),yscrollcommand = yscrollbar.set)
#Expanse Option
listbox.pack(padx = 10, pady = 10,expand = YES, fill = "both")
# #Part that Loads Assets categories from csv in list
# for each_item in range(len(x)):
# listbox.insert(END, x[each_item])
# listbox.itemconfig(each_item, bg = "white")
#Back Page Button
backbutt = tk.Button(self.cvs3, text='Back',font=('Arial',12), bg='white',command=lambda: self.controller.show_frame(PageOne))
backbutt.place(relx=0.225, rely=0.15, anchor='ne', width="80", height="40")
#Pack Sections
self.cvs.pack()
self.cvs2.pack()
self.cvslist.place(relx=0.75, rely=0.2, relwidth=0.5, anchor='ne')
self.cvs3.pack()
if __name__ == '__main__':
app = MyApp()
app.title('Score Sort')
app.mainloop()
Understand this is alot of code and considerably complex from most stackoverflow questions. If anyone can suggest/recommend another platform where I can get hands on help that would be appreciated as well.
I can tell you how to make this work, but this is a really bad design. Your second page is relying on data that was generated by the first page. You need a sensible way to do that communication. In the short term, if you add global x to your databrowser function, it will work.
At the very least, take databrowser out of PageOne.make_widget and make it a global function. You'll still need the global x statement, but at least it makes it clear that it's not private data.
I am making my first tkinter program and when I run the code bellow I get a an error:
frame = F(window,self )
TypeError: init() takes 1 positional argument but 3 were given"
and I cant find out why.
Code:
class welcome_screen(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
lable = tk.Label(self,text="Step Cyber",bg = "gold", width = "500",height = "1", font=("Calibri",45)).pack()
label.pack()
lable = tk.Label(self,text="Welcome to The Step Cyber. Access computer as Client or Admin", font=("Calibri")).pack()
label.pack()
button = tk.Button(self,text="Client",width = "30",height = "2",command=lambda: controller.show_frame(client_sceen) ).pack()
button.pack()
tk.Label(self,text="").pack()
button = tk.Button(self,text="Administrator",width = "30",height = "2", command=lambda: controller.show_frame(admin_login)).pack()
button.pack()
This is the class I use to create the window and change frames, the one above is one of other multiple classes frames. What might be the problem. Thank you in advance
class Application(tk.Tk):
def __init__(self,*args,**kwargs):
tk.Tk.__init__(self,*args,**kwargs)
#creating a window
window = tk.Frame(self)
window.pack()
window.grid_rowconfigure(0,minsize = 800)
window.grid_columnconfigure(0,minsize= 800)
self.frames = {}
for F in (welcome_screen,client_sceen,timer_screen,admin_login,admin_screen,Regester_Admin_screen):
frame = F(window,self )
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew" )
self.show_frame(welcome_screen)
def show_frame(self,page):
frame = self.frames[page]
frame.tkraise()
app = Application()
app.mainloop()
I am a newbie in Python, I am keen in being able to swap between different frame in Tkinter. But I can't seems to be able to do it with Canvas. Any expert able to help me point out my mistake?
My main goal is to swap effectively between StartPage and PageOne.
import tkinter as tk
class backbone(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self,*args, **kwargs)
container=tk.Frame(self)
container.config(width=600,height=400,bg="beige")
container.pack()
self.frames={}
for F in (StartPage, PageOne):
frame=F(container,self)
self.frames[F]=frame
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)
canvas = tk.Canvas(self, width = 600, height = 400, bg='#aaaaff')
canvas.pack()
btn_2=tk.Button(self, text="Start Page", bg='#3ab54a',fg='blue',
command=lambda: controller.show_frame(PageOne))
btn_2.place(relx=0.35, rely=0.79, relwidth=0.3, relheight=0.1)
btn_2.pack()
class PageOne(tk.Frame):
def __init__(self,parent,controller):
tk.Canvas.__init__(self,parent)
canvas = tk.Canvas(self, width = 600, height = 400, bg='#aaaaff')
canvas.pack()
btn_1=tk.Button(self, text="PageOne", bg='#3ab54a',fg='blue',
command=lambda: controller.show_frame(StartPage))
btn_1.place(relx=0.35, rely=0.79, relwidth=0.3, relheight=0.1)
btn_1.pack()
app=backbone()
app.mainloop()
Here ya go. You had a bunch of issues. I commented everything in the code that was fixed or changed.
import tkinter as tk
#prepare some data
ButtonPlace = dict(relx=0.35, rely=0.79, relwidth=0.3, relheight=0.1)
ButtonConfig = dict(bg='#3ab54a', fg='blue', activebackground='#3ab54a', activeforeground='blue')
CanvasConfig = dict(width=600, height=400, highlightthickness=0)
#class names should start with a capital letter
class BackBone(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
#you don't need an inner frame so I got rid of it
#init some vars for storing and managing pages
self.page = 0
self.pages = {}
self.page_names = []
#make a refererence of pages and page names
for C in [StartPage, PageOne]:
self.pages[C.NAME]=C(self)
self.page_names.append(C.NAME)
#you can just use one button for every page
self.btn = tk.Button(self, text="Start Page", command=self.next_page, **ButtonConfig)
self.btn.place(**ButtonPlace)
#init start page
self.btn.invoke()
def next_page(self):
#whatever page is packed ~ forget it
for n, f in self.pages.items():
f.pack_forget()
#get page name
name = self.page_names[self.page]
#pack page associated with name
self.pages[name].pack()
#change button text to the name of this page (same as you had it)
self.btn['text'] = name
#raise the button up in z-order
self.btn.tkraise()
#prime next page number
self.page = (self.page + 1) % len(self.page_names)
class StartPage(tk.Canvas):
#static page name reference
NAME = 'Start Page'
#the proper term is master ~ not parent. controller is no more
def __init__(self, master):
tk.Canvas.__init__(self, master, bg='#aaaaff', **CanvasConfig)
#you don't need a frame. make the whole thing a canvas
#apply StartPage comments to this page, as well
class PageOne(tk.Canvas):
NAME = 'Page One'
def __init__(self, master):
tk.Canvas.__init__(self, master, bg='#ffaaaa', **CanvasConfig)
#this is the proper way to initialize your app
if __name__ == '__main__':
app = BackBone()
app.configure(bg='beige', highlightthickness=0, bd=0)
app.resizable(False, False)
app.mainloop()
I am writing a program that will take skill names as input from text entries and calculate the corresponding value of all of the skills entered. When I enter a skill in the program and then print the skill to the shell it appears as an object? Why does this happen and how can I fix it, do I need a repr or str? Why doesn't the delete method to clear the text entry work as well?
import tkinter as tk
from tkinter import ttk
#make the lists to store the skill names
floorEle1Skills = []
class startValue(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Start Value Calculator")
tk.Tk.minsize(self, width = 350, height = 300)
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, floorPage, pommelPage, ringsPage, vaultPage, pbarsPage, hbarPage):
frame = f(container, self)
self.frames[f] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.showFrame(startPage)
#make the lists to store the skill names
floorEle1Skills = []
def showFrame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def floorEle1(skill):
floorEle1Skills.append(skill)
#clear the text entry
#ele1Entry.delete(0, tk.END)
#why doesnt this work???
#why is it printed as an object??
print(floorEle1Skills)
class startPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Select Event")
label.pack(pady = 10, padx = 10)
floorButton = ttk.Button(self, text = "Floor", command = lambda : controller.showFrame(floorPage))
floorButton.pack()
class floorPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Floor")
label.pack(pady = 10, padx = 10)
#make the entries and labels
ele1Label = tk.Label(self, text = "Element Group 1:")
ele1Label.pack()
skill1 = tk.StringVar()
ele1Entry = tk.Entry(self, textvariable = skill1)
ele1Entry.pack()
ele1Button = ttk.Button(self, text = "Add", command = lambda : controller.floorEle1())
ele1Button.pack()
startButton = ttk.Button(self, text = "Back to Start", command = lambda : controller.showFrame(startPage))
startButton.pack(side = 'bottom')
Welcome to Python. The problem is in the function floorEle1(skill). This is a member function of class startValue, but the argument list doesn't begin with self. Python doesn't force you to name the first variable self; you can actually name it whatever you want (but don't do it!). So within this function the variable named skill acts just like the variable self.
It's exactly as if you had written this:
def floorEle1(self):
floorEle1Skills.append(self)
#clear the text entry
#ele1Entry.delete(0, tk.END)
#why doesnt this work???
#why is it printed as an object??
print(floorEle1Skills)
I think you can see now that your code, in effect, appends self to floorEle1Skills; i.e., you append the instance of your main window! So when you print the list, the print statement shows that the list contains an object.
As already mentioned in the another answer the problem with the code turns around the function floorEle1(self, skill), BUT ... there are also some other issues that should be properly addressed in order to get the entered skills passed to the list of skills (see code below):
import tkinter as tk
from tkinter import ttk
#make the lists to store the skill names
# floorEle1Skills = []
class startValue(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Start Value Calculator")
tk.Tk.minsize(self, width = 350, height = 300)
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, floorPage): # , pommelPage, ringsPage, vaultPage, pbarsPage, hbarPage):
frame = f(container, self)
self.frames[f] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.showFrame(startPage)
#make the lists to store the skill names
self.floorEle1Skills = []
def showFrame(self, cont):
self.floorEle1Skills = []
frame = self.frames[cont]
frame.tkraise()
def floorEle1(self, skill):
print("#", skill.get())
self.floorEle1Skills.append(skill)
#clear the text entry
#ele1Entry.delete(0, tk.END)
#why doesnt this work???
#why is it printed as an object??
for item in self.floorEle1Skills:
print("##",item.get())
class startPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Select Event")
label.pack(pady = 10, padx = 10)
floorButton = ttk.Button(self, text = "Floor", command = lambda : controller.showFrame(floorPage))
floorButton.pack()
class floorPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Floor")
label.pack(pady = 10, padx = 10)
#make the entries and labels
ele1Label = tk.Label(self, text = "Element Group 1:")
ele1Label.pack()
skill1 = tk.StringVar()
ele1Entry = tk.Entry(self, textvariable = skill1)
ele1Entry.pack()
ele1Button = ttk.Button(self, text = "Add", command = lambda : controller.floorEle1(ele1Entry))
ele1Button.pack()
startButton = ttk.Button(self, text = "Back to Start", command = lambda : controller.showFrame(startPage))
startButton.pack(side = 'bottom')
root = tk.Tk()
my_gui = startValue()
root.mainloop()
Other changes in the code are:
definition of self.floorEle1Skills = [] in the '__ init __()' function and passing the appropriate parameter to controller.floorEle1(ele1Entry) so that the input string value is passed to the function handling the button push.
The above code prints the user input to the terminal (twice, first from the passed user input, second all items in the list).
Placing self.floorEle1Skills = [] line in showFrame() resets the list collecting the input of skills (making restart of input possible).
The code above solves both issues addressed in the question, but this doesn't mean that there are not further issues needing to be solved.