Accessing a tkinter list-box selection when using frames - python

I am trying to use frames in a tkinter window to change the layout when I user selects a range of options - in this case "Open".
I want the frame to update but I also need to capture the selection of the listbox. I have tried to access the selection from the method "openMat".
I have simplified the code as much as i can.
i have tried to solve this issue for a while, tried looking online for a solution and have finally resorted clicking the "ask a question" button.
import tkinter as tk
LARGE_FONT = ("Verdana", 12) # font's family is Verdana, font's size is 12
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# text for all windows
label2 = tk.Label(self, text='title', font=LARGE_FONT)
label2.pack(pady=10, padx=10) # center alignment
# this container contains all the pages
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1) # make the cell in grid cover the entire window
container.grid_columnconfigure(0,weight=1) # make the cell in grid cover the entire window
self.frames = {} # these are pages we want to navigate to
for F in (StartPage, Page2): # for each page
frame = F(container, self) # create the page
self.frames[F] = frame # store into frames
frame.grid(row=0, column=0, sticky="nsew") # grid it to container
self.show_frame(StartPage) # let the first page is StartPage
def show_frame(self, name):
frame = self.frames[name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
ltbox = tk.Listbox(self)
label = tk.Label(self, text='Menu', font=LARGE_FONT)
label.grid(row=0, column = 0)
#label.pack(pady=10, padx=10) # center alignment
button1 = tk.Button(self, text='Open', width = 12, # when click on this button, call the show_frame method to make PageOne appear
command=self.openMat)
button1.grid(row=1, column = 0)
#button1.pack() # pack it in
#Insert data in listbox
ltbox.insert( 1, "Option 1")
ltbox.insert( 2, "Option 2")
ltbox.insert( 3, "Option 3")
ltbox.insert( 4, "Option 4")
ltbox.grid(row=1, column = 4, rowspan=100, pady=0, padx=50)
print (ltbox.curselection())
def openMat(self):
#This function prints the option selected and changes the frame
print (ltbox.curselection())
app.show_frame(Page2)
class Page2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='Page Two', font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text='Back to Home', # likewise StartPage
command=lambda : controller.show_frame(StartPage))
button1.pack()
if __name__ == '__main__':
app = MainWindow()
app.mainloop()
This gives the error:
NameError: name 'ltbox' is not defined
thank you for reading my question - any help is much appreciated!

Your issue is of Scope.
ltbox is defined and hence can be used only inside the __init__ function of the class StartPage. If you want it to be accessible to all the functions of a class, you have to make it an instance attribute of the class, which is done by using self. So wherever you have used ltbox, just change it to self.ltbox.

Related

In tkinter, how can I insert the value of an inherited class variable into a Label widget?

