python tkinter hide the window during widget creation - python

I have a small annoying problem so I come to you to see if you can help to solve it.
I have the following code in Python2.7:
# main window
root = tk.Tk()
root.title('My application')
# create the objects in the main window
w = buildWidgetClass(root)
# size of the screen (monitor resolution)
screenWi = root.winfo_screenwidth()
screenHe = root.winfo_screenheight()
# now that widgets are created, find the widht and the height
root.update()
guiWi = root.winfo_width()
guiHe = root.winfo_height()
# position of the window
x = screenWi / 2 - guiWi / 2
y = screenHe / 2 - guiHe / 2
root.geometry("%dx%d+%d+%d" % (guiWi, guiHe, x, y))
So I create the main window (without any size) I insert widgets inside, then I define the size of the result, and place it in the middle of the screen.
The number of widget in the window may vary, so the resulting size!
So far, so good, it works ! My only problem is that the window first appear in the left top corner of the screen, then repositioned to the center. Not a big deal, but not really professional neither.
So my idea was to hide the main window during the widgets creation time and then make it appearing after having defined the geometry.
So after the first line, I added :
root.withdraw()
then at the end :
root.update()
root.deiconify()
but when the window reappear, it wasn't re-sized by the widget and have a size of 1x1 !!
I tried to replace root.withdraw() by root.iconify(), the window is correctly re-sized but, surprisingly, isn't deiconified at the end !!!
I'm a little bit lost on this ...

Using root.winfo_reqwidth instead of root.winfo_width may help in your case.

Finally with the input of kalgasnik, I have a working code
# main window
root = tk.Tk()
# hide the main window during time we insert widgets
root.withdraw()
root.title('My application')
# create the objects in the main window with .grid()
w = buildWidgetClass(root)
# size of the screen (monitor resolution)
screenWi = root.winfo_screenwidth()
screenHe = root.winfo_screenheight()
# now that widgets are created, find the width and the height
root.update()
# retrieve the requested size which is different as the current size
guiWi = root.winfo_reqwidth()
guiHe = root.winfo_reqheight()
# position of the window
x = (screenWi - guiWi) / 2
y = (screenHe - guiHe) / 2
root.geometry("%dx%d+%d+%d" % (guiWi, guiHe, x, y))
# restore the window
root.deiconify()
Thanks a lot to both of you for your time and your help

Related

Way to set a singled dimension of the root window using python - tkinter?

