1

I have a tkinter window that I removed the title bar from and added a custom close and minimize button to. When the program first loads it doesn't display an icon to the taskbar. When I click the custom made minimize button it then creates an icon on the taskbar; however, when I click to restore the window I am unable to get rid of the titlebar again.

I want the icon to always show on the taskbar, and when the program is minimized and then restored I would like the title bar to still be gone from .overrideredirect(1). Unfortunately I'm having trouble resetting the flag before and after minimizing without making the taskbar icon disappear.

Please let me know what I am doing wrong. Thanks!

#!/usr/bin/python3
from tkinter import *
import tkinter as tk
import datetime
import time
import math

root = tk.Tk() 

root.overrideredirect(1)

def close():
    root.destroy()
def minimizeWindow():
    root.withdraw()
    root.overrideredirect(False)
    root.iconify()

root.resizable(False, False)
canvas = Canvas(root, width = 400, height = 400)
canvas.pack()
exit = Button(root, text='x', command = close)
exitWindow = canvas.create_window(10,10, window=exit)
minimize = Button(root, text='-', command = minimizeWindow)
minimizeWindow = canvas.create_window(30,10,window=minimize)
icon = PhotoImage(file='py.gif')
root.tk.call('wm', 'iconphoto', root._w, icon)
root.mainloop() # starts the mainloop

I am trying to make it work for both windows and linux. The reason I'm taking out the title bar altogether is to avoid the differences that come from the OS font and window settings. It's currently exhibiting this same behavior on both Operating Systems.

To reiterate, I want the taskbar icon to show up on program launch and I want the program's window to maintain it's titlebar-less state when restored from being minimized.

Jamin
  • 1,362
  • 8
  • 22
  • What are you doing with the icon? It does not work here at all. Are you trying to keep it and use it in your own bar? – Mike - SMT Oct 09 '18 at 17:36
  • The icon seems to work in Linux but not in Windows. I'm more concerned with it displaying an icon at all on the taskbar when it is first started, as well as the overrideredirect. When it's minimized and restored I don't want the title bar to show up. – Jamin Oct 09 '18 at 17:52
  • On windows I can create an label holding an icon on the canvas. That should work for you here. Is there a reason to use canvas over a frame here? – Mike - SMT Oct 09 '18 at 17:54
  • Yes because I'm going to use the canvas class to draw something – Jamin Oct 09 '18 at 17:58
  • You can still use canvas to draw something you do not need to use it for the bar. Unless you are wanting to draw something on the bar? If you do want to draw on the BAR you can still do this with a canvas and just place the canvas object in the bar frame. – Mike - SMT Oct 09 '18 at 18:00

2 Answers2

2

It depends on what operating system you are using. If you are using Windows the below solution should work for you.

I have added a function that will reapply the overriderdirect. This function is being called by a bind we used on root.

I have also changed your canvas to a frame as this make it easier to manage things like buttons.

For linux you may need to use a different file type. On window you use .ico and on linux you may need to use .xbm.

See this answer about it on this post: Python 3 tkinter iconbitmap error in ubuntu

Update:

I have added the iconbitmap and root.tk.call('wm', 'iconphoto', root._w, icon) however I am not sure if you will be able to make your taskbar icon change until you compile the code at least in windows. You can use py2exe or freeze. I have used freeze before and I have a customer desktop and taskbar icon I use for it.

import tkinter as tk

root = tk.Tk() 
root.geometry("400x400")
root.overrideredirect(1)
root.resizable(False, False)
root.columnconfigure(0, weight=1)
root.iconbitmap(default='./Colors/small_red.ico')


def close():
    root.destroy()

def minimizeWindow():
    root.withdraw()
    root.overrideredirect(False)
    root.iconify()

def check_map(event): # apply override on deiconify.
    if str(event) == "<Map event>":
        root.overrideredirect(1)
        print ('Deiconified', event)
    else:
        print ('Iconified', event)

bar_frame = tk.Frame(root)
bar_frame.grid(row=0, column=0, sticky="ew")
bar_frame.columnconfigure(0, weight=1)
icon = tk.PhotoImage(file='./Colors/small_red.gif')
# This appears to have the same results so not sure what the difference is from iconbitmap.
# root.tk.call('wm', 'iconphoto', root._w, icon) 

tk.Button(bar_frame, text='x', command=close).grid(row=0, column=1)
tk.Button(bar_frame, text='-', command=minimizeWindow).grid(row=0, column=2)

root.bind('<Map>', check_map) # added bindings to pass windows status to function
root.bind('<Unmap>', check_map)

