Tkinter app disappears when exiting full screen - python

I have a python tkinter application and want to display it in full screen when starting it (in Ubuntu if that matters). So I used Tk.attributes('-zoomed', True). If I pull the window out of full screen with the mouse it just disappears. I can still see the application's icon - so it's still open - but I can only see my empty desktop and clicking on the icon doesn't make it visible either.
When I define the window's size with Tk.geometry('1500x800'), then make it full screen and exit full screen again like before it doesn't disappear.
What could be the reason for that?
Thanks in advance.
edit: I'm sorry, I wrote the question from memory and it's been I while since I wrote that and Tk is not my real variable name. Here is the actual code:
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# Set the window's size
self.geometry('1500x800') # set size manually
# self.attributes('-zoomed', True) # fullscreen with toolbar
# self.attributes('-fullscreen', True) # fullscreen
...

If you want to set the fullscreen attribute to True, it is as easy as:
root = Tk()
root.attributes('-fullscreen', True)
However, it doesn't show the title bar. If you want to keep it visible, you can resize the Tk element with the geometry() method:
root = Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (w, h))

Related

How do I change the size of a tkinter canvas through a new window?

So I have one Tkinter screen that has a canvas. I want to change the size of the canvas by creating a new window that has entry widgets. So I created a new screen and added 2 entry widgets. I want to get the value from those widgets and based on that...it should change the size of the canvas. I tried to do this for an hour, but no luck. Please assist me.
Here is my code
from tkinter import *
# create root window
root = Tk()
# Create Canvas
canvas = Canvas(root, width=50, height=50)
# Create an additional window (the one that is used to enter the new geometry)
dialog = Toplevel(root)
# Add entry widgets for width and height to the new window
width_entry = tk.Entry(dialog)
height_entry = tk.Entry(dialog)
# Add a button to the new window that applies the given width and height
apply_button = Button(dialog, text = 'Apply geometry', command = lambda: canvas.geometry(width_entry.get()+'x'+height_entry.get()))
# Its not possible to get the geometry of a canvas in tkinter...so how do I change the size.
# display the entry boxes and button
width_entry.pack()
height_entry.pack()
apply_button.pack()
# start the tk mainloop
root.mainloop()
Please Assist me
The command you are looking for is canvas.config
Here, I have adjusted the given code:
import tkinter as tk
# create root window
root = tk.Tk()
# Create Canvas
canvas = tk.Canvas(root, width=50, height=50)
canvas.pack()
# Create an additional window (the one that is used to enter the new geometry)
dialog = tk.Toplevel(root)
# Add entry widgets for width and height to the new window
width_entry = tk.Entry(dialog)
height_entry = tk.Entry(dialog)
# Add a button to the new window that applies the given width and height
apply_button = tk.Button(dialog, text = 'Apply geometry', command = lambda: canvas.config(width=width_entry.get(), height=height_entry.get()))
# display the entry boxes and button
width_entry.pack()
height_entry.pack()
apply_button.pack()
# start the tk mainloop
root.mainloop()
I also changed a couple other things:
You imported * from tkinter, but for some items you still led with tk.; I changed them all to match that and switched the import to match as well. (You could still use *, but then just don't have the leading tk.s.)
The canvas was never packed so you could never see what was going on there.
One more suggestion, that line where you make the button is really long. Maybe make a function that does what the lambda does and assign its command to that function instead of a lambda. You can probably see that a line that long is even hard to read here much less if someone (maybe a future version of yourself) was to try to read your code, and edit it or make sense of it. Generally, try to keep all lines down to 80 characters.
Let us know if you have any more questions etc.

Disable window move in Tkinter Python

it seems that I was pending to continue the bombardment of questions. It this is short, Is it possible to disable the movement of the Tkinter window without deleting the top bar of this?
It would give a minimal and reproducible code, but if it did it would only be two lines, it would be useless.
Bind a event for your window,and set the window .geometry()
But now you can not revise the window size by dragging the window's border(But it can maximize the window.).
Here is an example of the code:
import tkinter
def GetWindowPos():
global X,Y
X = win.winfo_geometry().split("+")[1]
Y = win.winfo_geometry().split("+")[2]
win.bind_all('<Configure>', HoldOn)
def HoldOn(event):
win.geometry("+{}+{}".format(X,Y))
win = tkinter.Tk()
win.geometry("400x400+{}+{}".format(12,12))
tkinter.Label(win,text="Halo!").grid()
win.after(100,GetWindowPos)
win.mainloop()
I have found a method, but as you might know to achieve something, we have to lose something!
You can use:
root.overrideredirect(True) # turns off title bar
by which you wont be able to move the tkinter window and also Tkinter application won't be displayed in taskbar, but you will also lose the title bar.
but if you wish to have the title bar,
then you can create one by this link.
Or use below to make a new title bar and also be able to move it(from this answer)
def move_window(event):
root.geometry('+{0}+{1}'.format(event.x_root, event.y_root)
# bind title bar motion to the move window function
title_bar.bind('<B1-Motion>', move_window)
But still your Tkinter application won't show up in taskbar, here's a solution(from this answer):
root = tkinter.Tk()
top = tkinter.Toplevel(root)
root.attributes("-alpha",0.0) # to make root invisible
#toplevel follows root taskbar events (minimize, restore)
def onRootIconify(event): top.withdraw()
root.bind("<Unmap>", onRootIconify)
def onRootDeiconify(event): top.deiconify()
root.bind("<Map>", onRootDeiconify)
You can add a toplevel window under the root object, make toplevel invisible and then handle the icon events of top level to hide or show the root window on taskbar.

How do I create a new python tkinter window so fits exactly in the available desktop area, but isn't maximized?

(Environment: Windows, Python 3)
My problem is that using .geometry to set a height & width sets the height & width of the space inside the window - the title bar and window border make it larger. Below is my code so far. As you'll see, even though I have it create a window that's the exact size of the available screen area, the window ends up being too big because the title bar and borders aren't accounted for when setting the size.
See that "what needs to change here" part? What do those two statements need to be changed to or replaced with, that's simple? (If you have it right, the window should fit exactly in the available space on your desktop, with title bar and borders clearly visible.)
Please keep it simple - I'm still new to all of this. :-)
#Important variables:
#screenAvailableWidth, screenAvailableHeight: Height & width of
# screen without
# taskbar
#windowWidth, windowHeight: Height & width of new window to create
#window: Object of class Tk() from tkinter.
#Get screen height and width WITHOUT including the taskbar.
#This part works fine - I've tested the result and it's good.
from win32api import GetMonitorInfo, MonitorFromPoint
monitorInfo = GetMonitorInfo(MonitorFromPoint((0,0)))
workArea = monitorInfo.get("Work")
screenAvailableWidth = workArea[2]
screenAvailableHeight = workArea[3]
#Create a tkinter window
from tkinter import Tk
window = Tk()
#Set new window height & width
#--------------------------------------------
#----- HERE. What needs to change here? -----
#--------------------------------------------
windowWidth = screenAvailableWidth
windowHeight = screenAvailableHeight
#--------------------------------------------
#Show debug info
print("")
print("screenAvailableWidth:",screenAvailableWidth,
" screenAvailableHeight:",screenAvailableHeight)
print("windowWidth:\t",windowWidth," windowHeight:\t",windowHeight)
#Set the new window to upper left corner and height &
# width of screen
window.geometry("{}x{}+0+0".format(windowWidth,windowHeight))
#Show the window
window.mainloop()
I GOT IT! The trick is that as long as the window's visible (even if it's somewhere offscreen), you can do this:
titlebarHeight = window.winfo_rooty() - window.winfo_y()
borderSize= window.winfo_rootx() - window.winfo_x()
And once you have those, you can adjust your desired window width and height to correct for the title bar and borders like this:
WindowWidth = WindowWidth - (borderSize * 2)
WindowHeight = (WindowHeight - titlebarHeight) - borderSize
So, the code that ended up working in the end is this (which is complete - copy and paste this into your editor of choice and it should run as-is):
#Get screen height and width WITHOUT including the taskbar.
#This part works fine - I've tested the result and it's good.
from win32api import GetMonitorInfo, MonitorFromPoint
monitorInfo = GetMonitorInfo(MonitorFromPoint((0,0)))
workArea = monitorInfo.get("Work")
screenAvailableWidth = workArea[2]
screenAvailableHeight = workArea[3]
#Create a tkinter window
from tkinter import Tk
window = Tk()
#Set new window height & width
#--------------------------------------------
#----- HERE. This is what changed: -----
#--------------------------------------------
#Make window visible so we can get some geometry
window.update_idletasks()
#Calculate title bar and border size
titlebarHeight = window.winfo_rooty() - window.winfo_y()
borderSize= window.winfo_rootx() - window.winfo_x()
#Start with full available screen
windowWidth = screenAvailableWidth
windowHeight = screenAvailableHeight
#Adjust for title bar and borders
windowWidth = windowWidth - (borderSize * 2 )
windowHeight = (windowHeight - titlebarHeight) - borderSize
#--------------------------------------------
#Show debug info
print("")
print("screenAvailableWidth:",screenAvailableWidth,
" screenAvailableHeight:",screenAvailableHeight)
print("windowWidth:\t",windowWidth," windowHeight:\t",windowHeight)
#Set the new window to upper left corner and height &
# width of screen (after adjustment)
window.geometry("{}x{}+0+0".format(windowWidth,windowHeight))
#Show the window
window.mainloop()
(The breakthrough was examining all the properties mentioned in the suspected duplicate question (and it's comments and replies) here: tkinter window get x, y, geometry/coordinates without top of window
That question didn't really put the pieces together in a newbie-friendly way, nor did it have any usable sample code, so hopefully this will be of use to someone else in the future.)
To everyone who commented and offered solutions for me, thank you! I really appreciate you taking the time to do so. :-)
Instead of using monitorInfo you can use winfo_screedwidth() and winfo_screenheight().
This is how to do it:
windowWidth = window.winfo_screenwidth
windowHeight = window.winfo_screenheight
window.geometry("%sx%s" %(screenWidth, screenHeight)
You can use window.overrideredirect(True) to get rid of the task bar. It will also get rid of the bar at the top, so you will have to use alt+f4 to exit out of the window.
Also, these options are optional but will certainly make your code more clear and efficient by getting rid of possible errors which may occur when doing certain tasks with the code.
--You can stop reading if you want to--
Instead of from tkinter import Tk use import tkinter as tk. This means you can write tk.widget and not having to write out every widget you use. Also, if you use from tkinter import * you can use import tkinter as tk instead as it groups all attributes into tk. It will certainly clean up the attributes, and you will not having them together with all of the built in attributes
Also, get all of your widgets into a class. You can do this like so:
class Name(tk.Frame):
Inside it you need to write the __init__ function:
def __init__(self, master, **kwargs): #Feel free to add any extra parameters
Inside the __init__ function you write:
super().__init__(master, **kwargs)
The class makes your code neat and tidy while the __init__ and super() are needed for whenever you make a function.
Also, you can use the __name__ == "__main__" if condition to stop the code from running when importing it to another script.
This is how to do this:
def func_name():
root = tk.Tk()
#Add any root titles, geometry or any other configurations here
app = Window(root) #Instead of Window, replace it with your class name
app.pack(fill=tk.BOTH, expand=True)
#Add any app configurations here
root.mainloop()
if __name__ == "__main__":
func_name()
All these features, you can include to make your code neater.

Widgets disappear when main window moved off screen

I have a tkinter window that I have given a background picture by creating a Label widget with a PhotoImage instance (referencing the image instance through Label attributing).
However when I run the script and move the main window below the start menu (am using Windows 10) or past the sides of the screens for even one moment, all the widgets packed onto the Label (w/ background pic) completely disappear.
They only come back (somewhat) upon hovering over them with the mouse it seems. Also the background picture remains and continues to fill the screen. Could it be that the background picture Label is being "lifted" and makes it seem like the widgets are disappearing? If so, how can I prevent this from happening?
The fix that I have found for now is to not use a Label with a PhotoImage as the parent "frame", but instead use a typical Frame widget with only a background color, but this is not ideal.
import tkinter as tk
root = tk.Tk()
root.geometry('600x350+600+300')
root.resizable(width=False, height=False)
boxBg = '#666'
frameBg = '#fff'
#problem method
backgroundImg = tk.PhotoImage(file='program_media/background.png')
bgFrame = tk.Label(root, image=backgroundImg)
bgFrame.image = backgroundImg
#less than ideal solution so far
#bgFrame = tk.Frame(root, bg='#fff')
bgFrame.pack(expand=1, fill=tk.BOTH)
mainFrame = tk.Frame(bgFrame)
mainFrame.pack(side=tk.TOP)
title = tk.Label(mainFrame, text='Test String')
title.pack(side=tk.TOP)
#widget creation code packed within mainFrame
#...
#... All these widgets (including mainFrame above) are disappearing
#...
#end of widget creation code
root.mainloop()
See what I mean in this screenshot of BEFORE and AFTER moving the main window below the start menu.

How do I stop flickering in my transparent Splash screen in Tkinter?

Using a bit of modified code I found on the web for creating a generic Tkinter splash screen, I tried to to create a transparent splash screen kind of thing with a .png. I know this code will only work with Windows and I am fine with that.
However, I notice there is flickering (Canvas area is black before it draws the picture) with the image when it draws on the screen. I don't know very much about it but I suspect it has to do something with the buffering of the image after googling and reading. I also read that canvas supports double buffering so the flickering shouldn't be happening so maybe it's the Top Level widget or something.
In any case is there any fix to this? I'd really like to continue using Tkinter for this and it would be a huge letdown not to be able to get rid of the flickering. Here is the code I am using below.
from Tkinter import *
import ttk
from PIL import Image, ImageTk
import time
class Splash:
def __init__(self, root, filename, wait):
self.__root = root
#To use .pngs or .jpgs instead of just .bmps and .gifs, PIL is needed
self.__file = ImageTk.PhotoImage(Image.open(filename))
self.__wait = wait + time.clock()
def __enter__(self):
# Hide the root while it is built.
self.__root.withdraw()
# Create components of splash screen.
window = Toplevel(self.__root)
#Set splash window bg to transparent
window.attributes('-transparent', '#FFFFFE')
#Set canvas bg to transparent
canvas = Canvas(window,bg="#FFFFFE")
splash = self.__file
# Get the screen's width and height.
scrW = window.winfo_screenwidth()
scrH = window.winfo_screenheight()
# Get the images's width and height.
imgW = splash.width()
imgH = splash.height()
# Compute positioning for splash screen.
Xpos = (scrW - imgW) // 2
Ypos = (scrH - imgH) // 2
# Configure the window showing the logo.
window.overrideredirect(True)
window.geometry('+{}+{}'.format(Xpos, Ypos))
# Setup canvas on which image is drawn.
canvas.configure(width=imgW, height=imgH, highlightthickness=0)
canvas.pack()
# Show the splash screen on the monitor.
canvas.create_image(imgW // 2, imgH // 2, image=splash)
window.update()
# Save the variables for later cleanup.
self.__window = window
self.__canvas = canvas
self.__splash = splash
def __exit__(self, exc_type, exc_val, exc_tb):
# Ensure that required time has passed.
now = time.clock()
if now < self.__wait:
time.sleep(self.__wait - now)
# Free used resources in reverse order.
del self.__splash
self.__canvas.destroy()
self.__window.destroy()
# Give control back to the root program.
self.__root.update_idletasks()
self.__root.deiconify()
if __name__ == '__main__':
#thread2 = myLazyDoStuffThread()
root = Tk()
with Splash(root,'splash.png',3):
myprog = ApplyGUIAndOtherThings(root)#,thread2)
root.mainloop()
A rule of thumb you should follow is to never put a call to sleep in a GUI. It does exactly what it says, it causes your whole application to sleep. This means that the GUI is not able to redraw itself, and is likely the cause of your flicker.
If you want a window to be destroyed after a period of time, use the after method. For example:
delta = (self.__wait - now) * 1000
self.after(delta, self.close)
You'll need to define self.close to destroy the window.
This gives you an opportunity to add a little "fade away" effect if you like. You do this by checking to see if the alpha of the splash screen is below some threshold (say, 10%) and destroy it. If it's not, reduce the alpha by 10% and call the function again in 100 ms.

Categories