Get icon of root window to be used by second window tkinter - python

I was wondering if there is anyway to get the ico file of one window and use it in the same window, without getting to know the icon location.
from tkinter import *
root = Tk()
root.iconbitmap('img/icn.ico')
top = Toplevel()
root.mainloop()
Here I want top to have icon of root without saying top.iconbitmap() or top.iconphoto(), the closest ive got is top.tk.call('wm','iconbitmap') but I dont know what is to be done with this as i couldnt find a understandable documentation.
Why dont I want to use iconbitmap(), its basically that, with tkinter.messagebox you can see the messagebox automatically inherit the icons from the parent widget. I was trying to duplicate this effect. Where if the icon is the default tk icon, then show blank icon or else show the custom icon.
Thanks in advance :D

[I'm using links into the core Tk documentation here. It's much more accurate than the Tkinter docs for most things, and Tkinter is mostly an obvious thin wrapper around it.]
You don't want wm iconbitmap. That's been effectively obsolete for decades; it uses an object class — bitmap — that's not relevant these days as it is monochrome and uses the weirdest format. (Filenames need to be preceded by # to make them work.)
Instead, you want to manipulate the wm iconphoto of the toplevel windows concerned. These take true photo images (there are many image file formats you can load into them) and you can share them easily.
# Load the image from the file; can also use PNG and other formats
my_image = PhotoImage(file="image.gif")
# Apply the image as the icons
first_toplevel_window.iconphoto(False, my_image)
second_toplevel_window.iconphoto(False, my_image)
Note that how the icon is displayed can vary wildly; it's not under your control.

You can use iconphoto() and set the first argument to True, then the same icon will be used for future created toplevels as well:
import tkinter as tk
root = tk.Tk()
icn = tk.PhotoImage(file='my-icon.png')
root.iconphoto(True, icn)
top = tk.Toplevel(root)
root.mainloop()

If you use the default instead of the bitmap (or first) argument, the icon will automatically be used on all TopLevel windows:
root.iconbitmap('img/icn.ico') # icon set only on root
root.iconbitmap(bitmap='img/icn.ico') # same as above
root.iconbitmap(default='img/icn.ico') # icon set on root and all TopLevels

Related

Tkinter: disable text widget content auto resize (newline), when user resize window

Advice: i'm working on Windows 8.1, with Python and Tkinter at last version; i wrote from tkinter import * to post less code here, i know that it is a bad practice, use for example import tkinter as tk instead.
I'm coding my first text editor, and i have a problem when i resize the main windows. When i run the program it display on screen a window with dimension 750x500 pixel. So far, all ok, i can write text without problem (note that menu_bar and other features are work-in progress, but we dont care about them). Problem is with Text widget when user tries to resize window with cursor. The content of the text practically adapts to the size of the window (the length of each string is reduced or increased based on the width of the window). But i don't want that this happen. I want that Text widget changes his width automatically in base of window size, but the content mustn't be adapted. I hope that you understand my question, if not, i will try to explain better.
I have searched on online reference if there's a parameter to set this option, but i haven't found anything.
How to solve the problems concerning the Text widget and resizing the window?
from tkinter import *
root = Tk()
root.geometry("750x500")
content_text = Text(root, wrap=WORD, bg="grey25", undo=True, cursor="",
insertbackground="red", foreground="white", font="courier 12")
content_text.pack(fill=BOTH, expand=True)
scroll_bar = Scrollbar(content_text)
content_text.configure(yscrollcommand=scroll_bar.set, selectbackground="dodgerblue")
scroll_bar.configure(command=content_text.yview)
scroll_bar.pack(side=RIGHT, fill=Y)
if __name__ == '__main__':
root.mainloop()
You can't do what you want. If you have wrapping turned on, text will always wrap at the edge of the window. When you change the width of the window, the text will re-wrap to the new width. There is no configuration option to tell the widget to wrap at any other place.

Why packing widgets into frames instead of directly packing them into the root window?

