Рамка кнопки обрезается при использовании дробного DPR.C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Рамка кнопки обрезается при использовании дробного DPR.

Сообщение Anonymous »

Недавно я обновил часть программного обеспечения с Qt 5.15 до Qt 6.5. Сам процесс оказался проще, чем ожидалось, но новая обработка масштабирования с высоким разрешением привела к некоторым визуальным ошибкам на нескольких виджетах, в основном видимых на кнопках, поэтому я сосредоточусь на них.
Эти кнопки основаны на 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
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»