一个完美的方案,必须是程序的尺寸能和DPI对应上,而且画面不模糊。
如果你的程序是结合OpenGL程序的,你需要小心,如果OpenGL是在Qt程序里面写的话,可能不会有太大的问题,但是如果OpenGL功能是由别人提供的,像自己封装成一个库,那么意味着你可能需要在一些方面要乘以那个缩放倍数,才能得到正确的OpenGL窗体大小和显示位置。多做一些测试来验证下是否存在这样的问题。
将你的Qt版本升级到Qt 6.3以上, Qt 6对于DPI有了很好的改善,如果是windows平台,你不需要做额外的动作,要做的就是看项目在Qt 6能不能成功编译。如果无法改变Qt版本,或者使用Qt 6编译不过,可以尝试下面的方法。
这个方案是针对windows的,当然Linux和Mac也是一样的思路,本质就是要得到缩放的倍数,然后设置环境变量。支持的版本应该是>= Qt 5.6,如果我没记错的话,支持QT_SCALE_FACTOR就行。
#include "mainwindow.h"
#include
#include
#include
#include
#include
#include
#include
double calculateScaleFactor()
{
auto activeWindow = GetActiveWindow();
HMONITOR monitor = MonitorFromWindow(activeWindow, MONITOR_DEFAULTTONEAREST);
// Get the logical width and height of the monitor
MONITORINFOEX monitorInfoEx;
monitorInfoEx.cbSize = sizeof(monitorInfoEx);
GetMonitorInfo(monitor, &monitorInfoEx);
auto cxLogical = monitorInfoEx.rcMonitor.right - monitorInfoEx.rcMonitor.left;
auto cyLogical = monitorInfoEx.rcMonitor.bottom - monitorInfoEx.rcMonitor.top;
// Get the physical width and height of the monitor
DEVMODE devMode;
devMode.dmSize = sizeof(devMode);
devMode.dmDriverExtra = 0;
EnumDisplaySettings(monitorInfoEx.szDevice, ENUM_CURRENT_SETTINGS, &devMode);
auto cxPhysical = devMode.dmPelsWidth;
auto cyPhysical = devMode.dmPelsHeight;
// Calculate the scaling factor
double horizontalScale = ((double)cxPhysical / (double)cxLogical);
double verticalScale = ((double)cyPhysical / (double)cyLogical);
std::cout << "Horizonzal scaling: " << horizontalScale << "\n";
std::cout << "Vertical scaling: " << verticalScale;
return horizontalScale > verticalScale ? verticalScale : horizontalScale;
}
int main(int argc, char *argv[])
{
double scaleFactor = calculateScaleFactor();
// enable QIcon produces highdpi pixmap
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
qputenv("QT_SCALE_FACTOR", QByteArray::number(scaleFactor));
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
为了更好的支持DPI,我们应该在项目使用矢量图,比如svg图片,这样可以确保我们在任何DPI都能显示正确,而且不模糊。我们使用AA_UseHighDpiPixmaps和QIcon的结合的方式,来获取正确的缩放的图片。下面是一些我对svg图片测试的总结