Qt 6.5在Windows 10下高DPI导致QPixmap缩放异常的解决方法
解决Qt 6.5在Windows 10高DPI下QPixmap缩放异常问题
在Windows 10系统上使用Qt 6.5开发应用时,发现QPixmap会随系统DPI缩放比例出现异常缩放情况,具体表现为不同缩放比例下图片形状、尺寸显示不一致。
最小复现示例
- Windows缩放比例100%时:

- 缩放比例125%时:

- 缩放比例150%时:

复现代码如下:
class Label : public QLabel { Q_OBJECT public: QIcon icon; Label(QWidget* parent = nullptr) : QLabel(parent){} void paintEvent(QPaintEvent* event) override { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); icon.paint(&painter, rect(), Qt::AlignCenter, QIcon::Normal, QIcon::On); } }; inline QPixmap setRoundness(QPixmap pixmap, int roundness) { QPainterPath path; qDebug() << pixmap.width() << pixmap.height(); // Round the pixmap by 50% path.addRoundedRect(QRectF(0, 0, pixmap.width(), pixmap.height()), pixmap.width() / 2, pixmap.height() / 2); QPixmap roundedPixmap = QPixmap(pixmap.size()); roundedPixmap.fill(Qt::transparent); QPainter painter(&roundedPixmap); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.fillPath(path, Qt::black); painter.setCompositionMode(QPainter::CompositionMode_SourceIn); painter.drawPixmap(0, 0, pixmap); pixmap.save("test_1.png"); roundedPixmap.save("test_2.png"); return roundedPixmap; } class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr) : QMainWindow(parent), ui(new Ui::MainWindowClass()) { ui->setupUi(this); setStyleSheet("#centralWidget { background-color: rgba(80, 80, 80, 80); }"); QIcon icon = QIcon("C:/Users/Katia/test.png"); // 原始为标准方形图片 QPixmap roundedPixmap = setRoundness(icon.pixmap(QSize(55, 55)), 50); Label* label = new Label; label->icon = roundedPixmap; QLabel* label_2 = new QLabel; label_2->setPixmap(roundedPixmap); QWidget* widget = new QWidget; QHBoxLayout* hLayout = new QHBoxLayout(widget); hLayout->addWidget(label); hLayout->addWidget(label_2); hLayout->setContentsMargins(0, 0, 0, 0); hLayout->setSpacing(30); setCentralWidget(widget); setContentsMargins(32, 32, 32, 32); return; } }
问题根源确认
问题出在QPixmap环节而非QPaintEvent,因为将roundedPixmap保存为test_2.png时,不同DPI下的输出结果存在明显差异:
- DPI 150%时的保存结果:

- DPI 100%时的保存结果:

解决方案
1. 启用Qt高DPI缩放支持
在应用启动代码中添加以下配置,确保Qt正确识别并处理高DPI环境:
#include <QApplication> #include <QGuiApplication> int main(int argc, char *argv[]) { // 启用全局高DPI缩放 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // 启用高DPI图片自动缩放支持 QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
2. 基于设备像素比计算图片尺寸
调用icon.pixmap()时,不要直接传入固定像素值,而是根据当前屏幕的设备像素比(DPR)计算实际像素尺寸,确保图片有足够分辨率适配高DPI:
// 获取主屏幕的设备像素比 qreal dpr = QGuiApplication::primaryScreen()->devicePixelRatio(); // 目标显示尺寸为55x55设备无关像素,计算实际需要的像素尺寸 QSize pixmapSize(qRound(55 * dpr), qRound(55 * dpr)); QPixmap roundedPixmap = setRoundness(icon.pixmap(pixmapSize), 50); // 为处理后的图片设置设备像素比,让Qt正确识别缩放比例 roundedPixmap.setDevicePixelRatio(dpr);
3. 优化圆角绘制逻辑
在setRoundness函数中,使用浮点运算避免整数截断误差,同时继承原图片的设备像素比:
inline QPixmap setRoundness(QPixmap pixmap, int roundness) { QPainterPath path; qreal width = pixmap.width(); qreal height = pixmap.height(); qDebug() << width << height; // 用浮点值计算圆角半径,避免整数除法导致的形状偏差 path.addRoundedRect(QRectF(0, 0, width, height), width / 2.0, height / 2.0); QPixmap roundedPixmap = QPixmap(pixmap.size()); roundedPixmap.fill(Qt::transparent); QPainter painter(&roundedPixmap); painter.setRenderHint(QPainter::Antialiasing, true); painter.setRenderHint(QPainter::SmoothPixmapTransform); painter.fillPath(path, Qt::black); painter.setCompositionMode(QPainter::CompositionMode_SourceIn); painter.drawPixmap(0, 0, pixmap); pixmap.save("test_1.png"); roundedPixmap.save("test_2.png"); // 继承原图片的设备像素比 roundedPixmap.setDevicePixelRatio(pixmap.devicePixelRatio()); return roundedPixmap; }
4. 简化自定义Label绘制逻辑
如果无需复杂自定义绘制,直接使用原生QLabel即可——原生QLabel会自动处理带有正确DPR的QPixmap缩放。若必须自定义绘制,需在paintEvent中考虑当前设备的DPR:
void paintEvent(QPaintEvent* event) override { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::SmoothPixmapTransform); // 获取当前绘制设备的DPR qreal dpr = painter.device()->devicePixelRatio(); // 调整绘制区域或图片尺寸适配DPR QRect adjustedRect = rect() * dpr; icon.paint(&painter, adjustedRect, Qt::AlignCenter, QIcon::Normal, QIcon::On); }
内容的提问来源于stack exchange,提问作者Jabu
相关产品推荐
相关产品推荐

