I have my Tkinker app where I create more frame and based on what I click I show one or another, the problem now is that I want them to refresh with new information every time that I call them; do you know how can I do?
This is my code:
class HFlair(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(10, weight=1)
container.grid_columnconfigure(10, weight=1)
self.container=container
self.frames = {}
for F in ((StartPage, None), (PageOne, None)):
page_name = F[0].__name__
frame = F[0](parent=container, controller=self, attr=F[1])
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name,arg=None):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
if arg:
frame.users(arg)
class StartPage(tk.Frame):
def __init__(self, parent, controller,attr=None):
tk.Frame.__init__(self, parent,attr)
self.controller = controller
self.title=tk.Frame(self)
self.title.pack(side="top")
self.menu=tk.Frame(self)
self.menu.pack(side="top")
self.app=tk.Frame(self) #### frame that I want refresh
self.app.pack(side="top") #### frame that I want refresh
class PageOne(tk.Frame):
def __init__(self, parent, controller, attr=None):
self.controller=controller
tk.Frame.__init__(self, parent,attr)
self.controller = controller
self.title=tk.Frame(self)
self.title.pack(side="top")
self.menu=tk.Frame(self)
self.menu.pack(side="top")
self.app=tk.Frame(self) #### frame that I want refresh
self.app.pack(side="top") #### frame that I want refresh
My problem is that in the frame self.app I have some information that I take from the DB so every time that I go to this specific page I want the Frame refresh to take update information.
Is there some easy way to do it?
I try with .update() but didn't work, more than other didn't give me any issue but the Frame didn't refresh.
Related
I am creating frames for my project and so far I have it where it goes from the home page to the main page when the button is clicked. The problem I am facing is when I try to go from the home page to the log page where I am faced with an issue of calling the show_frame() function (located in MainApplication) in class MainPage.
How would I go about using arguments in MainPage so I can move from main page to log page?
class MainApplication(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# initialize frames
self.frames = {}
for F in (HomePage, MainPage, LogPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
# show home page frame first
self.show_frame(HomePage)
def show_frame(self, cont): # <-- FUNCTION HERE
frame = self.frames[cont]
frame.tkraise()
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
continue_button = ttk.Button(self, text="Enter program", width=15,
command=lambda: controller.show_frame(MainPage)) # <-- works here
continue_button.pack()
class MainPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
def success_actions(self):
self.run_script_button["text"] = "View log"
self.run_script_button.configure(
command=lambda: controller.show_frame(LogPage)) # <-- want to use here
class LogPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
pass
It works only in HomePage because you made it inside the __init__() method but in the MainPage you need it outside.
To solve this try setting controller as an instance variable:
class MainPage(tk.Frame):
def __init__(self, parent, controller):
self.controller = controller
tk.Frame.__init__(self, parent)
def success_actions(self):
self.run_script_button["text"] = "View log"
self.run_script_button.configure(
command=lambda: self.controller.show_frame(LogPage))
I am creating a password manager software. The passwords are stored in different categories. When I click on the category it should open a ViewPasswordsInsideCategory page.
I am unable to pass the category name to the ViewPasswordsInsideCategory page.
Please help! I am new to Python and cant solve this issue.
I tried to pass an argument when I can showframe function but I couldn't achieve the goal.
class PasswordPage(Page):
def __init__(self, *args, **kwargs):
Page.__init__(self, *args, **kwargs)
self.shared_data = {
"category": tk.StringVar(),
"password": tk.StringVar()}
self.passwordScreen = Frame(self)
self.passwordScreen.pack(fill="both", expand=True)
self.passwordScreen.columnconfigure(0, weight=1)
self.passwordScreen.rowconfigure(0, weight=1)
self.frames = {}
for F in (PasswordCategoryPage,ViewPasswords_InCategory,CreateNewPassword,ViewPassword,ModifyPassword):
page_name = F.__name__
frame = F(parent=self.passwordScreen, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("PasswordCategoryPage")
def show_frame(self, page_name, arg=None):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class PasswordCategoryPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
# passwords categories content
self.labels = []
self.dict = {'Home': 'Blue', 'Work': 'Red', 'School': 'Yellow', "Technical": 'Pink', "Office": 'Orange'}
self.button = []
j = 0
for key, value in self.dict.items():
self.name = key
self.key = Label(self.pass_page_container,text=self.name,bg=value)
# Add the Label to the list
self.labels.append(key)
self.key.grid(row=j, column=0, sticky=(N, S, E, W))
self.key.bind("<Double-Button-1>", self.showPasswordPage)
j = j + 1
def showPasswordPage(self,event):
#here need to pass the label that was clicked to the ViewPasswords_InCategory page
self.controller.show_frame("ViewPasswords_InCategory")
class ViewPasswords_InCategory(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
#here need the name of the category selected to extract data from database
# home banner
home_label = Label(self, text=here need the name of the category, bg="blue", width=200, height=3, fg='white')
home_label.pack(side=TOP, expand=False)
The simply way is to add a new function in class ViewPasswords_InCategory to update the banner. Then whenever you switch to the page, call the new function. My proposed changes are:
1) return the frame that is raised in function PasswordPage.show_frame(...):
class PasswordPage(Page):
...
def show_frame(self, page_name, arg=None):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
return frame # return the raised frame
2) add new function, for example set_category(...) inside class ViewPasswords_InCategory to update its banner:
class ViewPasswords_InCategory(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
# home banner
self.home_label = Label(self, text='', bg="blue", width=200, height=3, fg='white') # changed to instance variable
self.home_label.pack(side=TOP, expand=False)
# new function to update banner
def set_category(self, category):
self.home_label['text'] = category
3) update PasswordCategoryPage.showPasswordPage(...) to call the new fucntion:
class PasswordCategoryPage(tk.Frame):
...
def showPasswordPage(self,event):
#here need to pass the label that was clicked to the ViewPasswords_InCategory page
self.controller.show_frame("ViewPasswords_InCategory").set_category(event.widget['text'])
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have a Class hierarchy where I am trying to switch tkinter windows while retaining specific properties (such as window name, dimensions, resizable, etc.). I'm having some issues with the resizable part since it takes in two values:
import tkinter as tk
from tkinter import font as tkfont
class Manifold(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self) #container = stack of frames; one on top is visible
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F,geometry,title in zip((StartPage,PageOne,PageTwo,PageThree),
("532x279","532x279","254x279","299x620"),
("","Experimental Data","Orientation Distribution","Manifold Embedding"),
((False,False),(False,False),(True,True),(True,True))):
page_name = F.__name__
frame = F(container, self)
self.frames[page_name] = (frame,geometry,title,(option1,option2)) #puts all pages in stacked order
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, geometry, title = self.frames[page_name]
self.update_idletasks()
self.geometry(geometry) #changes between window sizes
tk.Tk.wm_title(self, title) #window heading
###UNKNOWN:
self.resizable(*options)
###########
frame.tkraise() #raises window to top
if __name__ == "__main__":
app = Manifold()
app.mainloop()
Any advice would be greatly appreciated.
Close. Try this:
self.frames = {}
for F,geometry,title,options in zip((StartPage,PageOne,PageTwo,PageThree),
("532x279","532x279","254x279","299x620"),
("","Experimental Data","Orientation Distribution","Manifold Embedding"),
((False,False),(False,False),(True,True),(True,True))):
page_name = F.__name__
frame = F(container, self)
self.frames[page_name] = (frame,geometry,title,options) #puts all pages in stacked order
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, geometry, title,options = self.frames[page_name]
self.geometry(geometry) #changes between window sizes
self.title(title) #window heading
self.resizable(*options)
###########
frame.tkraise() #raises window to top
Assuming this is a subclass of Tk().
update_idletasks should not be needed (it's very rarely used).
It would be a lot neater to put those options in each Frame's tkraise() method. In order to do that you would need a hook to the root (the Tk() instance). Since you've obfuscated that somewhat with your "container" Frame (why?) you need to be sure to pass the root instance along. A simple example:
import tkinter as tk
class BigWindow(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
tk.Button(self, text='go to\nsmall window', command=lambda: master.show_frame(SmallWindow)).pack()
def tkraise(self):
self.master.title('Big Window')
self.master.geometry('600x600')
self.master.resizable(True, True)
tk.Frame.tkraise(self) # raise this Frame
class SmallWindow(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
tk.Button(self, text='go to\nbig window', command=lambda: master.show_frame(BigWindow)).pack()
def tkraise(self):
self.master.title('Small Window')
self.master.geometry('200x200')
self.master.resizable(False, False)
tk.Frame.tkraise(self)
class Manifold(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frames = {}
for F in (SmallWindow, BigWindow):
frame = F(self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(SmallWindow)
def show_frame(self, page): #show a frame for the given page
self.frames[page].tkraise()
if __name__ == "__main__":
app = Manifold()
app.mainloop()
You could make this even cleaner by making a base class for all your other frames to inherit from, and then just setting some variables:
import tkinter as tk
class AutoSizeFrame(tk.Frame):
def tkraise(self):
self.master.title(self.title)
self.master.geometry(self.geometry)
self.master.resizable(*self.resizemodes)
tk.Frame.tkraise(self) # raise this Frame
class BigWindow(AutoSizeFrame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.title = 'Big Window'
self.geometry = '600x600'
self.resizemodes = (True, True)
tk.Button(self, text='go to\nsmall window', command=lambda: master.show_frame(SmallWindow)).pack()
class SmallWindow(AutoSizeFrame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.title = 'Small Window'
self.geometry = '200x200'
self.resizemodes = (False, False)
tk.Button(self, text='go to\nbig window', command=lambda: master.show_frame(BigWindow)).pack()
class Manifold(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frames = {}
for F in (SmallWindow, BigWindow):
frame = F(self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(SmallWindow)
def show_frame(self, page): #show a frame for the given page
self.frames[page].tkraise()
if __name__ == "__main__":
app = Manifold()
app.mainloop()
I need some help with updating informations between two or more frames in tkinter. I am currelty working on a small project, where I have serval frames with information, each frame is one class.
First frame is a setting frame - so where the user can click some buttons and select several things.
The second frame should show the selected image with the made choices.
So far I can make the choices on the setting page but when i click forward to the result page it shows me empty frames and no image and not the made choices.
I tried to do some shared_data with the information that should be passed between the two frames/classes, so I can acess them on the resultpage but some how it is not updating the information. So it doesn't show me the image because mode on the results page is 0 like at the beginng.
class xyz (tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
...
self.shared_data = {
"no": tk.IntVar(),
"selectedname": tk.StringVar(),
"selectedpath": tk.StringVar(),
.....
}
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 (SettingPage, PageResults):
page_name = F.__name__
frame = F(container, self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("SettingPage")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class SettingPage(tk.Frame):
def __init__(self, parent, controller, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.controller = controller
self.controller.shared_data["no"] = 0
...
# after selecting serval buttons
self.controller.shared_data["no"] = 1
buttonContinue = ttk.Button(self, text='''CONTINUE >>''', command=lambda: controller.show_frame("PageResults"))
buttonContinue.place(relx=0.84, rely=0.9, height=43, width=186)
class PageResults(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
mode = self.controller.shared_data["no"]
if mode == 1 :
# show image
#......
I can't show you the exact real code I am using so I tried so simplify it. I am new to tkinter so any help would be much apprechiated.
Thank you!!
The problem is because you do this:
self.shared_data = {
"no": tk.IntVar(),
...
}
And then later you do this:
self.controller.shared_data["no"] = 0
So, shared_data["no"] starts out as an IntVar and then you replace it with an integer.
When you use an IntVar you must use the set method to change the value, and the get method to get the value:
self.controller.shared_data["no"].set(0)
...
if self.controller.shared_data["no"] == 0:
...
I am trying to access the Text widget defined in class FirstPage from outside of the class.
I tried to solve this problem by creating a new instance of FirstPage, but could not find the right arguments to use. Also tried to use instance of GUI to gain the access, but unsuccessfully.
My problem is solved when I can use text.insert(0.0, t) from outside of the classes. It would help me modify the text displayed with Tkinter by functions that are not directly related with the GUI.
The origin of the code I am trying to use is found: Switch between two frames in tkinter
Also I removed lines that were not necessary for this question..
import Tkinter as tk
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.geometry(self, '580x410')
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 = {}
frame = FirstPage(container, self)
self.frames[FirstPage] = frame
frame.grid(row=0, column=0, sticky="nsew")
frame = self.frames[FirstPage]
frame.tkraise()
class FirstPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
text = tk.Text(self , height=25, width=80)
text.grid(column=0, row=0, sticky="nw")
app = GUI()
app.mainloop()
EDIT:
Here is the working code:
import Tkinter as tk
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.geometry(self, '580x410')
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 = {}
frame = FirstPage(container, self)
self.frames[FirstPage] = frame
frame.grid(row=0, column=0, sticky="nsew")
frame = self.frames[FirstPage]
frame.tkraise()
page_name = FirstPage.__name__
self.frames[page_name] = frame
def get_page(self, page_name):
return self.frames[page_name]
class FirstPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.text = tk.Text(self , height=25, width=80)
self.text.grid(column=0, row=0, sticky="nw")
app = GUI()
app.get_page("FirstPage").text.insert("1.0", "Hello, world")
app.mainloop()
There's nothing special you need to do. As with any python object, you simply need a reference to the object in order to manipulate it.
The concept in the code you started with is to have a "controller" that controls access to all of the pages, since that object is where the pages are created. You can add a function in the controller that gives you a reference to a page, and then you can use that to call a function on that page.
Here's the changes you need to make to the controller:
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
...
page_name = FirstPage.__name__
self.frames[page_name] = frame
...
def get_page(self, page_name):
return self.frames[page_name]
You also need to modify FirstPage to keep a reference to the widget so that you can access it later:
class FirstPage(tk.Frame):
def __init__(self, parent, controller):
...
self.text = tk.Text(...)
...
From within any other code you can now access the text widget via get_page (but your pages must save a reference to the controller for this to work).
class AnotherPage(tk.Frame):
def __init__(self, parent, controller):
...
self.controller = controller
...
def some_function(self):
...
first_page = self.controller.get_page("FirstPage")
text = first_page.text.get("1.0", "end-1c")
...
first_page.text.insert("end", "some new text\n")
Note that this technique works outside of any GUI pages. In your code, app is the controller, so you can do something like this:
app = GUI()
app.get_page("FirstPage").text.insert("1.0", "Hello, world")