Suppose I have a lovely window full of tkinter widgets all set with a function. One of these many widgets is a button. When this button is pressed, I want to 'move on to the next screen'. The next screen is in another function(including all the widgets I want to appear on that screen). I have tried to simply run the next procedure from the button, but If it does run correctly, it only adds the widgets to the existing window, and you end up with both screen#1 and screen#2 jumbled together. I have a feeling I need to use destroy, but I'm not sure how to do such, as the only way I could come up with was to group all the widgets in window 1 together in a frame, and destroy it, but I cant get access to destroy the frame from within function #2, as its a variable only within function/window #1. Sorry if that's confusing, The other option is the source, but there's a ton of widgets and other windows in progress which leads me to believe that would be even more confusing.
2 Answers
The simplest thing is to have your function create a single frame, and then place all of the widgets in that frame. The frame can then be placed in the main window such that it fills the whole window. Then, to delete everything you simply need to delete that one frame.
Another way to "move on to the next screen" is to use this same method, but create all of the frames ahead of time. You can stack these frames on top of each other, and use lift
and/or lower
to determine which one is on top. The one on top will obscure the ones below.
For an example of stacking, see Switch between two frames in tkinter
As for the problem of frame2 not knowing how to destroy frame1, you simply need to pass in a reference to the existing frame when creating a new frame, or pass in a reference to a "controller" - a function that knows about all the frames. You then ask the controller to delete the current frame, and the controller will know what the current frame is.

- 1
- 1

- 370,779
- 53
- 539
- 685
-
I know this is probably fairly straightforward, but could you explain how Id go about doing the second part, regarding passing in a reference and whatnot. Say that I have def SplashScreen as #1, and inside everything is in one frame called totalFrame. I also have ActivationScreen which should follow the splashScreen, and again, has one frame called mainFrame. Could you describe roughly what Id have to do with these to get it running? – qwerty22 Jan 19 '15 at 23:44
-
@qwerty22: the question I linked to shows you how. It creates frames and passes in a "controller", which is itself. It knows about all of the frames and can show or delete them. The other pages can then call any method of the controller., – Bryan Oakley Jan 20 '15 at 00:00
-
Ah, ok, I associate the example with the first bit and somehow didnt make the connection. Thanks! – qwerty22 Jan 20 '15 at 00:25
-
So Iv tried just copying one of my windows into the samp you provided, and everything is now working for that given window, except none of the pictures load (using `PhotoImage(file=
)` and `tk.Label(image= – qwerty22 Jan 20 '15 at 04:16)` any ideas why that might be? Tried using full path name and file name. -
Actually got it, apparently they needed to be globals – qwerty22 Jan 20 '15 at 04:27
-
So how would I go about calling for a frame change from inside a function (not from a button)? – qwerty22 Jan 22 '15 at 06:41
-
@qwerty22: I don't understand your question. You cannot change "from a button", you can _only_ do the change from inside a function. Buttons don't do anything but call functions. Your function needs a reference to either the frame (so it can delete it directly) or it needs a reference to a controller-like object (so it can ask the controller to delete it). – Bryan Oakley Jan 22 '15 at 11:44
A button calling a function that deletes all existing frames and rebuilds another sounds like a design flaw. The propensity for errors (forgetting to delete certain elements in some places of the code etc) is pretty large.
If you don't have an insane number of UI elements, I suggest creating them all at once, and hiding/showing various elements as necessary.
Take a look at this SO answer for how you might go about creating GUI elements that can be shown/hidden, and how the callback function might look.
Edit: If you really need to do it based on these functions, then I guess an alternative approach might be this:
Say 'top_frame' is the frame that includes all your widgets which you want to destroy when you run function #2. Change all of your GUI elements in function #1 so that when you create them, you explicitly pass them top_frame
so that they have a link to it (self.top_frame = top_frame
). This means your button will also have an attribute self.top_frame
. You pass that as one of the arguments to function #2, and function #2 now can refer to top_frame and destroy it.
But definitely prone to error and probably slower due to all the creation/destruction of GUI elements. I recommend going through the code in the answer above when you have the time, it really is a much better solution.
-
I know my existing methods are flawed and/or not in good form. I have little experience and I'm looking to learn how I can improve. That answer probably has a viable solution, but unfortunately, I don't have the expertise required to adapt it to my own work, as there's some functions and whatnot being called on which I didn't even know existed, either way, I'll keep workin' on it and see what happens – qwerty22 Jan 19 '15 at 06:38
-
Deleting a frame and replacing it with another is a reasonable thing to do, I don't see why you call it a design flaw. It's really no different than going to a different section of a website. If all the widgets you want to create/destroy are in a single frame, you just have to delete and recreate one frame, the frame will take care of deleting all of its children. – Bryan Oakley Jan 19 '15 at 11:52
-
hmm, generally I have found it much easier to reason about hiding/showing GUI elements instead of deleting/creating them, but I guess it's mainly in cases where I hide/show subsections of the GUI. – zehnpaard Jan 20 '15 at 01:51