Эти кнопки основаны на QPushButton, и их событие PaintEvent перезаписано следующим образом:
QPainter p(this);
p.setRenderHints(QPainter::Antialiasing);
//Set clip path
QPainterPath bgRectPath;
bgRectPath.addRoundedRect(this->rect(), rectRadius, rectRadius);
p.setClipPath(bgRectPath);
//Draw background
p.fillPath(bgRectPath, QBrush(backgroundColor));
//Draw Frame
QScreen *screen = this->screen();
qreal dpr = screen->devicePixelRatio();
qreal scaledLineWidth = lineWidth * ceil(dpr);
QPen framePen = QPen(lineColor, scaledLineWidth);
framePen.setCosmetic(true);
p.setPen(framePen);
p.drawPath(bgRectPath);
//Draw Label
QFont font = p.font();
font.setPixelSize(labelFontSize);
p.setFont(font);
p.setPen(fontColor);
p.drawText(rect(), labelAlign, label);
Я уже настроил PaintEvent так, чтобы ширина линии не была дробной, что привело к совершенно другому набору проблем. Вместо этого ширина линии масштабируется вручную с помощью ceil(dpr) и с помощью косметического QPen.
Это решило визуальные ошибки для некоторых кнопок, но не для всех. Остальные проблемы, похоже, связаны с QLayouts, в которых находятся эти кнопки, и именно здесь начинает возникать несогласованность. Вот три примера кнопок в макетах с использованием полей 0, 0, 0, 0:
Эти кнопки идеальны.

Эта кнопка обрезана слева

Эти кнопки обрезаны сверху
< img alt="Эти кнопки обрезаны сверху" src="https://i.sstatic.net/lQC5uPx9.png" />
За исключением добавления кнопок и изменения поля я установил выравнивание на Qt::AlignRight и интервал на 10. Удаление выравнивания также не решает проблему.
Как видно, некоторые кнопки обрезаны выключен либо слева, либо сверху. Это можно исправить, изменив поля макета, например. 1, 0, 0, 0 или 0, 1, 0, 0 соответственно. Но на этом согласованность не заканчивается: иногда одного пикселя недостаточно и требуется 2-3 пикселя. Кроме того, когда кнопки, которые нормально используют нулевое поле со всех сторон, все же получают поле, они, как следствие, обрезаются.
Я думал о реализации всех этих полей вручную, но боюсь, что поведение может измениться, как только другое используется коэффициент масштабирования или разрешение экрана.
Существует ли последовательный способ предотвратить отключение этих виджетов? Самый простой способ, вероятно, — настроить HighDpiScaleFactorRoundingPolicy, чтобы не было дробных DPR, но я хотел бы предотвратить это, если это возможно.
Вот код, необходимый для репликации обрезки кнопку на левой стороне (с использованием приемлемого разрешения монитора 3840 x 2160 и масштабирования 150%). Я собрал его, используя 64-разрядную версию Qt 6.5.5 MinGW.
main.cpp
#include "mainwindow.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include "custombutton.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
QWidget *widget = new QWidget;
CustomButton *button = new CustomButton;
QHBoxLayout *layout = new QHBoxLayout;
layout->addSpacing(5);
layout->addWidget(button);
layout->addSpacing(5);
layout->setContentsMargins(0, 0, 0, 0); //Left side is cut off
// layout->setContentsMargins(1, 0, 0, 0); //Left side is not cut off
widget->setLayout(layout);
setCentralWidget(widget);
}
MainWindow::~MainWindow() {}
custombutton.h
#ifndef CUSTOMBUTTON_H
#define CUSTOMBUTTON_H
#include
#include
#include
#include
#include
class CustomButton : public QPushButton
{
Q_OBJECT
public:
CustomButton();
protected:
void paintEvent(QPaintEvent *event) override;
};
#endif // CUSTOMBUTTON_H
custombutton.cpp
#include "custombutton.h"
CustomButton::CustomButton() {}
void CustomButton::paintEvent(QPaintEvent *event)
{
QPainter p(this);
p.setRenderHints(QPainter::Antialiasing);
//Set clip path
QPainterPath bgRectPath;
bgRectPath.addRoundedRect(rect(), 0.5*rect().height(), 0.5*rect().height());
p.setClipPath(bgRectPath);
//Draw Frame
QScreen *screen = this->screen();
qreal dpr = screen->devicePixelRatio();
qreal scaledLineWidth = 1.0 * ceil(dpr);
QPen framePen = QPen(Qt::black, scaledLineWidth);
framePen.setCosmetic(true);
p.setPen(framePen);
p.drawPath(bgRectPath);
event->accept();
}
Подробнее здесь: https://stackoverflow.com/questions/787 ... tional-dpr
Мобильная версия