Qt:利用QSqlQueryModel(只读模型)进行分页

28 篇文章 1 订阅
8 篇文章 1 订阅


QSqlQueryModel类为SQL结果集提供了一个只读数据模型

先说一下分页思路吧:

QSqlQueryModel 是通过 setQuery 函数进行查询的,setQuery 函数支持sql语句查询,那sql语句中有有一个 LIMIT ,就是使用LIMIT进行分页。

LIMI:Limit接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目

Limit 语句详解:点击这里就可以进去哦

这篇文章就是使用sql语句的LIMIT进行分页,sql语句拼接是重点。注意:拼接sql一定要注意空格、空间、空格

第一步:重写 QSqlQueryModel

#include <QSqlQueryModel>
#include <QPoint>

class customQSqlQueryModel : public QSqlQueryModel
{
    Q_OBJECT
public:
    explicit customQSqlQueryModel(QObject *parent = nullptr);
    
    //设置sql语句 到 from tableName 结束
    void setSql(QString sql);

    //设置过滤条件
    void setFilter(QString filter);

    //设置sql查询条数
    void setLimitCount(int count);
    
    //设置排序
	int setOrderBy(QString field);
	//添加数据到 m_orderByFields
    void appOrderByList(QString field,bool isDESC = false);

    //设置left join 的表
    void setJoin(QString tabelName,QString oldFieldName,QString newFieldName);
    //设置除了主表其他表进行相连
    void setOtherJoin(QString tableNameLeft,QString tableNameRight,QString joinFieldName,QString showFieldName,int colIndex);
    //是否已连接
    bool isJoin(QString tableName,QString sql);

    //拼接sql语句
    void jointSql();

	//执行查询语句
    void mySqlSelect();
    //执行查询语句--是否重新拼接sql语句
    void mySqlSelect(bool queryAgain);
    
    //拼接sql私有方法
private:
	//拼接left join
    void jointLeftJoin(QString &tmp);
    //拼接ohterLeftJOin
    void jointOtherLeftJoin(QString &tmp);
    //拼接where
    void jointWhere(QString &tmp);
    //拼接OrderBy
    void jointOrderBy(QString &tmp);
    //拼接LIMIT
    void jointLimit(QString &tmp);
	
	//分页的方法---------------
public:
    //计算页数
    void calculatePage();

    //设置第几页
    bool currentPageEdit(int page);

    //获取当前页
    int getCurrentPage();

    //获取总页数
    int getTotalNumPage();

private:
    QString m_sql;                  //初始sql
    QString m_startTableName;       //初始的表名,left join 时 用到
    QString m_fullSql;              //拼接完成的sql

	//Left join 使用到的储存列表
    QStringList m_joinTableNames;   //连接表
    QStringList m_joinOldFieldNames;//旧列
    QStringList m_joinNewFieldNames;//新列

	//其它join
    QStringList m_otherJoinTableLeft;   //左,作为连接表
    QStringList m_otherJoinTableRight;  //右,作为被连接表
    QStringList m_joinFieldNames;       //连接的键值,双方名字需要相同
    QStringList m_showFieldNames;       //右,被连接表显示字段
    QList<int> m_colIndexs;             //显示的列索引

    QString m_filter;               //过滤条件

    QStringList m_orderByFields;    //排序字段集合
    QList<bool> m_isDESCs;          //是否倒序

    bool m_queryAgain;              //查看是否更新了查询条件,true : 重新拼接sql语句,false 不重新拼接

    //分页的私有成员变量
private:
    QPoint m_limit;                 //查询控制条数  x :从x - 1开始 , y : 查询条数

    QString m_NotLimitStr;          //不包含limit语句,用于查询数据总条数

    int m_thisPage;                 //当前页
    int m_totalPage;                //总页数

