Как получить соотношение пикселей устройства в Qt 4.8 для Windows?

У нас есть настольное приложение, которое использует Qt 4.8.
Мы пытаемся поддерживать различные экраны DPI, такие как Mac Retina, Surface Pro 4.
Для Mac мы можем получить соотношение пикселей устройства только одним вызовом функции:

CGFloat devicePixelRatio = [[NSScreen mainScreen] backingScaleFactor];

Есть ли какая-либо полезная функция в WinAPI для получения соотношения пикселей устройства?

Благодарю.

1

Решение

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

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 флаг для да в Настройки проекта> Инструмент манифеста> Ввод и вывод страница свойств.

1

Другие решения

Вот как я рассчитываю 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;
}
0

Теперь есть сложная проблема, замаскированная в простом вопросе 🙂 Я не могу ответить на этот вопрос, но просто дать некоторые незначительные подсказки:

Во-первых, в 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 с высоким разрешением?

0
По вопросам рекламы [email protected]