У нас есть настольное приложение, которое использует Qt 4.8.
Мы пытаемся поддерживать различные экраны DPI, такие как Mac Retina, Surface Pro 4.
Для Mac мы можем получить соотношение пикселей устройства только одним вызовом функции:
CGFloat devicePixelRatio = [[NSScreen mainScreen] backingScaleFactor];
Есть ли какая-либо полезная функция в WinAPI для получения соотношения пикселей устройства?
Благодарю.
Наконец, я нашел решение использовать приведенный ниже фрагмент кода, чтобы получить коэффициент масштабирования,
FLOAT dpiX, dpiY;
HDC screen = GetDC(0);
dpiX = static_cast<FLOAT>(GetDeviceCaps(screen, LOGPIXELSX));
dpiY = static_cast<FLOAT>(GetDeviceCaps(screen, LOGPIXELSY));
ReleaseDC(0, screen);
FLOAT scaleFactor = dpiX / 96.0f; // this is same as devicePixelRatio
Теперь нужно сделать так, чтобы ваше приложение знало о DPI. Для этого набора Включить DPI DPI флаг для да в Настройки проекта> Инструмент манифеста> Ввод и вывод страница свойств.
Вот как я рассчитываю DPI.
Замените утверждения фактической проверкой ошибок, так как некоторые из этих ситуаций иногда случаются.
#include <QString>
#include <Windows.h>
#include <SetupApi.h>
#include <cfgmgr32.h>
#include <assert.h>
#include <vector>
#include <stdint.h>
const GUID GUID_CLASS_MONITOR = { 0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 };
// Assumes hEDIDRegKey is valid
bool GetMonitorSizeFromEDID(const HKEY hEDIDRegKey, short& WidthMm, short& HeightMm)
{
DWORD dwType, AcutalValueNameLength = 128;
TCHAR valueName[128];
BYTE EDIDdata[1024];
DWORD edidsize = sizeof(EDIDdata);
for (LONG i = 0, retValue = ERROR_SUCCESS; retValue != ERROR_NO_MORE_ITEMS; ++i)
{
retValue = RegEnumValue(hEDIDRegKey, i, &valueName[0],
&AcutalValueNameLength, NULL, &dwType,
EDIDdata, // buffer
&edidsize); // buffer size
if (retValue != ERROR_SUCCESS || QString(valueName) != "EDID")
continue;
WidthMm = ((EDIDdata[68] & 0xF0) << 4) + EDIDdata[66];
HeightMm = ((EDIDdata[68] & 0x0F) << 8) + EDIDdata[67];
return true; // valid EDID found
}
return false; // EDID not found
}
bool GetSizeForDevID(const QString& TargetDevID, short& WidthMm, short& HeightMm)
{
HDEVINFO devInfo = SetupDiGetClassDevsExA(
&GUID_CLASS_MONITOR, //class GUID
NULL, //enumerator
NULL, //HWND
DIGCF_PRESENT | DIGCF_PROFILE, // Flags //DIGCF_ALLCLASSES|
NULL, // device info, create a new one.
NULL, // machine name, local machine
NULL);// reserved
if (NULL == devInfo)
return false;
bool success = false;
for (ULONG i = 0; ERROR_NO_MORE_ITEMS != GetLastError(); ++i)
{
SP_DEVINFO_DATA devInfoData;
memset(&devInfoData, 0, sizeof(devInfoData));
devInfoData.cbSize = sizeof(devInfoData);
if (SetupDiEnumDeviceInfo(devInfo, i, &devInfoData))
{
CHAR Instance[MAX_DEVICE_ID_LEN];
SetupDiGetDeviceInstanceIdA(devInfo, &devInfoData, Instance, MAX_DEVICE_ID_LEN, NULL);
if (!QString(Instance).contains(TargetDevID))
continue;
HKEY hEDIDRegKey = SetupDiOpenDevRegKey(devInfo, &devInfoData,
DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (!hEDIDRegKey || (hEDIDRegKey == INVALID_HANDLE_VALUE))
continue;
success = GetMonitorSizeFromEDID(hEDIDRegKey, WidthMm, HeightMm);
RegCloseKey(hEDIDRegKey);
if (success)
break;
}
}
SetupDiDestroyDeviceInfoList(devInfo);
return success;
}
static bool DisplayDeviceFromHMonitor(HMONITOR hMonitor, DISPLAY_DEVICE& ddMonOut)
{
MONITORINFOEX mi;
mi.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfoA(hMonitor, &mi);
DISPLAY_DEVICE dd;
dd.cb = sizeof(dd);
for (DWORD devIdx = 0; EnumDisplayDevicesA(nullptr, devIdx, &dd, 0); ++devIdx)
{
if (QString(dd.DeviceName) != QString(mi.szDevice))
continue;
DISPLAY_DEVICE ddMon;
memset(&ddMon, 0, sizeof(ddMon));
ddMon.cb = sizeof(ddMon);
if (EnumDisplayDevicesA(dd.DeviceName, 0, &ddMon, 0))
{
ddMonOut = ddMon;
return true;
}
memset(&dd, 0, sizeof(dd));
dd.cb = sizeof(dd);
}
return false;
}
BOOL CALLBACK MonitorEnumProc(
_In_ HMONITOR hMonitor,
_In_ HDC /*hdcMonitor*/,
_In_ LPRECT /*lprcMonitor*/,
_In_ LPARAM context
)
{
std::vector<HMONITOR> * monitors = (std::vector<HMONITOR>*)context;
assert(monitors);
monitors->push_back(hMonitor);
return TRUE;
}
uint32_t CSystemMetrics::screenDpi(void* window, const CRect& rect)
{
// Identify the HMONITOR of interest via the callback MyMonitorEnumProc
HDC dc = GetWindowDC((HWND)window);
assert(dc);
RECT windowRect;
windowRect.top = rect.top;
windowRect.left = rect.left;
windowRect.right = rect.right;
windowRect.bottom = rect.bottom;
std::vector<HMONITOR> monitors;
EnumDisplayMonitors(dc, rect.size().area() > 0 ? (&windowRect) : nullptr, MonitorEnumProc, (LPARAM)&monitors);
ReleaseDC((HWND)window, dc);
assert(!monitors.empty());
DISPLAY_DEVICE ddMon;
assert(DisplayDeviceFromHMonitor(monitors.front(), ddMon));
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
assert(GetMonitorInfoA(monitors.front(), &monitorInfo));
const auto deviceIdSections = QString(ddMon.DeviceID).split("\\");
assert(deviceIdSections.size() > 1);
short widthMm, heightMm;
assert(GetSizeForDevID(deviceIdSections[1], widthMm, heightMm));
const float hDPI = (monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left) * 25.4f / widthMm;
const float vDPI = (monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top) * 25.4f / heightMm;
const uint32_t dpi = uint32_t(((float)hDPI + (float)vDPI / 2.0f) + 0.5f);
assert(dpi < 700 && widthMm > 100 && heightMm > 100);
return dpi;
}
Теперь есть сложная проблема, замаскированная в простом вопросе 🙂 Я не могу ответить на этот вопрос, но просто дать некоторые незначительные подсказки:
Во-первых, в Windows нет парадигмы «устройство-пиксель против логики-пикселя», известной из OSX, поэтому ваш вопрос об «соотношении пикселей устройства» может вызвать раздражение у не-OSX-разработчиков.
Для Qt произошли некоторые существенные изменения с версий 4.x до 5.x. На самом деле, вы можете подумать об обновлении до Qt 5.
http://doc.qt.io/qt-5/highdpi.html
Цитировать по этой ссылке:
«В Qt 5.4 представлена экспериментальная поддержка масштабирования по соотношению пикселей устройства, аналогичного OS X, для плагинов платформы для Windows и Unix (XCB)».
Qt 4, с другой стороны, предлагает только те советы для «масштабируемых приложений»:
http://doc.qt.io/qt-4.8/scalability.html
Связанный ТАК вопрос:
Автоматическое изменение масштаба приложения на платформе Windows с высоким разрешением?