    // QAbstractItemModel interface
public:
    //控制数据居中显示
    QVariant data(const QModelIndex &index, int role) const override;

第二步:实现重写 QSqlQueryModel的方法

#include "customqsqlquerymodel.h"

#include <QSqlQuery>
#include <QDebug>

#include "DB/sqldatabase.h"   //数据库database,查询时用到

customQSqlQueryModel::customQSqlQueryModel(QObject *parent)
    : QSqlQueryModel(parent)
{
	//由于用到了QPoint来存放limit两个常量,在这里初始化一下
    m_limit.setX(0);	
    m_limit.setY(0);
    m_queryAgain = true;
}

/**
 * @brief customQSqlQueryModel::setSql
 * @param sql 初始sql语句
 * 功能:设置sql语句,获取表名
 */
void customQSqlQueryModel::setSql(QString sql)
{
    m_sql = sql;

    //获取查询的表格名
    m_startTableName = m_sql.split(" ",QString::SkipEmptyParts).last();
}

/**
 * @brief customQSqlQueryModel::setFilter
 * @param filter          条件sql语句,不包含where,请自己注意sql语句的空格
 * @param filterValues    条件语句的 值
 * 功能:设置条件语句
 */
void customQSqlQueryModel::setFilter(QString filter)
{
    m_filter = filter;
}

/**
 * @brief customQSqlQueryModel::setLimit
 * @param count     读取的总数
 * 功能:设置LIMIT 第二个参数,并将当前页初始化为第一页
 */
void customQSqlQueryModel::setLimitCount(int count)
{
    m_limit.setY(count);
    m_thisPage = 1;
}

/**
 * @brief customQSqlQueryModel::setOrderBy
 * @param field 列名
 * @return   1 : 升序  , 2 :降序  , 0 :不排序
 * 功能:通过列名进行排序,排序顺序 升序--》降序--》不排序
 */
int customQSqlQueryModel::setOrderBy(QString field)
{
    int index = m_orderByFields.indexOf(field);

    if(-1 != index)
    {
        //存在,判断是否降序
        if(m_isDESCs[index])
        {
            //降序,将降序--》不排序:将列名和是否降序从列表中删除
            m_orderByFields.removeAt(index);
            m_isDESCs.removeAt(index);
            return 0;
        }
        else
        {
            //升序,将升序--》降序
            m_isDESCs[index] = true;
            return 2;
        }
    }
    else
    {
        //不存在,添加
        appOrderByList(field);
        return 1;
    }
}

/**
 * @brief customQSqlQueryModel::appOrderByList
 * @param field         排序字段
 * @param isDESC        是否倒叙,true倒序
 * 功能:设置order by 参数,添加进入容器,升序
 */
void customQSqlQueryModel::appOrderByList(QString field, bool isDESC)
{
    m_orderByFields.append(field);
    m_isDESCs.append(isDESC);
}

/**
 * @brief customQSqlQueryModel::setJoin
 * @param tableName         连接的表
 * @param oldFieldName      旧的列名,列名一定是外键列
 * @param newFieldName      新的列名,外键表的某个字段
 *
 * 功能:添加 LEFT JOIN 需要的参数
 *
 */
void customQSqlQueryModel::setJoin(QString tableName, QString oldFieldName,QString newFieldName)
{
    if(tableName.isEmpty() || oldFieldName.isEmpty() || newFieldName.isEmpty())
    {
        return;
    }
    
	//当存在一列相同的不添加
    if(m_joinTableNames.contains(tableName))
    {
        if(m_joinOldFieldNames.contains(oldFieldName))
        {
            return;
        }
    }

    m_joinTableNames.append(tableName);
    m_joinOldFieldNames.append(oldFieldName);
    m_joinNewFieldNames.append(newFieldName);
}

/**
 * @brief customQSqlQueryModel::setOtherJoin
 * @param tableNameLeft     连接表
 * @param tableNameRight    被连接表
 * @param joinFieldName     连接键值
 * @param showFieldName     显示字段
 */
void customQSqlQueryModel::setOtherJoin(QString tableNameLeft, QString tableNameRight, QString joinFieldName, QString showFieldName,int colIndex)
{
    if(tableNameLeft.isEmpty() || tableNameRight.isEmpty() || joinFieldName.isEmpty() || showFieldName.isEmpty() || colIndex < 0)
    {
        return;
    }
    m_otherJoinTableLeft.append(tableNameLeft);
    m_otherJoinTableRight.append(tableNameRight);
    m_joinFieldNames.append(joinFieldName);
    m_showFieldNames.append(showFieldName);
    m_colIndexs.append(colIndex);
}

/**
 * @brief customQSqlQueryModel::isJoin
 * @param tabelName  要连接的表名
 * @return  true:以连接过了
 */
bool customQSqlQueryModel::isJoin(QString tableName,QString sql)
{
    QStringList splitList = sql.split(" ");

    for(int i = 0; i < splitList.size(); i++)
    {
        if(splitList[i].compare("LEFT") == 0)
        {
            if(tableName.compare(splitList[i+2]) == 0)
            {
                return true;
            }
        }
    }

    return false;
}

/**
 * @brief customQSqlQueryModel::jointSql
 * 功能:拼接完整的sql语句
 */
void customQSqlQueryModel::jointSql()
{
    QString tmp = "";

    tmp.append(m_sql);

    jointLeftJoin(tmp);

    jointOtherLeftJoin(tmp);

    jointWhere(tmp);

    jointOrderBy(tmp);
	
	//用于查询数据总条数的 m_NotLimitStr
    m_NotLimitStr = tmp;

    jointLimit(tmp);

    m_fullSql = tmp;
}

/**
 * @brief customQSqlQueryModel::jointLeftJoin
 * @param tmp
 * 功能:拼接连接
 */
void customQSqlQueryModel::jointLeftJoin(QString &tmp)
{
    //left join
    if(!m_joinTableNames.isEmpty())
    {
        for(int i = 0; i < m_joinTableNames.size(); i ++)
        {
            //替换查询列
            QString tempNewFieldName = QString("%1.%2").arg(m_joinTableNames[i]).arg(m_joinNewFieldNames[i]);

            //将字段替换
            tmp.replace(m_joinOldFieldNames[i],tempNewFieldName);

            //当第一次连接就拼接
            if(false == isJoin(m_joinTableNames[i],tmp))
            {
                QString joinStr = QString(" LEFT JOIN %1 ON %2.%3 = %4.%5 ").arg(m_joinTableNames[i]).arg(m_startTableName)
                        .arg(m_joinOldFieldNames[i]).arg(m_joinTableNames[i]).arg(m_joinOldFieldNames[i]);

                tmp.append(joinStr);
            }
        }
    }
}

/**
 * @brief customQSqlQueryModel::jointOtherLeftJoin
 * @param tmp
 * 功能:拼接其它连接
 */
void customQSqlQueryModel::jointOtherLeftJoin(QString &tmp)
{
    //其它 left join
    if(!m_otherJoinTableRight.isEmpty())
    {
        for(int i = 0; i < m_otherJoinTableRight.size(); i++)
        {
            //拼接显示列名
            QString showFieldName = QString(" %1.%2 ").arg(m_otherJoinTableRight[i]).arg(m_showFieldNames[i]);

            //将显示列名添加到tmp
            QStringList list = tmp.split("from");

            QStringList colList = list[0].split(",");

            QString appTem;

            for(int j = 0; j < colList.size(); j++)
            {
                if(j == m_colIndexs[i] - 1)
                {
                    appTem.append(showFieldName);
                    appTem.append(",");
                }

                appTem.append(colList[j]);

                if(j + 1 != colList.size())
                {
                    appTem.append(",");
                }
            }

            tmp = QString("%1 %2 %3").arg(appTem).arg("from").arg(list[1]);

            if(false == isJoin(m_otherJoinTableRight[i],tmp))
            {
                QString joinStr = QString(" LEFT JOIN %1 ON %2.%3 = %4.%5 ").arg(m_otherJoinTableRight[i]).arg(m_otherJoinTableLeft[i])
                        .arg(m_joinFieldNames[i]).arg(m_otherJoinTableRight[i]).arg(m_joinFieldNames[i]);

                tmp.append(joinStr);
            }
        }
    }
}

/**
 * @brief customQSqlQueryModel::jointWhere
 * @param tmp
 * 功能:拼接where
 */
void customQSqlQueryModel::jointWhere(QString &tmp)
{
    //where
    if(!m_filter.isEmpty())
    {
        tmp.append(m_filter);
    }
}

/**
 * @brief customQSqlQueryModel::jointOrderBy
 * @param tmp
 * 功能:拼接排序参数
 */
void customQSqlQueryModel::jointOrderBy(QString &tmp)
{
    //orderby
    if(!m_orderByFields.isEmpty())
    {
        QString orderTmp = " ORDER BY ";

        for(int i = 0; i < m_orderByFields.size(); i++)
        {
            orderTmp.append(m_orderByFields[i]);

            orderTmp.append(QString(" ").append(m_isDESCs[i] ? "DESC" : "ASC"));

            if(i + 1 != m_orderByFields.size())
            {
                orderTmp.append(",");
            }
        }

        tmp.append(orderTmp);
    }

}

/**
 * @brief customQSqlQueryModel::jointLimit
 * @param tmp
 * 功能:拼接limit参数
 */
void customQSqlQueryModel::jointLimit(QString &tmp)
{
    //QPoint.isNill() 当x和y为0,返回true
    if(!m_limit.isNull())
    {
        tmp.append(QString(" LIMIT %1 , %2 ").arg(m_limit.x()).arg(m_limit.y()));
    }
}

/**
 * @brief customQSqlQueryModel::mySqlSelect
 * 功能:执行sql查询语句
 */
void customQSqlQueryModel::mySqlSelect()
{
    QSqlQuery query(g_myDB);

    //是否重新拼接
    if(m_queryAgain)
    {
        jointSql();
    }

    query.prepare(m_fullSql);

    this->setQuery(m_fullSql,g_myDB);

    m_queryAgain = false;

    //计算页数
    calculatePage();
}

/**
 * @brief customQSqlQueryModel::mySqlSelect
 * @param queryAgain 设置 是否从新拼接参数
 * 功能:设置是否从新拼接参数,并执行查询
 */
void customQSqlQueryModel::mySqlSelect(bool queryAgain)
{
    m_queryAgain = queryAgain;
    mySqlSelect();
}

/**
 * @brief customQSqlQueryModel::calculatePage
 * 功能:计算页数,总页数
 */
void customQSqlQueryModel::calculatePage()
{
    QSqlQuery query(g_myDB);

    query.prepare(m_NotLimitStr);

    if(query.exec())
    {
        int rowCount = query.size();

        int tmpTotal = rowCount / m_limit.y();

		//不能取余,加一页
        if(rowCount % m_limit.y() != 0)
        {
            tmpTotal++;
        }

        m_totalPage = tmpTotal;

        return;
    }

    m_totalPage = 0;
}

/**
 * @brief customQSqlQueryModel::currentPageEdit
 * @param page 第几页
 * 功能:跳转至page页
 */
bool customQSqlQueryModel::currentPageEdit(int page)
{
    if(page > m_totalPage || page <= 0)
    {
        return false;
    }

    m_thisPage = page;

    --page;

    int count = m_limit.y();

    m_limit.setX(page * count);

    mySqlSelect(true);

    return true;
}

/**
 * @brief customQSqlQueryModel::getCurrentPage
 * @return 当前页
 */
int customQSqlQueryModel::getCurrentPage()
{
    return m_thisPage;
}

/**
 * @brief customQSqlQueryModel::getTotalNumPage
 * @return 总页数
 */
int customQSqlQueryModel::getTotalNumPage()
{
    return m_totalPage;
}

//重写data方法,主要使文字居中显示
QVariant customQSqlQueryModel::data(const QModelIndex &index, int role) const
{
    QVariant value = QSqlQueryModel::data(index,role);

    //单元格内容居中
    if(role == Qt::TextAlignmentRole)
    {
        value = Qt::AlignCenter;
    }

    return value;
}

第三步:如何使用

其实把这个代码看一下就知道应该知道咋使了,但我还是要说一说…信号和槽连接我就不写出来了。
注意:拼接sql一定要注意空格、空间、空格

3.1 引用

在需要使用类中的头文件的类前添加 我们重写model的那个类 ,这个过程称为 “前置声明”

前置声明:点击这里就可以进入了解前置声明

RoomManage.h


//这里是头文件--------

class customQSqlQueryModel;   //把它放到类的前面,前置声明

namespace Ui {
class RoomManage;
}

class RoomManage : public QWidget
{
    Q_OBJECT

public:
    explicit RoomManage(QWidget *parent = nullptr);
    ~RoomManage();
    
private:
	customQSqlQueryModel *m_model;  //声明一下私有成员
}

RoomManage .cpp

#include "customqsqlquerymodel.h"

RoomManage::RoomManage(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::RoomManage),
    isLoad(true)
{
    ui->setupUi(this);
    m_model = new customQSqlQueryModel(this);
}

3.2 初始化

cpp文件

void RoomManage::initTable()
{
    m_sql = "select "
                "room_id ,"
                "tower_range_id as 楼区,"
                "tower_seat_id as 楼座,"
                "room_type_id as 房间类型,"
                "room_state_id as 房间状态,"
                "tower_tier as 楼层 "
            "from room ";
    //拼接sql一定要注意空格、空间、空格

	//设置sql语句
    m_model->setSql(m_sql);

	//进行连接
    m_model->setJoin("tower_range","tower_range_id","m_describe");
    m_model->setJoin("tower_seat","tower_seat_id","m_describe");
    m_model->setJoin("room_type","room_type_id","m_describe");
    m_model->setJoin("room_state","room_state_id","m_describe");

	//设置显示条数
    m_model->setLimitCount(7);
	//查询
    m_model->mySqlSelect();
	//设置模型
    ui->tableView->setModel(m_model);
    //隐藏第一行
    ui->tableView->hideColumn(0);
    //设置水平表头最后一列补齐	
    ui->tableView->horizontalHeader()->setStretchLastSection(true);
    //设置表格菜单弹出设置
    ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
    //设置选中行为
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    //设置选择模式
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);

