Python/tkinter - How do I get the window size including borders on Windows?
Asked Answered
B

3

7

I'm trying to position my window based on with width and height of the window. On Windows, the window size reported by wm_geometry, winfo_width and winfo_height is the size of the client area, i.e. the window size without the borders. The position of the window, as reported by wm_geometry, winfo_x and winfo_y, and the position set using wm_geometry, is the position of the top left point of the window including the border.

This means that when I try to center the window on the screen, the position is visibly too low on the screen.

I don't want to hard-code the border thickness since it can vary.

Is it possible to get or infer the size of the window border on Windows using Python/tkinter?

Baumann answered 20/10, 2015 at 8:18 Comment(7)
There might be a better solution, but maybe you could hack something by maximizing the window using root.attributes('-fullscreen', True), getting the geometry of the frame and the screen resolution and then you should be able to calculate the size of the borders of the window (i think..). I'm not sure if you can do it without actually displaying it on the screen though.Suitcase
@Suitcase The thickness of the border is not the same when the window is maximized. The top border is visibly thinner and the left, right and bottom borders are gone. (This is on Windows 8)Baumann
Another idea. Again I haven't tried it, but i think you have to use some stuff from outside of tkinter. What about something like suggested here.Suitcase
@Suitcase Thanks for the link, I'll consider thatBaumann
I think it might be impossible to get the window size until it's displayed using that method though. Not sure if that's a problem.Suitcase
@Suitcase The window is already open, that's not a problem. I'm just trying to figure out the exact coordinates to move the window to in order to keep the center of the window at the same position after some content changes.Baumann
I see. You should definitly be able to do as i suggested. Seems hackish though - and not really OS independent.Suitcase
B
6

From http://wiki.tcl.tk/11291:

wm geometry . returns contentsWidthxcontentsHeight+decorationTop+decorationLeftEdge.

and winfo rooty . returns contentsTop and winfo rootx . returns contentsLeftEdge

From these you can calculate the title bar height and left border width (which generally matches the right and bottom border width). This should work on windows, but will not necessarily work on all platforms. As the linked page also examines, there are also issues in determining the total height and width of the screen area available due to the windows taskbar.

Bathsheb answered 20/10, 2015 at 19:27 Comment(1)
Wow, you're right! Even though I tested all these methods I didn't notice that rooty and rootx returned the position of the client rectangle. I'm now doing client_x - window_x and client_y - window_y to calculate the size of the border, and adding the size of the border to the client size to get the window size. Works like a charm!Baumann
I
1

Below you can use tkinter's geometry function to extract the coordinates of the tkinter gui.

geometry_info = root.geometry()
#geometry_info format: "widthxheight + x + y"
#convert into a list of individual coordinates
delimiters = 'x+'
position_info = re.split('[' + delimiters + ']', geometry_info)
Innutrition answered 17/11, 2023 at 16:46 Comment(1)
Six months later your first upvote :)Seabolt
S
0

As we discussed in the comments, I doubt you can do it using pure tkinter.

I've tried to implement a solution for getting the window size including the border using win32gui. From this information you should be able to implement the rest of the functionality. Unfortunatly this is only for Windows platforms and requires an installation on pywin32. You can get it here. I'm sure there's a Mac and Linux equivalent if that is a requirement.

This is my solution, tested in Python 3.4:

import tkinter as tk
import win32gui

class TestApp:
    def __init__(self, master):
        frame = tk.Frame(master)
        frame.pack()

        self.master = master

        label = tk.Label(text='Test Label')
        label.pack()
        b1 = tk.Button(text='test', command=self.pressed)
        b1.pack()

    def pressed(self):
        win32gui.EnumWindows(self.callback, None)
        x = root.winfo_x()
        y = root.winfo_y()
        w = self.master.winfo_width()
        h = self.master.winfo_height()
        print('tkinter location: ({},{})'.format(x, y))
        print('tkinter size: ({},{})'.format(w, h))


    def callback(self, hwnd, extra):
        if "Test title" in win32gui.GetWindowText(hwnd):
            rect = win32gui.GetWindowRect(hwnd)
            x = rect[0]
            y = rect[1]
            w = rect[2] - x
            h = rect[3] - y
            print('Window location: ({},{})'.format(x, y))
            print('Window size: ({},{})'.format(w, h))

root = tk.Tk()
root.title("Test title")
app = TestApp(root)
root.mainloop()

I'm win32gui.EnumWindows() to interate over all available windows to locate the one with the correct title. From this I can then get the size using win32gui.GetWindowRect().

I'll print the results from win32gui and tkinter to the console for comparison.

Suitcase answered 20/10, 2015 at 18:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.