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

QPainter在QPixmap上绘制文本显示模糊问题求助

QPixmap绘制文本后显示模糊的原因与解决方法

问题描述

在QMainWindow的paintEvent中,直接绘制文本时显示效果清晰;但先将文本绘制到QPixmap,再复制到窗口时,文本(尤其是/字符)出现明显模糊。已启用QPainter::HighQualityAntialiasing渲染提示,且两种场景使用相同的窗口默认字体。

相关代码

mainwindow.hxx

#include "mainwindow.hxx"
#include "./ui_mainwindow.h"

#include <QPainter>
#include <QString>
#include <QStaticText>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    auto f = font();
    f.setPixelSize(70);
    setFont(f);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::paintEvent(QPaintEvent *event)
{
    {
    QPixmap img(width(), height());
    QPainter painter(&img);
    painter.setFont(font());
    painter.setBrush(Qt::black);
    painter.setPen(Qt::NoPen);
    painter.drawRect(rect());
    painter.setRenderHint(QPainter::HighQualityAntialiasing);


    painter.setPen(Qt::blue);
    painter.drawText(0, 80, "/// lorem ipsum dolor sit amet");
    // Create a QPainter to draw on the window
    QPainter painter2(this);
    painter2.setRenderHint(QPainter::HighQualityAntialiasing);
    painter2.drawPixmap(rect(), img);
    }

    {
    // Create a QPainter to draw on the window
    QPainter painter(this);
    painter.setFont(font());
    painter.setBrush(Qt::black);
    painter.setPen(Qt::NoPen);
    painter.setRenderHint(QPainter::HighQualityAntialiasing);

    painter.setPen(Qt::blue);
    painter.drawText(0, 300, "/// lorem ipsum dolor sit amet");
    }

}

main.cxx

#include "mainwindow.hxx"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget"/>
 </widget>
 <resources/>
 <connections/>
</ui>

原因分析

核心问题是设备像素比(Device Pixel Ratio, DPR)不匹配:

  • 直接绘制到窗口时,QPainter会自动适配系统的高DPI设置,使用窗口的设备像素比渲染文本,确保每个逻辑像素对应足够的物理像素,保证清晰度。
  • 手动创建QPixmap时,默认使用1.0的设备像素比。在高分辨率屏幕(DPR>1)下,QPixmap的实际物理像素尺寸远小于窗口的物理像素尺寸,后续将其绘制到窗口时会被拉伸放大,导致文本边缘模糊,细节丢失(比如/这类细线条字符)。
  • 仅启用抗锯齿无法解决该问题,因为抗锯齿是优化渲染过程的平滑度,无法弥补物理像素不足的根源。

解决方案

创建QPixmap时,需匹配窗口的设备像素比,确保QPixmap的物理像素尺寸足够:

修改后的paintEvent代码

void MainWindow::paintEvent(QPaintEvent *event)
{
    {
        // 获取窗口的设备像素比
        qreal dpr = devicePixelRatio();
        // 创建对应物理像素尺寸的QPixmap
        QPixmap img(width() * dpr, height() * dpr);
        // 设置QPixmap的设备像素比,与窗口保持一致
        img.setDevicePixelRatio(dpr);
        
        QPainter painter(&img);
        painter.setFont(font());
        painter.setBrush(Qt::black);
        painter.setPen(Qt::NoPen);
        // 绘制QPixmap自身的背景矩形(物理像素尺寸)
        painter.drawRect(img.rect());
        painter.setRenderHint(QPainter::HighQualityAntialiasing);

        painter.setPen(Qt::blue);
        // 用逻辑坐标绘制文本,QPainter会自动转换为物理像素
        painter.drawText(0, 80, "/// lorem ipsum dolor sit amet");
        
        QPainter painter2(this);
        painter2.setRenderHint(QPainter::HighQualityAntialiasing);
        painter2.drawPixmap(rect(), img);
    }

    {
        QPainter painter(this);
        painter.setFont(font());
        painter.setBrush(Qt::black);
        painter.setPen(Qt::NoPen);
        painter.setRenderHint(QPainter::HighQualityAntialiasing);

        painter.setPen(Qt::blue);
        painter.drawText(0, 300, "/// lorem ipsum dolor sit amet");
    }
}

关键说明

  1. 匹配DPR:通过devicePixelRatio()获取窗口的设备像素比,以此创建对应物理像素尺寸的QPixmap,并设置其DPR,确保渲染的文本拥有足够的像素细节。
  2. 坐标适配:绘制文本时使用逻辑坐标即可,QPainter会根据QPixmap的DPR自动转换为物理像素,无需手动调整坐标值。
  3. 背景绘制:绘制QPixmap背景时,使用img.rect()而非窗口的rect(),避免因尺寸不匹配导致的绘制异常。

内容的提问来源于stack exchange,提问作者overscore

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 15:44:51