Пользовательский виджет в QScrollArea плохо перерисовывается только при прокрутке
Я пытаюсь получить пользовательский виджет прокрутки в QT, и я получаю ошибки перерисовки при прокрутке. Alt-tab или другие события перерисовки перерисовываются правильно.
Я основываю это на примере по адресу http://doc.qt.io/qt-5/qtwidgets-widgets-charactermap-example.html
repeatatingwidget.cpp (отрывок):
QSize RepeatingWidget::sizeHint() const {
return QSize(500, itemHeight * displayItems.size() + 1);
}
void RepeatingWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.fillRect(event->rect(), QBrush(Qt::white));
painter.setFont(displayFont);
QRect itemRect = event->rect();
int top = itemRect.top();
QFontMetrics fontMetrics(*displayFont);
for (auto item : displayItems) {
painter.setPen(QPen(Qt::gray));
painter.drawRect(itemRect.left(), top, itemRect.right(), itemHeight);
painter.setPen(QPen(Qt::black));
painter.drawText(8, 4 + top + fontMetrics.ascent(), item.name);
top += itemHeight;
}
}
mainwindow.cpp (отрывок):
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
QMenu *filemenu = menuBar()->addMenu(tr("File"));
filemenu->addAction(tr("Quit"), this, &QWidget::close);
auto *centralWidget = new QWidget;
scrollArea = new QScrollArea;
repeatingArea = new RepeatingWidget();
scrollArea->setWidget(repeatingArea);
auto *centralLayout = new QVBoxLayout;
centralLayout->addWidget(scrollArea, 1);
centralWidget->setLayout(centralLayout);
setCentralWidget(centralWidget);
setWindowTitle(tr("Widget Test"));
}
Это похоже на пример, но я получаю ошибки перерисовки, которые не происходят в charmap.
я пробовал setGeometry
, setWidgetResizable
и политики другого размера, но я все еще получаю эти ошибки перерисовки.
После прокрутки:
Я не знаю, что я делаю неправильно, потому что это в значительной степени идентично по важности образцу кода из charmap.
Это полный код: https://gist.github.com/jonasbuckner/2acc1a960e457946ce4756199de3fb57
2 ответа
QPaintEvent
это метод, который позволяет вам создавать интеллектуальные рисунки, то есть рисовать там, где это необходимо, экономя ресурсы, например, он дает нам информацию о прямоугольнике, который нужно раскрасить event->rect()
, с этим мы можем вычислить элементы, которые должны быть нарисованы, так как другие будут скрыты, и поэтому нет необходимости красить их:
void RepeatingWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.fillRect(event->rect(), QBrush(Qt::white));
painter.setFont(displayFont);
QFontMetrics fontMetrics(displayFont);
int i = std::max(event->rect().top()/itemHeight, 0);
int j = std::min(event->rect().bottom()/itemHeight+1, displayItems.size());
QRect itemRect(0, i*itemHeight, width(), itemHeight);
for(; i < j; i++){
painter.setPen(QPen(Qt::gray));
painter.drawRect(itemRect);
painter.setPen(QPen(Qt::black));
painter.drawText(8, 4 + itemRect.top() + fontMetrics.ascent(), displayItems[i].name);
itemRect.translate(0, itemHeight);
}
}
Ваш исходный код не работал, потому что вы рисовали все элементы, но использовали event->rect, который может быть только частью RepeatingWidget.
Иногда непросто вычислить, какие элементы находятся в событии -> прямоугольник, как показывает @eyllanesc. В этих случаях просто используйте clientRect - Qt обрежет рисунок за вас.