Qt: Рисование QPixmaps с высоким DPI

Я написал приложение, которое рисует два улыбающихся лица:

введите описание изображения здесь

Первый нарисован прямо на QWidget:

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

Второй нарисован на 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());
}

Результат:

введите описание изображения здесь

Второе лицо выглядит так, как будто оно нарисовано с правильным разрешением, но затем масштабировано. Теперь я застрял. Как рисовать на QPixmap а затем нарисовать это QPixmap так правильно работает на экранах Retina / HiDPI?

Целое приложение:

#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();
}

2

Решение

Если вы хотите рендеринг HighDPI, вы также должны использовать аргументы QRectF и QPointF для функций QPainter. В вашей функции paintFace (…) настройте функции drawEllipse и drawText, чтобы использовать аргументы QRectF, а не QRect. Это может помочь.

Не рекомендуется использовать qApp-> devicePixelRatio (). Есть люди со смешанными мониторами HighDPI и Non-HighDPI. Поскольку вы находитесь в функции виджета paintEvent (…), вы можете напрямую использовать функцию-член QWidget devicePixelRatioF (), а не qApp-> devicePixelRatio (). Это обеспечит правильную визуализацию виджета, даже когда пользователь перемещает виджет между мониторами со смешанным разрешением.

Вы также должны включить масштабирование с высоким разрешением в Qt через: QCoreApplication :: setAttribute (Qt :: AA_EnableHighDpiScaling);

Здесь представлено полное решение, которое отлично отображает улыбающееся лицо на экране HighDPI и Non-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();
}
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]