Я написал приложение, которое рисует два улыбающихся лица:
Первый нарисован прямо на 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();
}
Если вы хотите рендеринг 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();
}
Других решений пока нет …