I'm looking to have a window occupy the width of the screen but not (yet) the height of the screen. I have the root established and working but as far as I can tell the geometry method requires at least a width AND height, not one or the other individually. I would like the window to continue to scale dynamically in height as widgets are added/taken away. There is a starting height of the notebook tab and button
Without the rest of the code for the ReaderUI class shown below, this is what the main method looks like so far...
def main():
root=Tk()
tab_control = ttk.Notebook(root)
first_tab = ttk.Frame(tab_control)
tab_control.add(tab1,text="File 1")
tab_control.pack(expand=1,fill="both")
new_tab_button = Button(tab,text="create new tab", command = lambda: new_tab(tab_control))
new_tab_button.pack(padx = 5, pady = 5)
newUI = ReaderUI(tab1)
width=root.winfo_screenwidth()
height = root.winfo_screenheight()
root.geometry("{}x{}+0+0".format(width,height)
root.resizable(False,False)
root.mainloop()
My question boils down to this: is there a way to have the UI build itself in terms of height (as it would without the geometry method in place) and only establish a width as wide as the screen? Potentially a modification to the line
root.geometry("{}x{}+0+0".format(width,height))
so that height is left unset and free to move.
you can use
winfo_screenwidth
- Returns a decimal string giving the width of window's screen, in pixels.
Code
root.winfo_screenwidth()
root being your Tk() instance
then you can lock the x axis by using
root.resizable(False, True) # (X,Y)
Recourse
https://www.astro.princeton.edu/~rhl/Tcl-Tk_docs/tk8.0a1/winfo.n.html

Python with tkinter aspect ratio issue

I am attempting to create a simple window that maintains a square shape when resized, using python 3.6.4 and tkinter 8.6. Here is my code that produces a window, but does not maintain its aspect ratio when resized.
import tkinter as tk
w = tk.Tk()
w.aspect(1,1,1,1)
w.mainloop()
maybe you can use a canvas to make that, he detect event (image size changed) and .place relative x and relative y. I tryed make a script to help you, but you need make somes changes
from tkinter import *
# create a canvas with no internal border
canvas = Canvas(bd=0, highlightthickness=0)
canvas.pack(fill=BOTH, expand=1)
lastw, lasth = canvas.winfo_width(), canvas.winfo_height()
# track changes to the canvas size and draw
# a rectangle which fills the visible part of
# the canvas
def configure(event):
global lastw, lasth
canvas.delete("all")
w, h = event.width, event.height
try:
label.config(font = ('Arial ', int(12 * ((w - lastw) / (h - lasth))))) # -- this formula need change :3
except ZeroDivisionError: pass
lastw, lasth = canvas.winfo_width(), canvas.winfo_height()
canvas.bind("<Configure>", configure)
label = Label(canvas, text = "YOLO")
label.place(relx = 0.5, rely = 0.5) # - this make the widget automatic change her pos
mainloop()
you can see how this work here http://effbot.org/zone/tkinter-window-size.htm

Tkinter recursive behavior with '<Configure>' callback

I try to have a tkinter.Frame that have a full screen image and some buttons underneath it
WIDTH, HEIGHT = 800, 600
root = Tk()
mainframe = Frame(root, padding="3 3 12 12")
mainframe.pack(fill=BOTH, expand=True)
infovariable = StringVar()
infovariable_label = Label(mainframe, textvariable=infovariable, anchor=S)
infovariable_label.pack(fill=X, side=TOP)
label = Label(mainframe)
label.pack(fill=BOTH, expand=True)
image_base = Image.open('hello.jpg')
# setting the photo
image = (image_base
.resize(2500, 1000)
.crop(0, 0, WIDTH,HEIGHT))
label.configure(image=photo)
When I do a window resize, I want my photo to be the same dimensions (width/height), if I do that:
def onResize(event):
global WIDTH, HEIGHT
WIDTH = event.width
HEIGHT = max(0, event.height - 50)
# setting the photo
image = (image_base
.resize(2500, 1000)
.crop(0, 0, WIDTH,HEIGHT))
root.bind('<Configure>', onResize)
The resize, makes the image change size, then call the resize again, having a window that infinitely resizes.
I have the same problem as this thread:
odd behavior with '<Configure>' callback
When you bind to the root window, that binding applies to every child of the root window, too, due to how tkinter uses binding tags.
Part of the solution is to change your onResize to only change the size of the image if the event.widget represents the root window. There may be other problems, but that's the first.
You also need to make sure you account for borders. If you make the image the same size of the window, but the label has a one pixel border, that will cause the label to grow, which will cause the root window to grow, which will start the process all over again.
Another answer related to bind tags is here: https://stackoverflow.com/a/2472992/7432

Open Tkinter Window so it sits on start menu bar

I would like to have a Tkinter window open at the bottom right of the screen or where ever the start bar is. Much like when you click on the battery icon on your laptp and the box pops up. My code currently hides it behind the start menu bar. I would essentially like it at the bottom right but sitting on top of the start menu bar. Also, not sure how to account for things if the start menu is not at the bottom.
My Code:
from Tkinter import *
def bottom_right(w=300, h=200):
# get screen width and height
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# calculate position x, y
x = (screen_width - w)
y = (screen_height-h)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
root = Tk()
bottom_right(500, 300)
root.mainloop()
You can use the win32api's .GetMonitorInfo() to find the 'working area' of the monitor, which is the area of the monitor without the taskbar. Then, seeing where the taskbar is, you can place the window in a corner of the working area. See this example:
import win32api
import Tkinter as tk
for monitor in win32api.EnumDisplayMonitors():
monitor_info = win32api.GetMonitorInfo(monitor[0])
if monitor_info['Flags'] == 1:
break
work_area = monitor_info['Work']
total_area = monitor_info['Monitor']
width = 300
height = 200
side = [i for i in range(4) if work_area[i]!=total_area[i]]
# Left
if side ==[0]:
x = str(work_area[0])
y = str(work_area[3]-height)
# Top
elif side == [1]:
x = str(work_area[2]-width)
y = str(work_area[1])
# Right
elif side == [2]:
x = str(work_area[2]-width)
y = str(work_area[3]-height)
# Bottom
elif side == [3]:
x = str(work_area[2]-width)
y = str(work_area[3]-height)
else:
x = str(work_area[2]-width)
y = str(work_area[3]-height)
geom = '{}x{}+{}+{}'.format(width, height, x, y)
root = tk.Tk()
root.configure(background='red')
root.geometry(geom)
root.overrideredirect(True)
root.mainloop()
Note that I've used overrideredirect to get rid of the frame of the window, since this messes with the placing a bit.
What you are calling the 'start menu bar' is usually called the taskbar, at least on Windows. root.iconify() minimizes the root window to the taskbar, wherever it happens to be, just as when one clicks [_] in the upper right of the window. Clicking on the icon de_iconifies it, just as with any other app.
root = tk.Tk()
root.iconify()
<build gui>
root.deiconify()
root.mainloop()
is a common pattern in a polished app when the part takes long enough to cause potentially visible construction activity. I believe putting the gui in a frame and packing the frame as the last step has the same effect (of hiding construction).

How to center a tkinter window and retain the "fit to children" behavior?

I have a window whose content changes. Sometimes the content is larger than the window, so the window expands to fit it's children. However, when I center a window using a call to "geometry", the window no longer resizes. Below, you will find code that illustrates this.
If you comment out the delayed center() function call, you'll notice that the window expands to fit its content. If you leave it as is, the window centers, but no longer expands to fit its content.
Is it possible to center a window AND have it continue to resize to fit its content?
from Tkinter import *
import ttk
def center(root):
w = root.winfo_screenwidth()
h = root.winfo_screenheight()
rootsize = tuple(int(_) for _ in root.geometry().split('+')[0].split('x'))
x = w/2 - rootsize[0]/2
y = h/2 - rootsize[1]/2
root.geometry("%dx%d+%d+%d" % (rootsize + (x, y)))
root = Tk()
var = StringVar()
var.set('Small Text')
label = ttk.Label(root, textvariable=var)
label.grid(column=0, row=0)
# Change the text label in a couple of seconds.
def changeit():
var.set('BIG TXT - ' * 5)
root.after(2000, changeit)
# Comment out this center call and the label expands.
root.after(100, lambda: center(root))
root.mainloop()
When you call the geometry command, don't provide a width and height -- just supply the x/y values. When you give it an explicit width and height, you're telling Tk "I want the window to be exactly this size" so it turns it's auto-resize behavior off.
root.geometry("+%d+%d" % (rootsize + (x, y)))
Also, you can use winfo_width() and winfo_height() to get the actual size of the window, instead of parsing the output of the geometry method.

Categories

Resources