先说一下分页思路吧:
QSqlQueryModel 是通过 setQuery 函数进行查询的,setQuery 函数支持sql语句查询,那sql语句中有有一个 LIMIT ,就是使用LIMIT进行分页。
LIMI:Limit接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目
Limit 语句详解:点击这里就可以进去哦
这篇文章就是使用sql语句的LIMIT进行分页,sql语句拼接是重点。注意:拼接sql一定要注意空格、空间、空格
#include
#include
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;
#include "customqsqlquerymodel.h"
#include
#include
#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一定要注意空格、空间、空格
在需要使用类中的头文件的类前添加 我们重写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);
}
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();
}
/**
* @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();
}
}
这个排序是通过点击表头进行排序的,所以需要用到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语句头皮发麻。