Custom Widget in QScrollArea Badly Redrawing Only on Scroll

我只是一个虾纸丫 提交于 2019-12-11 12:08:58

问题


I'm trying to get a custom scrolling widget in QT, and I'm getting redraw errors on scroll. Alt-tab or other redrawing events redraw correctly.

I'm basing it on the example at http://doc.qt.io/qt-5/qtwidgets-widgets-charactermap-example.html

repeatingwidget.cpp (excerpt):

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 (excerpt):

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

This seems to match the example, but I'm getting redraw errors that don't happen in charmap.

I've tried setGeometry, setWidgetResizable, and different size policies, but I'm still getting these redraw errors.

After scrolling:

I don't know what I'm doing wrong because it's largely identical in important ways to the example code from the charmap.

This is the full code: https://gist.github.com/jonasbuckner/2acc1a960e457946ce4756199de3fb57


回答1:


QPaintEvent is a method that allows you to make an intelligent painting, that is, to paint where necessary, thus saving resources, for example it gives us the information of the rectangle that must be painted through event->rect(), with this we can calculate the items that have to be painted since others will be hidden and therefore it is not necessary to paint them:

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




回答2:


Your original code didn't work because you were drawing all of the items, but using the event->rect, which may only be part of the RepeatingWidget.

Sometimes it is not easy to calculate which items are in the event->rect as @eyllanesc shows. In these cases, just use clientRect instead - Qt will clip the drawing for you.



来源:https://stackoverflow.com/questions/52460376/custom-widget-in-qscrollarea-badly-redrawing-only-on-scroll

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!