I'm learning Python by building an airplane ticket app. I'm currently working on learning TkInter for the GUI, and I want to know why I have to create a container (frame) instead of just putting everything in root = Tk() which seems to work.
Also, isn't ttk part of tkinter, therefore I shouldn't have to have the 2nd line (from tkinter import ttk)?
Here's my code:
from tkinter import *
from tkinter import ttk
root = Tk()
frame = Frame(root)
root.title("AirTix")
flight_title = Label(frame, text = "Flights").grid()
root.mainloop()
Thanks!
I want to know why I have to create a container (frame) instead of just putting everything in root = Tk() which seems to work.
You do not have to create a container. Whatever tutorial or book is telling you that you must is wrong. There's nothing wrong with creating everything in the root window.
That being said, for anything but the most trivial of apps, it helps tremendously to organize your widgets in logical groups, with each logical group being a frame (or, perhaps, a Canvas or PanedWindow). This gives you the flexibility to use the best geometry manager (pack, place, or grid) for each section.
For example, it makes sense to have a toolbar that is a frame with a bunch of buttons packed left-to-right. The same might be true for a bottom status bar. The main body might be a frame with widgets arranged in a grid.
grid can be a bit more complicated to use, and pack excels at placing widgets either in a single horizontal row (toolbar or status bar), or column (toolbar on top, status bar on bottom, main area in the middle.
Also, isn't ttk part of tkinter, therefore I shouldn't have to have the 2nd line (from tkinter import ttk)?
Even though ttk is part of tkinter, it does not get imported when you import everything from tkinter. Many python packages are this way, with sub-modules that must be explicitly imported.
Further, it's bad practice to use a wildcard import. Instead of doing this:
from tkinter import *
root = Tk()
... it's arguably better to do it like this:
import tkinter as tk
root = tk.Tk()
With the former, you end up polluting the global namespace with a bunch of things you may or may not use. With the latter, you import exactly one thing. Plus, it makes your code more self-documenting because it makes it crystal clear when you are expecting to use an object or class from the tk package.

Which file formats can I use for tkinter icons?

I know this might be obvious, but in tkinter you can set an icon, but I have found it really hard to find one. I just wanted to know if you have to use the .ico format for the file or if there is a way to use .png or .jpeg files.
Currently I have
window = Tkinter.Tk()
window.title("Weclome!")
window.geometry("200x300")
window.wm_iconbitmap("Icon.ico")
window.configure(background = "Black")
That is the whole setup I have and I just want to know about line 4:
window.wm_iconbitmap("Icon.ico")
Thanks for responding to my question, although i am sorry for not spending more time looking into the question rather than just asking here.
Let's start by reading the documentation!
The documentation at effbot.org says the following regarding iconbitmap(bitmap=None)
Sets or gets the icon bitmap to use when this window is iconified. This method is ignored by some window managers (including Windows).
Note that this method can only be used to display monochrome icons. To display a color icon, put it in a Label widget and display it using the iconwindow method instead.
Same as wm_iconbitmap.
So here's the documentation about iconwindow(window=None):
Sets or gets the icon window to use as an icon when this window is iconified. This method is ignored by some window managers (including Windows).
Same as wm_iconwindow.
window
The new icon window. If omitted, the current window is returned.
According to this other documentation, which actually says the same things as the docstrings of the homonymous method for tkinter in (at least) Python 2.7, 3.5 and 3.6:
wm_iconbitmap(self, bitmap=None, default=None)
Set bitmap for the iconified widget to bitmap. Return the bitmap if None is given.
Under Windows, the default parameter can be used to set the icon for the widget and any descendents that don't have an icon set explicitly. default can be the relative path to a .ico file (example: root.iconbitmap(default='myicon.ico') ). See Tk documentation for more information.
So here's the original Tk documentation:
wm iconbitmap window ?bitmap?
If bitmap is specified, then it names a bitmap in the standard forms accepted by Tk (see the Tk_GetBitmap manual entry for details). This bitmap is passed to the window manager to be displayed in window's icon, and the command returns an empty string. If an empty string is specified for bitmap, then any current icon bitmap is canceled for window. If bitmap is specified then the command returns an empty string. Otherwise, it returns the name of the current icon bitmap associated with window, or an empty string if window has no icon bitmap.
From my understanding of Tcl, here window is your toplevel window (either an instance of Tk or Toplevel).
On the Windows operating system, an additional flag is supported:
wm iconbitmap window ?-default? ?image?
If the -default flag is given, the icon is applied to all toplevel windows (existing and future) to which no other specific icon has yet been applied.
In addition to bitmap image types, a full path specification to any file which contains a valid Windows icon is also accepted (usually .ico or .icr files), or any file for which the shell has assigned an icon.
Tcl will first test if the file contains an icon, then if it has an assigned icon, and finally, if that fails, test for a bitmap.
Not very concrete and thus helpful answer so far.
My conclusion
The iconbitmap function (or method, depending on the programming language) should be used to set a bitmap image to the window when the window is iconified.
On Windows you're allowed to set a full path specification to any file which contains a valid Windows icon is also accepted (usually .ico or .icr files), or any file for which the shell has assigned an icon.
So which images are bitmaps?
xbm and xpm (for X Window System)
According to the Wikipedia article to which I linked "bitmap" to above:
The X Window System uses a similar xbm format for black-and-white images, and xpm for color images.
...
BMP file format
Netpbm format
.wbmp
ILBM
...
So most of the bitmap file formats are not cross-platform! In other words, if someone tells you to use a xbm image for the icon, it may not work on your platform because xbm are bitmaps for X Window System.
Note: even after this answer you may still have problems!
Other possible useful articles
Set window icon
tkinter TclError: error reading bitmap file
I was struggling a lot to find an answer too but finally I peeked into the source code of idle3.6 where I found the following piece of code:
# set application icon
icondir = os.path.join(os.path.dirname(__file__), 'Icons')
if system() == 'Windows':
iconfile = os.path.join(icondir, 'idle.ico')
root.wm_iconbitmap(default=iconfile)
else:
ext = '.png' if TkVersion >= 8.6 else '.gif'
iconfiles = [os.path.join(icondir, 'idle_%d%s' % (size, ext))
for size in (16, 32, 48)]
icons = [PhotoImage(master=root, file=iconfile)
for iconfile in iconfiles]
root.wm_iconphoto(True, *icons)
I searched through all files in the idlelib folder for .ico and .png using the rummage software.
So finally I managed to get the window icon working (on GNU-linux with TkVersion>=8.6) with the following two lines:
icon = PhotoImage(master=root, file='icon.png')
root.wm_iconphoto(True, icon)
where I put the icon directly in my application folder.
From the idle code it seems to me that on Windows still only .ico files are supported.

Determining what tkinter window is currently on top

I have written an application in python 2.7 and tkinter. I created a tool bar with several buttons that open up respective top windows that display various options. I used ttk.Checkbutton with the 'toolbutton' style as an indicator to show whether the option windows are open or closed.
The problem is that the option windows will go to the back if another window is selected. Currently, if one selects the toolbutton again, the option window will close. However, I only want to close the window if it is on top. If the option window is not on top, I want the window to moved to the front.
Some of the code I have working:
class MainWindow:
def __init__(self,application):
self.mainframe=tk.Frame(application)
application.geometry("900x600+30+30")
self.otherOptionsSelect=tk.IntVar()
self.otherOptions_Button=ttk.Checkbutton(application,style='Toolbutton',variable=self.otherOptionsSelect,
onvalue=1, offvalue=0,image=self.optionsIcon, command=self.otherOptions)
def otherOptions(self):
if self.otherOptionsSelect.get()==0:
self.otherOptions.destroy()
return
self.otherOptions=tk.Toplevel()
self.otherOptions.title("IsoSurface Options")
self.otherOptions.geometry("200x165+"+str(int(application.winfo_x())+555)+"+"+str(int(application.winfo_y())+230))
self.otherOptApply_button=ttk.Button(self.otherOptions,text="Apply",command=self.showFrame)
self.otherOptApply_button.place(x=20,y=80,width=50,height=30)
self.otherOptClose_button=ttk.Button(self.otherOptions,text="Close",command=self.otherOptionsClose)
self.otherOptClose_button.place(x=80,y=80,width=50,height=30)
def otherOptionsClose(self):
self.otherOptionsSelect.set(0)
self.otherOptions.destroy()
Here is a picture of the entire application I have written:
In the above image, each window has their respective ttk.checkbutton. At the moment, toggling the checkbutton either opens or closes the window. However, what I really want it to do is close the window if the window is in front of the application, or bring the window to the front if it is behind the application.
Hopefully this clears some things up.
Thanks in advance!
It is in fact possible to check stacking order of windows. Using Tkinter, you have to do some funny tcl evals to get at the information. I found the answer at TkDoc in the section on Windows and Dialogs, scroll down until you get to "Stacking Order". The code baffled me until I started playing around with it interactively. My test code was:
import Tkinter as tk
root = tk.Tk()
root.title('root')
one = tk.Toplevel(root)
one.title('one')
two = tk.Toplevel(root)
two.title('two')
I then manipulated the windows so that two was on top, one under that and root below them all. In that configuration, the following weirdness can tell you relative layering of windows:
root.tk.eval('wm stackorder '+str(two)+' isabove '+str(root))
returns 1, meaning "Yes, window two is above window root." While the following:
root.tk.eval('wm stackorder '+str(root)+' isabove '+str(two))
returns 0, meaning "No, window root is not above window two." You can also use the command:
root.tk.eval('wm stackorder '+str(root))
Which gives back the full window stacking order in the form of a weird string something like this:
'. .68400520L .68401032L'
Which starts to make sense when you run the commands:
str(root)
str(one)
str(two)
and figure out that root has the internal name '.', one is '.68400520L' and two is '.68401032L'. You read the output of root.tk.eval('wm stackorder '+str(root)) backwards so it's saying two is on top, one is under that and root is below both.

Python 2.7/Windows: How to control position of Tkinter common dialogs?

Python 2.7 under Windows: How can we control the position of Tkinter's common dialogs?
Here's what we've discovered:
Certain common dialogs always open up relative to their parent window
Certain common dialogs always open up centered on the user's desktop
All common dialogs appear to ignore the optional parent= parameter
Questions:
How can we force a dialog to open up relative to its parent window?
How can we force a dialog to open up centered on the user's desktop?
Background:
import tkColorChooser as colorchooser
import tkFileDialog as filedialog
import tkMessageBox as messagebox
; # always open up relative to parent windows
fileOpen = filedialog.askopenfilename()
fileOpens = filedialog.askopenfilenames()
fileSaveAs = filedialog.asksaveasfilename()
color = colorchooser.askcolor()
; # always open up centered on desktop
folderOpen = filedialog.askdirectory()
messagebox.askquestion()
Thank you,
Malcolm
For the Windows messagebox you can't. It appears in the center of the screen and that is that. However, the file selection dialog and color chooser are system dialogs that have been given a Tk wrapper so that users see the stock dialogs on this platform. If you set the -parent option then this is passed through to the wrapped windows and it will center itself over your designated toplevel.
In Tk:toplevel .t
tk_chooseColor -parent .t
How you turn that into Tkinter I leave to someone with some Python experience.
As for centering these, the hwndOwner member of the CHOOSECOLOR structure is always set to the HWND for one of your Tk toplevels. To let it parent against the desktop you'd need to pass NULL there and Tk doesn't let you. You could source the unix version (lib/clrpick.tcl) and show that instead but it would then look weird on a Windows desktop.

Categories