Qt的一些经验总结(8)-- qtableview滚动的刷新机制

440 阅读1分钟

代码流程

在控件初始化的时候,绑定scrollbar的valueChanged信号

// qabstractscrollarea.cpp
void QAbstractScrollAreaPrivate::init()
{
    // 省略部分代码
    QObject::connect(hbar, SIGNAL(valueChanged(int)), q, SLOT(_q_hslide(int)));
    QObject::connect(hbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
    scrollBarContainers[Qt::Vertical] = new QAbstractScrollAreaScrollBarContainer(Qt::Vertical, q);
    scrollBarContainers[Qt::Vertical]->setObjectName(QLatin1String("qt_scrollarea_vcontainer"));
    vbar = scrollBarContainers[Qt::Vertical]->scrollBar;
    vbar->setRange(0,0);
    scrollBarContainers[Qt::Vertical]->setVisible(false);
    vbar->installEventFilter(q);
    QObject::connect(vbar, SIGNAL(valueChanged(int)), q, SLOT(_q_vslide(int)));
    QObject::connect(vbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection);
    // 省略部分代码
}

void QAbstractScrollAreaPrivate::_q_hslide(int x)
{
    Q_Q(QAbstractScrollArea);
    int dx = xoffset - x;
    xoffset = x;
    // 调用子类scrollContentsBy复写的接口
    q->scrollContentsBy(dx, 0);
    flashScrollBars();
}

qtableview中复写了scrollContentsBy接口(之所以确定是这个函数进行ui刷新,是因为将这个函数复写后空实现,界面滚动后没有任何变化,没有进入paintEvent函数中)

void QTableView::scrollContentsBy(int dx, int dy)
{
    // 省略部分代码
    d->scrollContentsBy(dx, dy);
    // 省略部分代码
}

// 将滚动区域设置为脏区域
inline void scrollContentsBy(int dx, int dy) {
    scrollDirtyRegion(dx, dy);
    viewport->scroll(dx, dy);
}

// 更新脏区域
inline void scrollDirtyRegion(int dx, int dy) {
    scrollDelayOffset = QPoint(-dx, -dy);
    updateDirtyRegion();
    scrollDelayOffset = QPoint(0, 0);
}

void updateDirtyRegion() {
    updateTimer.stop();
    viewport->update(updateRegion);
    updateRegion = QRegion();
}

qt的ui绘制逻辑是先清空当前脏区域的内容,然后在进行绘制,最终走进paintEvent中。