9

我写了画两个笑脸的应用程序:

在此处输入图像描述

第一个直接画在QWidget上:

void DirectFace::paintEvent(QPaintEvent *ev)
{
    QPainter painter(this);
    paintFace(painter);
}

第二个画在 a 上QPixmap,而后者又被传送到小部件:

void BufferedFace::paintEvent(QPaintEvent *ev)
{
    QPixmap buffer(width(), height());
    buffer.fill(Qt::transparent);
    QPainter painter(&buffer);
    paintFace(painter);

    QPainter p(this);
    p.drawPixmap(ev->rect(), buffer, ev->rect());
}

到目前为止,一切都很好。我想看看我的应用在高分辨率屏幕上的样子(我没有),所以我设置QT_SCALE_FACTOR=2并运行了我的应用:

在此处输入图像描述

第一张脸清晰明快,而第二张脸是像素化的。那是因为它被绘制到低分辨率像素图上。所以我扩大了它QPixmap并设置正确devicePixelRatio

void BufferedFace::paintEvent(QPaintEvent *ev)
{
    qreal pixelRatio = qApp->devicePixelRatio();
    QPixmap buffer(width() * pixelRatio, height() * pixelRatio);
    buffer.setDevicePixelRatio(pixelRatio);
    buffer.fill(Qt::transparent);
    QPainter painter(&buffer);
    paintFace(painter);

    QPainter p(this);
    p.drawPixmap(ev->rect(), buffer, ev->rect());
}

结果:

在此处输入图像描述

第二张脸看起来像是以正确的分辨率绘制的,但随后被放大了。现在我被困住了。如何在 Retina/HiDPI 屏幕上进行绘制QPixmap然后绘制它QPixmap以使其正常工作?

整体应用:

#include <QtWidgets>

class SmilingFace : public QWidget
{
    public:
    SmilingFace(QWidget *parent) : QWidget(parent) {};
    void paintFace(QPainter &painter);
};

class DirectFace : public SmilingFace
{
    public:
    DirectFace(QWidget *parent) : SmilingFace(parent) {}
    void paintEvent(QPaintEvent *ev) override;
};

class BufferedFace : public SmilingFace
{
    public:
    BufferedFace(QWidget *parent) : SmilingFace(parent) {}
    void paintEvent(QPaintEvent *ev) override;
};


void SmilingFace::paintFace(QPainter &painter)
{
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::NoPen);
    painter.setBrush(QBrush(Qt::lightGray));
    painter.drawEllipse(1, 1, width()-2, height()-2);

    painter.setPen(Qt::white);
    painter.setFont(QFont("", 32));
    painter.drawText(rect(), Qt::AlignHCenter, ";)");
}

void DirectFace::paintEvent(QPaintEvent *ev)
{
    QPainter painter(this);
    paintFace(painter);
}

void BufferedFace::paintEvent(QPaintEvent *ev)
{
    QPixmap buffer(width(), height());
    buffer.fill(Qt::transparent);
    QPainter painter(&buffer);
    paintFace(painter);

    QPainter p(this);
    p.drawPixmap(ev->rect(), buffer, ev->rect());
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget w;
    w.setWindowTitle("HiDPI");

    DirectFace d(&w);
    d.resize(48, 48);
    d.move(16, 16);

    BufferedFace i(&w);
    i.resize(48, 48);
    i.move(16 + 48 + 16, 16);

    w.show();

    return a.exec();
}
4

1 回答 1

5

如果您想要 HighDPI 渲染,您还应该为 QPainter 函数使用 QRectF 和 QPointF 参数。在您的paintFace(...) 函数中,调整drawEllipse 和drawText 函数以使用QRectF 参数而不是QRect。这可能会有所帮助。

使用 qApp->devicePixelRatio() 不是一个好主意。有些人使用混合的 HighDPI 和非 HighDPI 显示器。由于您在一个小部件paintEvent(...) 函数中,您可以直接使用QWidget 成员函数devicePixelRatioF(),而不是qApp->devicePixelRatio()。这将处理小部件的正确呈现,即使用户在具有混合分辨率的监视器之间移动小部件也是如此。

您还应该通过以下方式在 Qt 中启用高 DPI 缩放: QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

这是完整的解决方案,它可以在 HighDPI 和非 HighDPI 屏幕上完美呈现笑脸,即使小部件在两者之间移动也是如此。用 Qt 5.9.2 测试

#include <QtWidgets>

class SmilingFace : public QWidget
{
public:
    SmilingFace(QWidget *parent) : QWidget(parent) {};
    void paintFace(QPainter &painter);
};

class DirectFace : public SmilingFace
{
public:
    DirectFace(QWidget *parent) : SmilingFace(parent) {}
    void paintEvent(QPaintEvent *ev) override;
};

class BufferedFace : public SmilingFace
{
public:
    BufferedFace(QWidget *parent) : SmilingFace(parent) {}
    void paintEvent(QPaintEvent *ev) override;
};


void SmilingFace::paintFace(QPainter &painter)
{
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::NoPen);
    painter.setBrush(QBrush(Qt::lightGray));
    painter.drawEllipse(QRectF(1, 1, width() - 2, height() - 2));

    painter.setPen(Qt::white);
    painter.setFont(QFont("", 32));
    painter.drawText(QRectF(0, 0, width(), height()), Qt::AlignHCenter, ";)");
}

void DirectFace::paintEvent(QPaintEvent *ev)
{
    QPainter painter(this);
    paintFace(painter);
}

void BufferedFace::paintEvent(QPaintEvent *ev)
{
    qreal dpr = devicePixelRatioF();
    QPixmap buffer(width() * dpr, height() * dpr);
    buffer.setDevicePixelRatio(dpr);
    buffer.fill(Qt::transparent);
    QPainter painter(&buffer);
    paintFace(painter);

    QPainter p(this);
    p.drawPixmap(ev->rect(), buffer, buffer.rect());
}

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QApplication a(argc, argv);

    QWidget w;
    w.setWindowTitle("HiDPI");

    DirectFace d(&w);
    d.resize(48, 48);
    d.move(16, 16);

    BufferedFace i(&w);
    i.resize(48, 48);
    i.move(16 + 48 + 16, 16);

    w.show();

    return a.exec();
}
于 2017-11-08T14:46:55.200 回答