	//必须初始化页数
    getCurrentPage();
    getTotalNumPage();
}

3.3 分页

/**
 * @brief RoomManage::currentPageEdit
 * @param pageStr 跳转的页数str
 * 功能:跳转到pageStr页
 * 由于我用的时QLineEdit作为编辑框,索引传递的参数是QString类型,其它的上一页什么的都可以通过这个函数实现,
 */
void RoomManage::currentPageEdit(QString pageStr)
{
    int page = 0;

    if(pageStr.isNull() || pageStr.isEmpty())
    {
        return;
    }

    bool isOK;

    page = pageStr.toInt(&isOK);

    if(isOK)
    {
        if(page > m_totalPage || page <= 0)
        {
            QMessageBox::warning(this,"警告","您输入的数字超出范围,请重新输入");
            return;
        }
        m_model->currentPageEdit(page);
        getCurrentPage();
    }
}

3.4 排序

这个排序是通过点击表头进行排序的,所以需要用到QHeaderView类,记得引用这个类,信号和槽就写出来了。

/**
 * @brief RoomManage::headerViewOnClicked
 * @param colIndex  行数
 * 功能:点击列头,进行降序或升序
 */
void RoomManage::headerViewOnClicked(int colIndex)
{
	//获取列名
    QString headerStr = m_model->headerData(colIndex,Qt::Horizontal).toString();
	//进行切割,如果排过序的话 列名是不正确的这个操作是为了获取正确的列名
    QStringList headers = headerStr.split(" ",QString::SkipEmptyParts);
	//进行排序
    int enumValue = m_model->setOrderBy(headers[0]);
	//对列名进行拼接,升序加个上箭头降序加个下箭头不排序就是原列名
    QString temp = " ";

    switch (enumValue) {
    case 1:
        temp.append("↑");
        break;
    case 2:
        temp.append("↓");
        break;
    default:
        break;
    }
	
	//设置列名
    m_model->setHeaderData(colIndex,Qt::Horizontal,headers[0].append(temp));
	
	//查询数据,并提示需要重新拼接sql
    m_model->mySqlSelect(true);
}

总结:怕是小脑袋瓜被热昏头了,看sql语句头皮发麻。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值