root.mainloop()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
  • Thank you for your response, I appreciate it a lot! I am trying to make it work for both windows and linux. The reason I'm taking out the title bar altogether is to avoid the differences that come from the OS font and window settings. I'm focused on getting it to work from ubuntu properly first before moving to Windows. I went ahead and tested the program on PC. The changes you suggested exhibits the same behavior as before on both operating systems. I've edited my main post to reflect this. – Jamin Oct 09 '18 at 17:06
  • @Jamin my code works fine on windows when it comes to keeping the overrideredirect working. I will see what I can do about the Icon and linux option. – Mike - SMT Oct 09 '18 at 17:37
  • @Jamin I have updated my code for the windows side of things. I am still reviewing linux. – Mike - SMT Oct 09 '18 at 18:04
  • Thank you for your update. I do not want the image to be on the program's canvas, I want the image to be the icon displayed on the taskbar for the operating system when the program is minimized. For my purposes I'm simply going to make the bar as well as rest of the program be drawn on a single canvas. Also I have retested the original program I posted and the icon works on the taskbar like intended on both Windows and Linux. The only problem is that the taskbar icon doesnt show up when the program is launched, and the titlebar reappears when restored from minimized. – Jamin Oct 09 '18 at 18:18
  • 1
    @Jamin I see I misunderstood your need. I am sure I can edit my answer to provide the icon to the minimized taskbar window. Keep in mind It is likely that you will not be able to provide a taskbar icon to the windows taskbar until you compile your code into an executable. Running the code from the python interpreter or the IDE may not allow it. – Mike - SMT Oct 09 '18 at 18:33
  • @Jamin I have found something that might help however I cannot test on linux. Please review my updated answer and there is a link to a related post. – Mike - SMT Oct 09 '18 at 18:57
  • This seems to work in windows but not in linux. I had to convert my gif to make a .ico file as well. I dont think linux uses .ico for their icons, I was trying to work around it but it seems to cause more problems on linux than before. Very useful for a windows-only case. Still looking for a way to get it to work in both linux and windows though. – Jamin Oct 09 '18 at 19:25
  • 1
    @Jamin You cannot use .ico in linux. Try using a `.xbm` file. That was part of the issue on the linked answer I added. – Mike - SMT Oct 09 '18 at 19:29
  • Results in the following error on Ubuntu. >>>> Traceback (most recent call last): File "stackovans.py", line 8, in root.iconbitmap(default='py.xbm') File "/usr/lib/python3.5/tkinter/__init__.py", line 1717, in wm_iconbitmap return self.tk.call('wm', 'iconbitmap', self._w, '-default', default) _tkinter.TclError: wrong # args: should be "wm iconbitmap window ?bitmap?" – Jamin Oct 09 '18 at 19:49
  • The string for the xmb file needs to start with a @. Try this for linux: `root.iconbitmap(default='@py.xmb')`. – Mike - SMT Oct 09 '18 at 19:57
  • I have attempted the prepending of @ to the file name. It results in the same error. From prior research I learned that gif was supported as a taskbar icon image format on ubuntu and .xmb caused problems for some. I know that I can get the icon to work on both windows and linux using the .gif format. Not yet sure how to use it in the code example you provided – Jamin Oct 09 '18 at 20:00
  • @Jamin I may need to install linux on my 2nd hard drive later to test. Sorry I cannot help further on the linux side. – Mike - SMT Oct 09 '18 at 20:03
  • @Jamin were you able to figure it out? – Mike - SMT Oct 12 '18 at 14:34
  • I haven't actually put it all together, but I figure the best way to do it is to handle each os separately. I think I can merge the answer you provided me for windows with the linux version with some sort of conditional if I really need to. Thanks for the windows solution! – Jamin Oct 12 '18 at 15:31
  • @Jamin You can by running an `if` statement at the beginning to check what OS you are on and then from there use it to run one or the other solutions. – Mike - SMT Oct 12 '18 at 15:34
0

There Are Two Ways

If you want to restore it in a new/custom Taskbar Just do this:-

from tkinter import *
import tkinter as tk
import datetime
import time
import math

root = tk.Tk() 

def close():
    root.destroy()
def minimizeWindow():
    root.update_idletasks()
    root.overrideredirect(False)
    root.state('iconic')
    root.attributes('-topmost', True)
    root.overrideredirect(True)
    root.geometry("215x330")
root.wm_overrideredirect(True)
root.attributes('-topmost', False)
root.resizable(False, False)
canvas = Canvas(root, width = 400, height = 400)
canvas.pack()
exit = Button(root, text='x', command = close)
exitWindow = canvas.create_window(10,10, window=exit)
minimize = Button(root, text='-', command = minimizeWindow)
minimizeWindow = canvas.create_window(30,10,window=minimize)
icon = PhotoImage(file='py.gif')
root.tk.call('wm', 'iconphoto', root._w, icon)
root.mainloop()

Else if you want to restore in your windows Taskbar:-

from tkinter import *
import tkinter as tk
import datetime
import time
import math

root = tk.Tk() 

root.overrideredirect(1)
def check(event):
    if str(event) == "<Map event>":
        window.overrideredirect(1)
    else:
        None
def close():
    root.destroy()
def minimizeWindow():
    root.withdraw()
    root.overrideredirect(False)
    root.iconify()
root.overrideredirect(True)

root.resizable(False, False)
canvas = Canvas(root, width = 400, height = 400)
canvas.pack()
exit = Button(root, text='x', command = close)
exitWindow = canvas.create_window(10,10, window=exit)
minimize = Button(root, text='-', command = minimizeWindow)
minimizeWindow = canvas.create_window(30,10,window=minimize)
icon = PhotoImage(file='py.gif')
root.tk.call('wm', 'iconphoto', root._w, icon)
root.bind('<Map>', check_map) 
root.bind('<Unmap>', check_map)
root.mainloop() # starts the mainloop