You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt 6.5在Windows 10下高DPI导致QPixmap缩放异常的解决方法

解决Qt 6.5在Windows 10高DPI下QPixmap缩放异常问题

在Windows 10系统上使用Qt 6.5开发应用时,发现QPixmap会随系统DPI缩放比例出现异常缩放情况,具体表现为不同缩放比例下图片形状、尺寸显示不一致。

最小复现示例

  • Windows缩放比例100%时:
    Windows缩放100%效果
  • 缩放比例125%时:
    Windows缩放125%效果
  • 缩放比例150%时:
    Windows缩放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 150%保存的图片
  • DPI 100%时的保存结果:
    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 03:18:10