QSqlQueryModel 是 Qt 框架中提供的一个高级数据库模型类,它继承自 QAbstractTableModel,专门用于执行 SQL 查询并在 Qt 的视图类(如 QTableView、QListView)中显示结果。
一、核心特点
-
只读性:默认是只读的,不能直接修改数据
-
轻量级:比 QSqlTableModel 更轻量,适合简单查询展示
-
灵活性:可以执行任意 SQL 查询
-
视图集成:与 Qt 的视图组件无缝集成
二、基本用法示例
#include <QApplication>
#include <QSqlDatabase>
#include <QSqlQueryModel>
#include <QTableView>
#include <QSqlQuery>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 建立数据库连接
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:"); // 内存数据库
if (!db.open()) {
qDebug() << "无法打开数据库";
return 1;
}
// 创建表并插入示例数据
QSqlQuery query;
query.exec("CREATE TABLE employees (id INT, name TEXT, salary REAL)");
query.exec("INSERT INTO employees VALUES (1, '张三', 5000.0)");
query.exec("INSERT INTO employees VALUES (2, '李四', 6000.0)");
// 创建模型并设置查询
QSqlQueryModel model;
model.setQuery("SELECT * FROM employees");
// 创建视图并设置模型
QTableView view;
view.setModel(&model);
view.show();
return app.exec();
}
三、常用方法详解
1. 设置查询
// 直接设置SQL语句
model.setQuery("SELECT name, salary FROM employees WHERE salary > 5500");
// 使用预编译查询
QSqlQuery preparedQuery;
preparedQuery.prepare("SELECT * FROM employees WHERE id = ?");
preparedQuery.addBindValue(employeeId);
model.setQuery(preparedQuery);
2. 访问数据
// 获取行数
int rowCount = model.rowCount();
// 获取列数
int columnCount = model.columnCount();
// 获取特定单元格数据
QString name = model.data(model.index(0, 1)).toString(); // 第一行第二列
3. 自定义显示
// 设置水平头标签
model.setHeaderData(0, Qt::Horizontal, tr("ID"));
model.setHeaderData(1, Qt::Horizontal, tr("姓名"));
model.setHeaderData(2, Qt::Horizontal, tr("薪水"));
// 自定义数据展示格式
QVariant QSqlQueryModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole && index.column() == 2) {
// 对薪水列进行格式化
return QString("¥%1").arg(QSqlQueryModel::data(index, role).toDouble());
}
return QSqlQueryModel::data(index, role);
}
四、高级用法
1. 自定义模型(使其可编辑)
class EditableSqlModel : public QSqlQueryModel
{
public:
Qt::ItemFlags flags(const QModelIndex &index) const override
{
Qt::ItemFlags flags = QSqlQueryModel::flags(index);
if (index.column() == 1 || index.column() == 2) // 使姓名和薪水可编辑
flags |= Qt::ItemIsEditable;
return flags;
}
bool setData(const QModelIndex &index, const QVariant &value, int role) override
{
if (index.column() < 1 || index.column() > 2)
return false;
QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), 0);
int id = data(primaryKeyIndex).toInt();
QString column;
if (index.column() == 1) column = "name";
else if (index.column() == 2) column = "salary";
QSqlQuery query;
query.prepare(QString("UPDATE employees SET %1 = ? WHERE id = ?").arg(column));
query.addBindValue(value);
query.addBindValue(id);
if (!query.exec())
return false;
refresh(); // 刷新数据
return true;
}
void refresh()
{
setQuery("SELECT * FROM employees");
}
};
2. 性能优化(大数据量)
// 使用批量获取数据
model.setQuery("SELECT * FROM large_table");
model.fetchMore(); // 当需要更多数据时
// 重写canFetchMore和fetchMore方法
bool canFetchMore(const QModelIndex &parent) const override
{
return currentRowCount < totalRowCount;
}
void fetchMore(const QModelIndex &parent) override
{
int remaining = totalRowCount - currentRowCount;
int itemsToFetch = qMin(100, remaining); // 每次获取100条
// 执行查询获取更多数据...
currentRowCount += itemsToFetch;
}
五、实际应用场景示例
1. 数据报表展示
// 复杂SQL查询生成报表
model.setQuery("SELECT department, COUNT(*) as count, AVG(salary) as avg_salary "
"FROM employees GROUP BY department ORDER BY avg_salary DESC");
2. 主从视图关联
// 主表模型
QSqlQueryModel departmentsModel;
departmentsModel.setQuery("SELECT id, name FROM departments");
// 从表模型(当主表选择变化时更新)
QSqlQueryModel employeesModel;
QObject::connect(departmentsView->selectionModel(), &QItemSelectionModel::currentRowChanged,
[&](const QModelIndex ¤t, const QModelIndex &previous) {
int deptId = departmentsModel.data(departmentsModel.index(current.row(), 0)).toInt();
employeesModel.setQuery(QString("SELECT name, position FROM employees WHERE dept_id = %1").arg(deptId));
});
六、注意事项
1.内存管理:大数据量查询可能导致内存问题,考虑分页或增量加载
2.错误处理:检查查询是否执行成功
if (model.lastError().isValid()) {
qDebug() << "查询错误:" << model.lastError().text();
}
3.线程安全:QSqlQueryModel 不是线程安全的,数据库操作应在同一线程
4.性能考虑:复杂查询可能影响UI响应,考虑在后台线程执行
总结
QSqlQueryModel 是 Qt 中连接数据库和UI的高效桥梁,特别适合展示复杂查询结果。虽然默认是只读的,但通过继承和重写方法可以实现编辑功能。对于简单的数据展示需求,它提供了快速开发的途径;对于复杂需求,它又提供了足够的灵活性进行扩展。