Координаты устройства Windows и виртуальные координаты

Я пытался найти ответ на этот вопрос в MSDN, но у меня нет четкого представления о том, как это должно работать. Вся моя работа на Windows 8.1.

Вот моя проблема. Я работаю на ноутбуке с монитором высокого разрешения 3200x1800. Я использую EnumDisplayMonitors, чтобы получить ограничивающий прямоугольник моего экрана.

Кажется, это работает нормально, если мои настройки дисплея установлены по умолчанию. Но я заметил, что когда я изменяю настройки отображения окна, чтобы отображать текст большего размера, разрешение, возвращаемое EnumDisplayMonitor, изменяется. Вместо 3200х1800 я получу 2133х1200.

Я предполагаю, что, поскольку я попросил увеличить текст, Windows решила представить экран как меньшее разрешение.

Кажется, что если я смотрю в свойствах виртуального экрана, то все представлено в реальных координатах моего экрана, т.е. 3200x1800. Но API-интерфейсы для получения прямоугольников окна и монитора, похоже, работают с этим «другим» координатным пространством.

Есть ли какая-либо документация/Windows API для обработки преобразования между этими «другими координатами» и «виртуальными координатами»? то есть, если я хочу, чтобы EnumDisplayMonitor или GetMonitorInfo давали мне истинные координаты экрана, как мне преобразовать 2133x1200 в 3200x1800?


person anoneironaut    schedule 03.07.2014    source источник


Ответы (2)


Вы увеличили DPI видеоадаптера до 150% (144 точки на дюйм), чтобы сохранить читаемость текста и избежать появления окон размером с почтовую марку. Совершенно необходимо на дисплеях с таким высоким разрешением. Но вы не сказали Windows, что ваша программа знает, как с этим справиться.

Таким образом, предполагается, что ваша программа старая и никогда не предназначалась для работы на таких мониторах. Это помогает и лжет вам. Он заставляет вашу программу отображать свой вывод в буфер памяти, затем берет этот вывод, масштабирует его на 150% и копирует в видеоадаптер. Это то, что вы можете видеть: текст выглядит более размытым, если вы поместите вывод своей программы рядом с программой, которая не требует такого масштабирования, например Блокнот.

И, конечно же, он вам врет, когда вы спрашиваете размер экрана. Он говорит вам, что он на 150% меньше, чем есть на самом деле. Чтобы после изменения масштаба создаваемое вами окно занимало весь экран.

Это все хорошо, но, конечно, не идеально, ваша программа выглядит не так хорошо, как должна. Вы должны сообщить Windows, что вы знаете, как обращаться с более высоким разрешением. Имейте в виду, что это выглядит проще, чем на практике. Заставить текст выглядеть четким тривиально, проблематичны растровые изображения. И в целом плодотворный источник ошибок, даже крупные компании могут ошибаться.

person Hans Passant    schedule 03.07.2014
comment
Ах, это ответ, я думаю. Я был очень смущен, потому что DPI, который я получил от перечисления устройств монитора, всегда был одним и тем же, независимо от того, что я изменил. Но разрешение постоянно менялось. Похоже, Windows мне лжет. Итак, теперь для дополнительного вопроса: если я предпочитаю, чтобы DPI моего приложения был неизвестен на данный момент, как мне проще всего определить DPI? Есть ли способ его рассчитать? - person anoneironaut; 03.07.2014
comment
Если вам нравится, когда вам лгут, то вам все равно, что это может быть. Вы просто предполагаете 96 dpi. - person Hans Passant; 03.07.2014
comment
Но я хотел бы знать, какое реальное разрешение для различных мониторов и окон. Похоже, что все API-интерфейсы, которые Windows предоставляет для этого, будут работать, только если мое приложение поддерживает DPI. Поэтому мне интересно, могу ли я выполнять эти преобразования, не зная DPI. - person anoneironaut; 03.07.2014
comment
Отключение лжи требует объявления вашей программы dpiAware. Жесткое требование. - person Hans Passant; 03.07.2014
comment
Хм, хорошо, я заметил одну вещь: несмотря на то, что разрешение моего монитора было указано как 2133x1200, если я использую перечисление устройств, чтобы получить разрешение моего монитора, оно сообщает 3200x1800. Безопасно ли использовать эти данные для оценки DPI, чтобы я мог правильно настроить? - person anoneironaut; 03.07.2014
comment
Ничего не корректируйте, если он будет на 150% больше. - person Hans Passant; 03.07.2014
comment
Я не хочу настраивать рендеринг моего приложения. Я просто хочу иметь возможность получать физические координаты всех объектов (окна, мониторы и т. д.) на моем рабочем столе. Прямо сейчас я получаю ложь, но я предполагаю, что если я просто вычислю DPI и применю его ко всем координатам и точкам, я получу физические значения. - person anoneironaut; 03.07.2014

Прежде чем я начну с ответа, позвольте мне спросить: что вы на самом деле пытаетесь сделать? Или, более конкретно, зачем вам знать разрешение монитора? Стандартный способ сделать это — вызвать GetWindowRect(GetDesktopWindow(), &rect). Я не уверен, что координаты экрана меняются в зависимости от настроек DPI, но вы должны попробовать это вместо GetMonitorInfo, так как последний предназначен для более сложных вещей. И если GetWindowRect по-прежнему возвращает масштабированный прямоугольник, просто вызовите DPtoLP, LPtoDP или другая функция координат отображения по мере необходимости.

Когда вы настраиваете параметры дисплея, как вы описали, вы фактически меняете настройки DPI экрана. Таким образом, некоторые API-интерфейсы переходят в режим совместимости, позволяя приложению создавать более крупные элементы и окна, ничего не зная об этом параметре.

Зачем вам знать фактическое разрешение экрана, поскольку большинство оконных API будут вести себя соответствующим образом при изменении масштабирования DPI?

Я подозреваю, что вы могли бы вызвать SetProcessDPIAware или эквивалент файла манифеста. Но сначала прочтите эту статью MSDN. понять масштабирование DPI.

person selbie    schedule 03.07.2014