The issue I am having is specifically with the Label widget. In the linked code, the tests for Text widgets and Button widgets both grab the inherited value and display it correctly.
You can find the Label widget in question in class PageTwo
The variable I am trying to inherit and display within the Label is the "num" variable set in the first class.
The goal is to take that variable, set the value in another class, and then display the newly set value later in a Label widget.
I have tried to set the Label to display the variable directly, as a str value, within an f-string, as well as setting a local variable within PageTwo to take the value of TestClass.num
Example of the code in question is:
import tkinter as tk
class TestClass(tk.Tk):
num = None
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Game")
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 (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(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self,
text="Make a selection",
wraplength=450, justify='center')
label.pack(padx=10, pady=10)
TestClass.num = tk.StringVar()
tk.Radiobutton(self, text="1", variable=TestClass.num, value="1", ).pack()
tk.Radiobutton(self, text="2", variable=TestClass.num, value="2", ).pack()
tk.Radiobutton(self, text="3", variable=TestClass.num, value="3", ).pack()
view_selection = tk.Button(self, text="test selection", command=lambda: print(TestClass.num.get()))
view_selection.pack()
next_page = tk.Button(self, text="Next Page",
command=lambda: controller.show_frame(PageTwo))
next_page.pack(pady=10, padx=10)
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# label = tk.Label(self, text=TestClass.num.get()
label = tk.Label(self, text=f"The number should show up here -> {TestClass.num.get()} <- ")
label.pack()
text1 = tk.Text(self)
text1.pack()
see_num = tk.Button(self, text="View Number",
command=lambda: text1.insert('1.0', TestClass.num.get()))
see_num.pack(pady=10, padx=10)
app = TestClass()
app.mainloop()
I have come across such uses of controller for a while now but never really got to know where the idea arose from. Anyway over here I see the problem might actually be in the program flow(when you instantiate with F(container, self) you are executing the __init__ of that class, hence the values are already being set.
When you select each item in the radio button, you want the value of the label to appropriately edit itself. So for that I think static variables are more appropriate(to access the widgets inside another class) and you can use command to fire a callback.
Also you need to fix the tristate issue of your Radiobutton, by giving different initial value to the StringVar to not be equal to the tristatevalue of Radiobutton or giving different tristatevalue to each radiobutton or to use ttk.Radiobutton that does not use this tristatevalue.
So the changes to be made for PageTwo are to create some static variables:
class PageTwo(tk.Frame):
label = ''
text = ''
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
PageTwo.text = "The number should show up here -> {} <- " # {} so we can `format` it to be whatever text we want, later
PageTwo.label = tk.Label(self, text=self.text.format(''))
PageTwo.label.pack()
...
...
And in PageOne, you need to set a command for Radiobutton that will be called each time an option is changed.
class PageOne(tk.Frame):
def __init__(self, parent, controller):
...
...
TestClass.num = tk.StringVar(value=' ')
command = lambda *args: PageTwo.label.config(text=PageTwo.text.format(TestClass.num.get()))
tk.Radiobutton(self, text="1", variable=TestClass.num, value="1",command=command).pack()
tk.Radiobutton(self, text="2", variable=TestClass.num, value="2",command=command).pack()
tk.Radiobutton(self, text="3", variable=TestClass.num, value="3",command=command).pack()
...
...
Another method I think possible is to create a function to create widgets, and load that up later when the page is supposed to be showed.

Python moving class to separate file causes nameError

I am simply trying to move class ScreenThree to a separate file 9 I will soon have many more)....However for the lambdas I get nameError ...how to fix?
I've tried many arrangements, but allways get some sort of nameError. For this post, I have deleted ScreenTwo, since these basically all look the same.
When moving this class to its own file what needs to be changed? I used import, which seemed to work & screen3 shows. , However the button lambda is where it fails
import tkinter as tk
LARGE_FONT = ("Verdana", 12) # font's family is Verdana, font's size is 12
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("Fuzzy System") # set the title of the main window
self.geometry("300x300") # set size of the main window to 300x300 pixels
# this container contains all the screens
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1) # make the cell in grid cover the entire window
container.grid_columnconfigure(0,weight=1) # make the cell in grid cover the entire window
self.frames = {} # these are screens we want to navigate to
for F in (ScreenOne, ScreenTwo,ScreenThree): # for each screen
frame = F(container, self) # create the screen
self.frames[F] = frame # store into frames
frame.grid(row=0, column=0, sticky="nsew") # grid it to container
self.show_frame(ScreenOne) # let the first screen is ScreenOne
def show_frame(self, name):
frame = self.frames[name]
frame.tkraise()
class ScreenOne(tk.Frame):
def __init__(self, parent, controller):
self.controller=controller
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='This is ScreenOne', font=LARGE_FONT)
label.pack(pady=10, padx=10) # center alignment
# when click on this button, call the show_frame method to make screenOne appear
button1 = tk.Button(self, text='Visit screen two', command=lambda : controller.show_frame(ScreenTwo))
button1.pack() # pack it in
self.button2 = tk.Button(self, text='GOTO Screen Three', command=lambda : controller.show_frame(ScreenThree))
self.button2.place(relx=0.5, rely=0.29, height=41, width=144)
self.button2.configure(background="#911218")
class ScreenThree(tk.Frame):
def __init__(self, parent, controller):
self.controller=controller
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='This is screen Three', font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text='GOTO ScreenTwo', command=lambda : controller.show_frame(ScreenTwo))
button1.pack()
button2 = tk.Button(self, text='GOTO Screen One', command=lambda : controller.show_frame(ScreenOne))
button2.pack()
if __name__ == '__main__':
app = MainWindow()
app.mainloop()
I have several classes, all looking similar to the following. They all work fine, no problems. However I want to move them to individual files, since they will soon become lengthy. I moved the following to file `scr3.py`.
I then added the following to my main file:
from scr3 import ScreenThree
Screen one and two work fine and my buttons in `screen3` show up. However when pushing on the screen three buttons I get a `NameError: name 'ScreenOne' is not defined` and similar for `screen2` (see the lambda funcs). These worked fine when all was in one file. `Screen1` and `2` (still in the `main` file) continue to work fine.
Why does it work fine when this same code is in the `main` file , but now fails? It has only been moved. What is the workaround?
import tkinter as tk
LARGE_FONT = ("Verdana", 12) # font's family is Verdana, font's size is 12
class ScreenThree(tk.Frame):
def __init__(self, parent, controller):
self.controller=controller
tk.Frame.__init__(self, parent)
label = tk.Label(self, text='This is screen Three', font=LARGE_FONT)
label.pack(pady=10, padx=10)
button1 = tk.Button(self, text='GOTO ScreenTwo', command=lambda : controller.show_frame(ScreenTwo))
button1.pack()
button2 = tk.Button(self, text='GOTO Screen One', command=lambda : controller.show_frame(ScreenOne))
button2.pack()
The code of ScreenThree is no longer in the same namespace as e.g. ScreenOne. You might fix this by passing a reference to ScreenOne and ScreenTwo as arguments to the __init__.

