标签:qt quick listview 下拉刷新 qml与c++
Qt Quick里的ListView,本身是Flickable的派生类,当你用鼠标拖曳或者手指触摸(触摸屏)时,会产生flickStarted和flickEnded两个信号,利用这两个信号,就可以实现下拉刷新数据,当然上拉刷新也是可以的。
创建一个Qt Quick App项目,添加dynamicModel.h和dynamicModel.cpp两个文件,用于实现DynamicListModel。项目创建过程参考《Qt Quick 之 Hello World 图文详解》。
我们实现的下拉刷新效果有点儿特别,每次刷新后,只保留预定义的一页数据,比如代码中默认的页大小为20。
版权所有foruok,转载请注明出处:http://blog.csdn.net/foruok。
很简单,直接上代码了。
dynamic.h:
#ifndef DYNAMICMODEL_H #define DYNAMICMODEL_H #include <QAbstractListModel> class DynamicListModelPrivate; class DynamicListModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(int pageSize READ pageSize WRITE setPageSize NOTIFY pageSizeChanged) Q_PROPERTY(int total READ total WRITE setTotal NOTIFY totalChanged) public: DynamicListModel(QObject *parent = 0); ~DynamicListModel(); int rowCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; QHash<int, QByteArray> roleNames() const; Q_INVOKABLE void loadMore(bool forward); int pageSize(); void setPageSize(int size); int total(); void setTotal(int total); signals: void pageSizeChanged(int size); void totalChanged(int total); private: DynamicListModelPrivate *m_dptr; }; #endif // DYNAMICMODEL_H
#include "dynamicModel.h" #include <QDebug> class DynamicListModelPrivate { public: DynamicListModelPrivate(DynamicListModel *model) : m_model(model), m_start(0), m_end(20) , m_total(100), m_pageSize(20) { m_roleNames.insert(Qt::UserRole, "content"); } void pageDown() { if(m_end < m_total) { m_start += m_pageSize; m_end += m_pageSize; if(m_end > m_total) { m_end = m_total; m_start = m_end - m_pageSize; } } } void pageUp() { if(m_start > 0) { m_start -= m_pageSize; if(m_start < 0) m_start = 0; m_end = m_start + m_pageSize; } } void adjustPageRange() { if(m_end - m_start < m_pageSize) { m_end = m_start + m_pageSize; if(m_end > m_total) { m_end = m_total; m_start = m_end - m_pageSize; } } } DynamicListModel *m_model; int m_start; int m_end; int m_total; int m_pageSize; QHash<int, QByteArray> m_roleNames; }; DynamicListModel::DynamicListModel(QObject *parent) : QAbstractListModel(parent), m_dptr(new DynamicListModelPrivate(this)) { } DynamicListModel::~DynamicListModel() { delete m_dptr; } int DynamicListModel::rowCount(const QModelIndex &parent) const { return m_dptr->m_end - m_dptr->m_start; } QVariant DynamicListModel::data(const QModelIndex &index, int role) const { int row = index.row(); //qDebug() << "index.row - " << row << " start - " << m_dptr->m_start; return QString::number(row + m_dptr->m_start); } QHash<int, QByteArray> DynamicListModel::roleNames() const { return m_dptr->m_roleNames; } void DynamicListModel::loadMore(bool forward) { beginResetModel(); if(forward)m_dptr->pageDown(); else m_dptr->pageUp(); endResetModel(); } int DynamicListModel::pageSize() { return m_dptr->m_pageSize; } void DynamicListModel::setPageSize(int size) { m_dptr->m_pageSize = size; m_dptr->adjustPageRange(); emit pageSizeChanged(size); } int DynamicListModel::total() { return m_dptr->m_total; } void DynamicListModel::setTotal(int total) { m_dptr->m_total = total; m_dptr->adjustPageRange(); emit totalChanged(total); }
loadMore()函数,区分向前还是向后加载数据,它调用DynamicListModel的pageDown()、pageUp()来更新内部的数据状态。在loadMore()一开始,调用beginResetModel(),通知关联到DynamicListModel上的view们刷新自己,当内部数据状态更新结束后,调用endResetModel()来通知view们,这样view们就会刷新,最终在实例化item delegate时调用data()方法来准备数据,此时m_start已变化,所以界面上看到的数字也跟着变了。
这个简单,我们在《Qt Quick 之 QML 与 C++ 混合编程详解》一文中已经讲过。直接看main.cpp:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "dynamicModel.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine engine; QQmlContext *ctx = engine.rootContext(); ctx->setContextProperty("dynamicModel", new DynamicListModel()); engine.load(QUrl(QStringLiteral("qrc:///main.qml"))); return app.exec(); }
是时候看看main.qml了:
import QtQuick 2.2 import QtQuick.Window 2.1 import QtQuick.Controls 1.2 import QtQuick.Layouts 1.1 import QtQuick.Controls.Styles 1.2 Window { width: 320; height: 480; minimumWidth: 300; minimumHeight: 480; visible: true; id: root; Component { id: listDelegate; Text { id: wrapper; width: parent.width; height: 32; font.pointSize: 15; verticalAlignment: Text.AlignVCenter; horizontalAlignment: Text.AlignHCenter; text: content; color: ListView.view.currentIndex == index ? "red" : "blue"; MouseArea { anchors.fill: parent; onClicked: { if(wrapper.ListView.view.currentIndex != index){ wrapper.ListView.view.currentIndex = index; } } } } } ListView { id: dynamicList; z: 1; anchors.fill: parent; anchors.margins: 10; delegate: listDelegate; model: dynamicModel; focus: true; activeFocusOnTab: true; highlight: Rectangle { color: "steelblue"; } property real contentYOnFlickStarted: 0; onFlickStarted: { //console.log("start,origY - ", originY, " contentY - ", contentY); contentYOnFlickStarted = contentY; } onFlickEnded: { //console.log("end,origY - ", originY, " contentY - ", contentY); dynamicModel.loadMore(contentY < contentYOnFlickStarted); } } }
onFlickStarted信号处理器,在这里我们仅仅是将flick开始时的contentY记录到contentYOnFlickStarted属性中。
onFlickEnded信号处理器,这里比较flick结束时的contentY和开始时的contentY(即contentYOnFlickStarted),结束时小,说明是下拉,结束时大,说明是上拉。根据比较结果调用loadMore()。
好啦,就这么简单了。看看效果。
图1是初始效果:
图1动态刷新列表初始效果
图2是下拉了两次后的效果:
图2 下拉刷新后的效果
图3是从图2所示状态上拉后的效果:
图3 上拉后的效果
版权所有foruok,转载请注明出处:http://blog.csdn.net/foruok。
好啦,解说完毕。
回顾本系列文章:
标签:qt quick listview 下拉刷新 qml与c++
原文地址:http://blog.csdn.net/foruok/article/details/39052729