I've been searching and not finding an answer as far as the differences of iconify() and withdraw() methods of Tkinter are concerned.
iconify() seems to "convert" the window to a taskbar icon and has a state of "iconic"
withdraw() seems to just remove the window from the screen, after which the window has a state of "withdrawn"
If you need to reverse the situation, you simply call deiconify() on both situations.
However, what is the real difference between the two methods and how do they essentially differ from one another?
Moreover, are they applied in different situations?
You've got it down correctly.
In more detail:
iconify() Turns the window into an icon (without destroying it). To redraw the window, use deiconify. Under Windows, the window will show up in the taskbar.
When the window has been iconified, the state method returns “iconic”.
withdraw() Removes the window from the screen (without destroying it). To redraw the window, use deiconify.
When the window has been withdrawn, the state method returns “withdrawn”.
Source: Tkinter -- Toplevel Window Methods
As far as use-cases go, you would normally use iconify() in situations where you want the user to be able to easily gain access to a window that was "minimized" (via iconify()) for whatever reason. For example, say a user clicks a button that "minimizes" a window and opens up a new one. Using iconify() lets the user do whatever they need to do in the new window and then return to the previous one easily since it appears to them as an icon.
On the other hand, withdraw() is useful to "hide" windows. For example, I have developed some applications that automatically created multiple windows on start-up of the application. If I had used iconify() the user would be aware of all the windows that had been created because they'd see them as icons. Imagine the shock of a user seeing 10 windows by simply starting up an application! Therefore, I used withdraw() so that each window would appear (via deiconify()) only if the user triggered the right event.
Related
I just want the equivalent of closing and reopening my main program. I want to invoke it when a "new"-like option from a drop-down menu is clicked on. Something like calling root.destroy() and then re-initiating the mainloop.
How can I get this done?
There are at least three ways you can solve this.
Method one: the head fake. When you create your app, don't put all the widgets in the root window. Instead, hide the root window and create a new toplevel that represents your application. When you restart it's just a matter of destroying that new toplevel and re-running all your start-up logic.
Method two: nuke and pave. Similar in concept but slightly different in execution. In this model, when you want to restart you simply delete all the widgets in the main window, reset the geometry to null (so the window will once again resize itself based on its contents) and then run the logic that draws all the other widgets.
Method three: if it worked the first time... As suggested by Martin v. Löwis, simply have your program exec a new instance of the program, then exit.
The first two methods are potentially faster and have the (dis?)advantage of preserving the current environment. For example you could save the copy of the clipboard, column widths, etc. The third method absolutely guarantees a blank slate.
If you are on Unix, restart the entire application with os.execv. Make sure you pass all command line arguments etc.
You could take all your GUI building logic and initial state code out of the mainloop and put it into functions. Call these functions from the mainloop (something like: buildgui() & initstate()) and then, when the user clicks your menu icon, just call initstate() to set it back like it was when the application first started.
I wanted to ask if it is possible to draw a child window inside a parent window so that it will only be able to move inside the parent window and won't be able to move out of the parent window bounds.
If you mean having actual windows with title bar, menu, status bar etc. inside the parent window then the answer is:
No, Tcl/Tk and by extension Tkinter does not support this with its standard widgets.
There have been efforts in the past to implement widgets which emulate MDI as you can see on the TCL wiki, but most of them are over a decade old. You will probably have to implement it yourself or choose a different GUI toolkit if you really need to implement this kind of UI design.
If you do it yourself, you can use the Frame widget as the subwindow, and use place to put it in the containing window. Or, you can create it as an object on a canvas. You'll have to write all of the code to give the inner window borders and a title bar, and to manage moving it around, iconifying it, etc.
I know that I can subclass a tk.Frame (or ttk.Frame) and add that to a TopLevel to make secondary windows, but I'm not sure how I should use that as the main window. I know that creating an instance of a Frame class and calling .mainloop() on it seems to work for using it as the main window, but I feel like that's bad practice...
What do other people do when they are making GUI layouts that they want to have available to main windows and secondary windows?
Create a subclass of a Frame, and then put it either in the root window or a toplevel. In either case, you still call mainloop only once on the root window.
The only care you have to take is that you have to be careful about letting the user close the root window, because it will cause all of the other windows to be destroyed.
If you're creating a program that can have multiple windows, you might want to consider hiding the root window and always putting your window in a Toplevel. Of course, when you do that you need to make sure you destroy the root window whenever the last toplevel window is destroyed, or your program will continue to run but the user will have no way to access it.
Do you mean having a home screen that you can flip back to? If so, you can try looking here: Using buttons in Tkinter to navigate to different pages of the application?
Is there a python library that allows you to create a GUI without the window manager (and equivalent under MS Windows) frame thing, and allow to set the window top-most (like over all other windows) ?
I've been looking on Internet but I'm obviously missing the right keywords.
Yup. Tkinter, or "tkinter" in python3. It's included in standard python distributions
Removing the Window Manager
The method
root.overrideredirect(True)
Removes the borders and manager. Setting the flag indicates to the manager that you don't want the widget to be managed. You can look at ttk, an extension to tkinter commonly included (in Python3 it's tkinter.ttk) if you don't want to completely remove the border, but just pick a different style.
Setting the TopMost Attribute
The method
root.wm_attributes("-topmost", 1)
Will put it at the top of the screen Combined, these will give you the desired behavior. You can then use other tkinter frames to decorate the widget as you please, i.e., add custom borders or close/minus buttons that would normally be included in the manager.
Resources
See this, e.g. for applying the topmost attribute
Make a tkinter window appear over all other windows
From Effbot about "overridedirect" (http://effbot.org/tkinterbook/wm.htm):
Sets or gets the override redirect flag. If non-zero, this prevents
the window manager from decorating the window. In other words, the
window will not have a title or a border, and it cannot be moved or
closed via ordinary means.
Note:
These functions can only be applied to the root window (Tk instance) or another Toplevel instance.
I just want the equivalent of closing and reopening my main program. I want to invoke it when a "new"-like option from a drop-down menu is clicked on. Something like calling root.destroy() and then re-initiating the mainloop.
How can I get this done?
There are at least three ways you can solve this.
Method one: the head fake. When you create your app, don't put all the widgets in the root window. Instead, hide the root window and create a new toplevel that represents your application. When you restart it's just a matter of destroying that new toplevel and re-running all your start-up logic.
Method two: nuke and pave. Similar in concept but slightly different in execution. In this model, when you want to restart you simply delete all the widgets in the main window, reset the geometry to null (so the window will once again resize itself based on its contents) and then run the logic that draws all the other widgets.
Method three: if it worked the first time... As suggested by Martin v. Löwis, simply have your program exec a new instance of the program, then exit.
The first two methods are potentially faster and have the (dis?)advantage of preserving the current environment. For example you could save the copy of the clipboard, column widths, etc. The third method absolutely guarantees a blank slate.
If you are on Unix, restart the entire application with os.execv. Make sure you pass all command line arguments etc.
You could take all your GUI building logic and initial state code out of the mainloop and put it into functions. Call these functions from the mainloop (something like: buildgui() & initstate()) and then, when the user clicks your menu icon, just call initstate() to set it back like it was when the application first started.