6
votes

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?

2
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.anderswb
@anderswb 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)Hubro
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.anderswb
@anderswb Thanks for the link, I'll consider thatHubro
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.anderswb

2 Answers

6
votes

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.

0
votes

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.