Пользовательский виджет в QScrollArea плохо перерисовывается только при прокрутке - PullRequest
0 голосов
/ 22 сентября 2018

Я пытаюсь получить пользовательский виджет прокрутки в 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 и политики другого размера, но я все еще получаю эти ошибки перерисовки.

During first draw:

После прокрутки:

After scrolling

Я не знаю, что я делаю неправильно, потому что это в значительной степени идентично по важности образцу кода из charmap.

Этополный код: https://gist.github.com/jonasbuckner/2acc1a960e457946ce4756199de3fb57

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Ваш исходный код не работал, потому что вы рисовали все элементы, но использовали событие-> rect, которое может быть только частью RepeatingWidget.

Иногда непросто вычислить, какие элементы находятся в событии -> прямоугольник, как показывает @eyllanesc.В этих случаях просто используйте clientRect вместо этого - Qt обрежет рисунок для вас.

0 голосов
/ 23 сентября 2018

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

enter image description here

enter image description here

...