9

I'm trying to figure out how to get the height of a tkInter window title bar but can't seem to find any info on how it's done.

I have tried using root.geometry() and it seems that root.geometry() only returns the size of the window content and not the total size of the window with title bar and border sizes. I have seen other people say that you need to ask the OS for those things. I was hoping to avoid this because it will make it harder to make the code platform independent. There must be a way to do this without going to the OS for this. Anyone know what it is I must do to get this info?

My system:

OS: Linux

KDE Plasma: 5.16.4

KDE Frameworks: 5.61.0


import tkinter

root = tkinter.Tk()
root.geometry("250x250+100+100")
root.update_idletasks()

print('root.winfo_x() = ', root.winfo_x())
print('root.winfo_y() = ', root.winfo_y())
print('root.geometry() = ', root.geometry())

root.mainloop()

Test code results:

    root.winfo_x() =  100
    root.winfo_y() =  100
    root.geometry() =  250x250+100+100

The height of the window when measured with a screen ruler app is:

x=102, y=286
SF12 Study
  • 375
  • 4
  • 18
Daniel Huckson
  • 1,157
  • 1
  • 13
  • 35
  • I can't find anything in that post that gets me the true width and height of a window. I need the width and height of window decorations ie (title bar, border widths) and it's content. Once I have the outer size of the window I can calculate the rest. – Daniel Huckson Sep 01 '19 at 14:43
  • 1
    Possible duplicate of [Python tk window get x, y, geometry/coordinates without top of window](https://stackoverflow.com/questions/13424598/python-tk-window-get-x-y-geometry-coordinates-without-top-of-window). Verfied, returns `(0, 22)` which ist **the height of the titelbar**. [Edit] your question and show your attemp. – stovfl Sep 01 '19 at 15:29
  • 1
    My results `(101, 122)`, so it may depend from the used `OS Window Manager`. I use Linux LXDE. – stovfl Sep 01 '19 at 15:58
  • I have tested the code above on Linux KDE 5.61.0 and on Windows 10, both give the same results as noted above. – Daniel Huckson Sep 01 '19 at 18:17
  • My bad, sould be 'frame.winfo_geometry()`, `frame.winfo_rootx()`, `frame.winfo_rooty()` – stovfl Sep 01 '19 at 19:03
  • frame.winfo_geometry() gives me 250x250+0+0 the same thing! – Daniel Huckson Sep 01 '19 at 19:43
  • Such things are controlled by your system's window manager, and while `tkinter` provides a littlebit interaction with it, like icon or title, unfortunately, geometry isn't a case. For example, on window system you can use [GetSystemMetrics(SM_CYCAPTION)](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics) for your task. Another direction could be [detecting a geometry](https://unix.stackexchange.com/questions/504415/read-x-window-property-of-non-client-area) of both client and non-client area of your window and do math. – CommonSense Sep 05 '19 at 08:18
  • So, in bitter end, "other people" are right! But, after all, under the hood of `tkinter` a window decoration is platform dependent. Thus, you or someone else will add these dependencies one way or another. Don't run away from it. – CommonSense Sep 05 '19 at 08:30

3 Answers3

8

Title bar(default) is a system setting.As far as I know,it depends on many factors.(System zoom ratio,different OS,DPI awareness and so on).

In windows,change the zoom ratio will get different value of height.


About the question: tkinter will be recognized a old software in windows,you need to set DPI awareness to make it have the system normal height(fit the system zoom ratio if your system zoom ratio is not 100%).

Normally,the height of system title bar are same:but some exception(I am not really know about winapi),different DPI awareness will show you the different height of title bar: enter image description here The same: enter image description here

To make them same and get the normal height of title bar:

import tkinter
import ctypes

ctypes.windll.shcore.SetProcessDpiAwareness(2)
print(ctypes.windll.user32.GetSystemMetrics(4))
root = tkinter.Tk()

root.mainloop()

Result: enter image description here enter image description here

Refer: MSDN doc:GetSystemMetrics,DPI awareness(value of DPI awareness).

jizhihaoSAMA
  • 12,336
  • 9
  • 27
  • 49
3

I have figured this out finally. In order to get the height of the title bar I first added a frame to the window and set the window geometry('1x1'). I also had to use update_idletasks() to update tkinter internal data. After doing this I got the correct height. Seems strange to have to do it this way but it worked. Below is the code I used to get the height. Tested and works in Windows and Linux. If anyone knows of a more correct way to do this I would sure like to know. Also if anyone is using apple please let me know if the code below works.

UPDATE: I have updated the code and it's been tested in (Linux, Windows and MacOS) to give the correct title bar height. I think this is the best way to do this because you don't need to make OS dependent system calls.But I don't know whether it could work for any zoom level.


Update:now could work for any zoom level.(Test passed in windows 10,windows 7)

import tkinter as tk
from sys import platform


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        tk.Frame(self).update_idletasks()
        self.geometry('350x200+100+100')
        self.update_idletasks()

        offset_y = 0
        if platform in ('win32', 'darwin'):
            import ctypes
            try: # >= win 8.1
                ctypes.windll.shcore.SetProcessDpiAwareness(2)
            except: # win 8.0 or less
                ctypes.windll.user32.SetProcessDPIAware()
            offset_y = int(self.geometry().rsplit('+', 1)[-1])

        bar_height = self.winfo_rooty() - offset_y
        print(f'Height: {bar_height}\nPlatform: {platform}')
        #  self.destroy()


def main():
    app = App()
    app.mainloop()


if __name__ == '__main__':
    main()
jizhihaoSAMA
  • 12,336
  • 9
  • 27
  • 49
Daniel Huckson
  • 1,157
  • 1
  • 13
  • 35
  • Are you sure it is the height of the title bar?It seems it is the distance between widget's upper edge and screen upper edge....If you use `self.geometry('1x1+100+1000')`, see the result,it will be `Height=1031` in my PC. – jizhihaoSAMA Apr 29 '20 at 06:37
  • And I gotta to say,the method to get the height of title bar should be different in the different OS.In windows,you could use `winapi` to get it. – jizhihaoSAMA Apr 29 '20 at 07:14
  • @jizhihaoSAMA, I have corrected the code above to include the window offset so now it works the way it should. This should also work no matter what zoom level you use or OS. I prefer not to use OS dependent system calls. Thank you for your response I will stick to using what I have unless there is some reason not to, it works fine for me!. – Daniel Huckson Apr 29 '20 at 14:11
  • Yes, your idea is also correct if there is 100% zoom level,you could just set `DPI awareness` just for windows,you could use some code to judge the platform.That's also could work on both linux and windows. – jizhihaoSAMA Apr 29 '20 at 14:56
  • 2
    I have tested the code on macOS and it gives the right titlebar height. – j_4321 Apr 30 '20 at 08:18
  • @ j_4321, Thank you for taking the time to test the code for me, much appreciated. – Daniel Huckson Apr 30 '20 at 11:21
0

Simpler way is just testing how self.winfo_y() changes after setting geometry first time and then correct for this change.

Nard
  • 119
  • 8