Tkinter: Code stops and window doesn't show up

I am working on a very basic interface on Python with Tkinter, that displays two input boxes and a button to login. I try to do it by creating different frames and change the frame when the user is logged. It was working nearly fine but then the code started to execute itself not entirely sometimes and entirely but without the Tkinter window. I looked into it and saw nothing shocking but I am not an expert so I am looking for help.
This is the code to run my class that implement Tkinter window:
print 1
app = Skeleton("HomePage")
print 2
app.mainloop()
print 3
The skeleton Class that implement the Tkinter window:
class Skeleton(Tk):
def __init__(self, f,*args, **kwags):
Tk.__init__(self,*args, **kwags)
self.title(f)
container = Frame(self, width=512, height=512)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
frameName = {"home","upload","retrieve","deconnected"}
self.frames["HomePage"] = HomePage(parent= container, controller=self)
self.frames["HomePage"].grid(row=0, column=0, sticky="nsew")
print 321
self.show_frame("HomePage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
print "Je vais te montrer mon frame"
frame = self.frames[page_name]
frame.tkraise()
And the code of the Home Page frame:
class HomePage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.parent = parent
self.controller = controller
#print ("Construction de la page dáccueil")
#LABEL
self.username = Label(self, text="Username:")
self.username.grid(row =0,column =0)
self.username.pack()
#ENTRY
self.username_txb = Entry( self)
self.username_txb.focus_set()
self.username_txb.grid(row =0,column =1)
self.username_txb.pack(side=LEFT)
#LABEL
self.pass_lbl = Label(self, text="Password:")
self.pass_lbl.grid(row =0,column =2)
#ENTRY
self.password_txb = Entry( self, text="Password", show = "*")
self.password_txb.grid(row =0,column =3)
self.password_txb.pack(side=LEFT)
#LOGIN BUTTON
self.login_btn = Button(self, text="Login", command=lambda: controller.show_frame("UploadPage"))
self.login_btn.grid(row =0,column =4)
self.login_btn.pack(side=LEFT)
self.info_pane = PanedWindow()
self.info_pane.grid(row =1,column =0)
self.info_pane.pack(fill="none", expand=True, side=BOTTOM)
self.info_lbl = Label(self, text="More information about access:", fg="blue", cursor="hand2")
self.contact_lbl = Label(self, text="Contact us", fg="blue", cursor="hand2")
self.contact_lbl.grid(row =2,column =0)
self.contact_lbl.pack()
self.contact_lbl.bind("<Button-1>", self.callback)
print ("123Construction de la page dáccueil")
#self.parent.update()
def callback(self, event):
pass
def connect(self,controller ):
login = self.username_txb.get()
pwd = self.password_txb.get()
if(login == "a" and pwd == "a"):
print "Valid account"
self.controller.show_frame("UploadPage")
#UploadPage frame is implemented
The output everytime I execute the code is as following:
1
123Construction de la page dáccueil
Thank you in advance for the help. Hope this will help other people.
First lets address your use of pack() and grid().
Due to how tkinter is set up you cannot use both pack() and grid() on the same widget in a frame or window at one time.
You may use for example pack() to pack the main frame and grid() on the widgets inside that frame but you cannot use both in side the frame.
If one of your issues is where each widget is located and if it is expanding with the window you can manage all that inside of grid() so we can just use grid() here as its what I prefer when writing up a GUI.
Next we need to look at your call to show_frame as you are attempting to show a frame that does not exist in self.frames in the code you have presented us.
I have created a new class so your program can be tested with this line of code:
self.controller.show_frame("UploadPage")
The new class just makes a basic frame with a label in it showing that the frame does rise properly with tkrise().
I did some general clean up as your show_frame method was taking unnecessary steps to raise the frame, your method of importing tkinter is not the best option and some other quality corrections.
Instead of using:
frame = self.frames[page_name]
frame.tkraise()
We can simplify this method with just one line like this:
self.frames[page_name].tkraise()
I have also changed how you are importing tkinter as importing with * can sometimes cause problems if you inadvertently override build in methods. The best option is to import tkinter like this:
import tkinter as tk
Take a look at the below code and let me know if you have any questions. It should provide the info you need to allow the HomePage frame and UploadPage frame to work as intended.
import tkinter as tk
class Skeleton(tk.Tk):
def __init__(self, f,*args, **kwags):
tk.Tk.__init__(self,*args, **kwags)
self.title(f)
self.container = tk.Frame(self, width=512, height=512)
self.container.grid(row=0, column=0, sticky="nsew")
self.container.grid_rowconfigure(0, weight=1)
self.container.grid_columnconfigure(0, weight=1)
self.frames = {}
self.frames["HomePage"] = HomePage(parent=self.container, controller=self)
self.frames["HomePage"].grid(row=0, column=0, sticky="nsew")
self.frames["UploadPage"] = UploadPage(parent=self.container)
self.frames["UploadPage"].grid(row=0, column=0, sticky="nsew")
self.show_frame("HomePage")
def show_frame(self, page_name):
self.frames[page_name].tkraise()
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.parent = parent
self.controller = controller
self.username = tk.Label(self, text="Username:")
self.username.grid(row =0,column =0)
self.username_txb = tk.Entry(self)
self.username_txb.focus_set()
self.username_txb.grid(row=0, column=1)
self.pass_lbl = tk.Label(self, text="Password:")
self.pass_lbl.grid(row =0,column =2)
self.password_txb = tk.Entry(self, text="Password", show="*")
self.password_txb.grid(row =0,column =3)
self.login_btn = tk.Button(self, text="Login", command=self.connect)
self.login_btn.grid(row=0, column=4)
self.info_pane = tk.PanedWindow()
self.info_pane.grid(row=1, column=0)
self.info_lbl = tk.Label(self, text="More information about access:", fg="blue", cursor="hand2")
self.contact_lbl = tk.Label(self, text="Contact us", fg="blue", cursor="hand2")
self.contact_lbl.grid(row=2, column=0)
self.contact_lbl.bind("<Button-1>", self.callback)
def callback(self, event):
pass
# webbrowser.open_new("https://www.tno.nl/nl/")
# I do not have the import for this webbrowser so I disabled it for testing.
def connect(self):
login = self.username_txb.get()
pwd = self.password_txb.get()
if(login == "a" and pwd == "a"):
self.controller.show_frame("UploadPage")
class UploadPage(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
tk.Label(self, text="This upload frame is a test to see if your code is working").grid(row=0, column=0)
if __name__ == "__main__":
app = Skeleton("HomePage")
app.mainloop()

Tkinter call function in another class

Hi i got some code from an answer on Switch between two frames in tkinter which im trying to modify so a button in the StartPage class can call a function called msg in PageOne class.
But im getting this error:
AttributeError: 'Frame' object has no attribute 'msg'
Here is the code so far i marked out the modifications i made to the code.
import tkinter as tk # python3
#import Tkinter as tk # python
TITLE_FONT = ("Helvetica", 18, "bold")
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
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):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.parent = parent #<-- my mod
label = tk.Label(self, text="This is the start page", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page Two",
command=lambda: controller.show_frame("PageTwo"))
self.button3 = tk.Button(text='Calling msg in another class', command=self.parent.msg)#<-- my mod
button1.pack()
button2.pack()
button3.pack()#<-- my mod
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.parent = parent #<-- my mod
label = tk.Label(self, text="This is page 1", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
def msg(self): #<-- my mod
print("IT WORKS!!")
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
Could anyone help me out?
Since you're instantiating all your classes in a loop, the easiest way to add references between them is probably to do it after that loop. Remove those references from inside the class, as they won't be valid until after instantiation. Note how button3 is no longer created or packed in StartPage, but rather in SampleApp.
for F in (StartPage, PageOne, PageTwo):
...
self.frames['StartPage'].pageone = self.frames['PageOne']
self.frames['StartPage'].button3 = tk.Button(
text='Calling msg in another class',
command=self.frames['StartPage'].pageone.msg) #<-- my mod
self.frames['StartPage'].button3.pack() #<-- my mod
Try this:
#code to get a page and use it inside any page
#1. create a variable name ex my_pageTwo
#2. show and get frame(page)
#3. now you can use a function from page
my_pageTwo = self.show_frame(PageTwo)
#
my_pageTwo = self.get_page(PageTwo)
#4. example
my_pageTwo.myfunction() #without self
#another example from my tkinter app:
#this function is inside main page:
def open_page8_and_ch_list(self):
if Pages.EEG_raw != '':
page_8 = self.show_frame(PageEight)
page_8 = self.get_page(PageEight)
self.show_frame(PageEight)
page_8.list_initial_ch_names()
else:
self.show_frame(PageEight)
message1_pg8(self)
def message1_pg8(self):
lines = ['Hey! Open a file to edit.']
tkinter.messagebox.showinfo('Myapp', "\n".join(lines))
# On the other hand "open_page8_and_ch_list
#" goes to container1 to open something in page8:
c1_button7 = tk.Button(container1,
text='Edit inicial EEG',
command=lambda: open_page8_and_ch_list(self))
c1_button7.grid(row=0, column=7))
I got stuck with this also, but after some tweaking and grasping the whole width of the code:
self.controller.frames['YourFrameName'].method()
You see everything has been instantiated and stored in a dictionary in the sampleapp class. And every other frame will have reference to the base 'sampleapp' class. So its as simple as referencing the base app and calling the frame that has the method that we want.

How to transfer data from one class to another in python using tkinter?

I have no idea how to transfer my data from one class into another. In the code, left below, I have imported some images using the askdirectory command from Tkinter and once I have the directory I import the images. I then get some information about the data, such as the number of extensions and the number of images. (I know these two values will be the same). I should probably mention that this data is found directly in the class PageOne1, it is dealt with in a function that is called from the class PageOne1.
Once this data is defined in a variable I need to be able to use it in a different class which is a frame that is raised higher once the button to import the data is clicked, this is just so that it looks different and the user knows something has happened.
The question is:
How can I transfer data from one class to another? E.G, in my code, I want to transfer data from class PageOne1 to PageOne2.
With this data that is being transfered I want to display it in a label.
#structure for this code NOT created by me - found on stackoverflow.com
import tkinter as tk
from tkinter import filedialog as tkFileDialog
import math, operator, functools, os, glob, imghdr
from PIL import Image, ImageFilter, ImageChops
#fonts
TITLE_FONT = ("Helvetica", 16, "bold","underline") #define font
BODY_FONT = ("Helvetica", 12) #define font
#define app
def show_frame(self, c): #raise a chosen frame
'''Show a frame for the given class'''
frame = self.frames[c]
frame.tkraise()
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the container will contain all frames stacked on top of each other, the frame to be displayed will be raised higher
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, PageOne1, PageOne2,):
frame = F(container, self)
self.frames[F] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, c): #raise a chosen frame
'''Show a frame for the given class'''
frame = self.frames[c]
frame.tkraise()
def choose(self):
image_list = []
extlist = []
root = tk.Tk()
root.withdraw()
file = tkFileDialog.askdirectory(parent=root,title="Choose directory")
if len(file) > 0:#validate the directory
print( "You chose %s" % file) #state where the directory is
for filename in glob.glob(file+"/*"):
print(filename)
im=Image.open(filename)
image_list.append(im)
ext = imghdr.what(filename)
extlist.append(ext)
print("Loop completed")
extlistlen = len(extlist)
image_listlen = len(image_list)
#these are the two pieces of data I want to transfer to PageOne2
self.show_frame(PageOne2)
#frames
class StartPage(tk.Frame): #title/menu/selection page
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="LTC Meteor Detection Program", font=TITLE_FONT) #using labels as they can be updated at any point without updating the GUI, if the data is to be manipulated by the user canvas will be used
label.pack(side="top", fill="x", pady=10) #pady offers padding between label and GUI border
button1 = tk.Button(self, text="Import Images",
command=lambda: controller.show_frame(PageOne1)) #if button1 chosen, controller.show_frame will raise the frame higher
#lambda and controller being used as commands to raise the frames
button2 = tk.Button(self, text="RMS Base Comparison",
command=lambda: controller.show_frame(PageTwo1))
button3 = tk.Button(self, text="Export Images",
command=lambda: controller.show_frame(PageThree1))
buttonexit = tk.Button(self,text="Quit",
command=lambda:app.destroy())
button1.pack()
button2.pack()
button3.pack()
buttonexit.pack()
class PageOne1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Import Images", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Select directory",
command=controller.choose)
button.pack()
button = tk.Button(self, text="Return To Menu",
command=lambda: controller.show_frame(StartPage))
button.pack()
#for reference:
#fileName = tkFileDialog.asksaveasfilename(parent=root,filetypes=myFormats ,title="Save the image as...")
class PageOne2(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Import Images", font=TITLE_FONT)
label.pack(side="top", fill="x", pady=10)
label = tk.Label(self, text = ("Number of images: ",image_listlen2," Number of different extensions: ",extlistlen2))
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Return To Menu",
command=lambda: controller.show_frame(StartPage))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
You have to keep a reference to the classes. I have eliminated all of the unnecessary code, so just
self.frames = {}
for F in (StartPage, PageOne1, PageOne2,):
frame = F(container, self)
self.frames[F] = frame
remains. You can then reference data that is a class attribute easily.
class StartPage():
def __init__(self):
## declare and iteger and a string
self.sp_1=1
self.sp_2="abc"
class PageOne1():
def __init__(self):
## declare a list and dictionary
self.sp_1=[1, 2, 3, 4, 5]
self.sp_2={"abc":1, "def":2}
class YourApp():
def __init__(self):
self.frames = {}
for F in (StartPage, PageOne1):
frame = F()
self.frames[F] = frame
## print instance attributes from other classes
for class_idx in self.frames:
instance=self.frames[class_idx]
print "\n", instance.sp_1
print instance.sp_2
YP=YourApp()

Categories