Windows: получение высоты строки заголовка окна - PullRequest
4 голосов
/ 11 июня 2019

Я пытался получить высоту строки заголовка определенного окна на Windows. Вы можете скопировать его с Notepad. Я использую C++, и ни один из кодов, которые я нашел в Интернете, не дал правильного результата. Используя, например, Screenpresso Я измерил 31 пикселей для высоты моей оконной панели.

Я попробовал следующие функции:

TitleBarHeight.h:

#pragma once

#include <windows.h>

inline int get_title_bar_thickness_1(const HWND window_handle)
{
    RECT window_rectangle, client_rectangle;
    GetWindowRect(window_handle, &window_rectangle);
    GetClientRect(window_handle, &client_rectangle);
    return window_rectangle.bottom - window_rectangle.top -
        (client_rectangle.bottom - client_rectangle.top);
}

inline int get_title_bar_thickness_2(const HWND window_handle)
{
    RECT window_rectangle, client_rectangle;
    GetWindowRect(window_handle, &window_rectangle);
    GetClientRect(window_handle, &client_rectangle);
    return (window_rectangle.right - window_rectangle.left - client_rectangle.right) / 2;
}

Результаты:

auto window_handle = FindWindow("Notepad", nullptr);
auto a = get_title_bar_thickness_1(window_handle); // 59
auto b = get_title_bar_thickness_2(window_handle); // 8
auto c = GetSystemMetrics(SM_CXSIZEFRAME); // 4
auto d = GetSystemMetrics(SM_CYCAPTION); // 23

Получение системных показателей с помощью GetSystemMetrics() не работает, поскольку окна могут иметь разную высоту заголовка, и аргумент для дескриптора окна отсутствует.

Как я могу действительно получить результат 31?

Ответы [ 4 ]

2 голосов
/ 16 июня 2019

Предполагая, что у вас нет строки меню, вы можете отобразить точки из клиентской системы координат на один экран

RECT wrect;
GetWindowRect( hwnd, &wrect );
RECT crect;
GetClientRect( hwnd, &crect );
POINT lefttop = { crect.left, crect.top }; // Practicaly both are 0
ClientToScreen( hwnd, &lefttop );
POINT rightbottom = { crect.right, crect.bottom };
ClientToScreen( hwnd, &rightbottom );

int left_border = lefttop.x - wrect.left; // Windows 10: includes transparent part
int right_border = wrect.right - rightbottom.x; // As above
int bottom_border = wrect.bottom - rightbottom.y; // As above
int top_border_with_title_bar = lefttop.y - wrect.top; // There is no transparent part

Получили 8, 8, 8 и 31 пиксель (96DPI или 100% масштабирование)

Следует также учитывать режим осведомленности о DPI.Особенно GetSystemMetrics сложно, потому что он запоминает состояние для DPI системы при запуске вашего приложения.

1 голос
/ 11 июня 2019

Во-первых, убедитесь, что ваше приложение поддерживает высокий уровень DPI, чтобы система не лгала вам.

Опции:

  1. Доверяйте GetSystemMetrics. Практически любое окно верхнего уровня, которое на самом деле имеет другой размер заголовка, выполняет настраиваемое управление не-клиентской областью, что сделает это (почти) невозможным. Очевидным исключением является окно инструментов (WS_EX_TOOLWINDOW), которое, вероятно, имеет высоту SM_CYSMCAPTION, если также установлен стиль WS_CAPTION.

  2. Получить прямоугольник целевого окна и стиль целевого окна. Используйте AdjustWindowRectEx, чтобы определить различия в размерах с переключенным стилем WS_CAPTION. Я не уверен, сработает ли это, потому что может быть какое-то взаимодействие между тем, можно ли иметь подпись без какой-либо границы.

  3. Получите прямоугольник целевого окна и отправьте сообщения WM_HITTEST для координат, которые перемещаются вниз по окну. Посчитайте, сколько из них получают HT_CAPTION взамен. Бонусные баллы, если вы делаете это с помощью бинарного поиска, а не линейного поиска. Это, вероятно, самый трудный и самый надежный способ сделать это, предполагая, что окно имеет прямоугольную область заголовка.

1 голос
/ 12 июня 2019

Отправьте сообщение WM_GETTITLEBARINFOEX в окно, и вы получите ограничительный прямоугольник строки заголовка.

TITLEBARINFOEX * ptinfo = (TITLEBARINFOEX *)malloc(sizeof(TITLEBARINFOEX));
ptinfo->cbSize = sizeof(TITLEBARINFOEX);
SendMessage(hWnd, WM_GETTITLEBARINFOEX,0, (LPARAM)ptinfo);
int height = ptinfo->rcTitleBar.bottom- ptinfo->rcTitleBar.top;
int width = ptinfo->rcTitleBar.right - ptinfo->rcTitleBar.left;
free(ptinfo);
1 голос
/ 11 июня 2019

Если я правильно понял, похоже, что вы хотите взять размер рамки окна (который мы должны быть в состоянии собрать из ширины, так как нет строки заголовка) и вычесть ее из размера вертикали минус окно клиента ...

inline int get_title_bar_thickness(const HWND window_handle)
{
    RECT window_rectangle, client_rectangle;
    int height, width;
    GetWindowRect(window_handle, &window_rectangle);
    GetClientRect(window_handle, &client_rectangle);
    height = (window_rectangle.bottom - window_rectangle.top) -
    (client_rectangle.bottom - client_rectangle.top);
    width = (window_rectangle.right - window_rectangle.left) - 
    (client_rectangle.right - client_rectangle.left);
    return height - (width/2);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...