QT 5.12.10 自定义 QSqlTableModel:实现库存预警高亮(附完整代码)
2026/7/6 22:07:15 网站建设 项目流程

QT 5.12.10 深度定制 QSqlTableModel:实现智能库存预警与可视化交互

1. 现代库存管理系统的核心需求与QT解决方案

在当今快节奏的商业环境中,一个高效的库存管理系统已经成为企业运营不可或缺的神经中枢。传统的手工记录或基础电子表格早已无法满足现代企业对库存准确性、实时响应和智能预警的需求。QT框架凭借其强大的跨平台能力、丰富的UI组件库和灵活的Model/View架构,成为开发专业级库存管理系统的理想选择。

库存管理系统的核心痛点通常集中在几个关键方面:实时库存可视化、低库存预警、多维度数据分析和用户友好的交互界面。QT的Model/View框架完美解决了这些问题,特别是通过自定义QSqlTableModel,开发者可以轻松实现:

  • 实时数据绑定:数据库变更即时反映在界面
  • 智能预警系统:库存低于阈值自动高亮提示
  • 高性能渲染:即使处理万级数据也能保持流畅
  • 跨平台一致性:Windows、Linux、macOS统一体验
// 基础模型类继承关系 QObject └── QAbstractItemModel └── QAbstractTableModel └── QSqlQueryModel └── QSqlTableModel └── CustomSqlModel (我们的自定义类)

2. 自定义QSqlTableModel的架构设计

2.1 模型类的基本结构

我们首先构建一个继承自QSqlTableModel的自定义模型类,重写关键的data()和flags()方法来实现预警功能。以下是头文件的基本结构:

// customsqltablemodel.h #include <QSqlTableModel> #include <QColor> class CustomSqlTableModel : public QSqlTableModel { Q_OBJECT public: explicit CustomSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase()); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; void setWarningThreshold(int threshold); void setWarningColumn(int column); private: int warningThreshold = 0; int warningColumn = -1; QColor warningColor = QColor(255, 200, 200); // 浅红色背景 };

2.2 关键方法实现原理

data()方法是模型视图架构的核心,它根据不同的角色(role)返回不同的数据表现形式。我们需要特别处理Qt::BackgroundRole来改变单元格背景色:

QVariant CustomSqlTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); // 库存预警逻辑 if (role == Qt::BackgroundRole && warningColumn >= 0) { QModelIndex stockIndex = this->index(index.row(), warningColumn); int stockValue = QSqlTableModel::data(stockIndex, Qt::DisplayRole).toInt(); if (stockValue < warningThreshold) { return warningColor; } } // 默认数据处理 return QSqlTableModel::data(index, role); }

flags()方法控制每个单元格的交互属性,我们可以通过它实现只读或可编辑区域:

Qt::ItemFlags CustomSqlTableModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = QSqlTableModel::flags(index); // 示例:ID列设为只读 if (index.column() == 0) { flags &= ~Qt::ItemIsEditable; } return flags; }

3. 数据库设计与模型集成

3.1 SQLite表结构设计

合理的数据库设计是系统稳定性的基础。我们采用SQLite作为存储引擎,设计库存表结构如下:

CREATE TABLE inventory ( id INTEGER PRIMARY KEY AUTOINCREMENT, product_code TEXT NOT NULL UNIQUE, product_name TEXT NOT NULL, category TEXT, current_stock INTEGER DEFAULT 0, warning_threshold INTEGER DEFAULT 10, last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

3.2 模型与数据库的绑定

将自定义模型与数据库表关联只需几行代码:

// 初始化数据库连接 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("inventory.db"); if (!db.open()) { qCritical() << "Database connection error:" << db.lastError().text(); return; } // 创建并配置模型 CustomSqlTableModel *model = new CustomSqlTableModel(this, db); model->setTable("inventory"); model->setEditStrategy(QSqlTableModel::OnManualSubmit); model->select(); // 设置预警参数 model->setWarningColumn(4); // current_stock列 model->setWarningThreshold(10); // 绑定到视图 QTableView *view = new QTableView; view->setModel(model);

4. 高级功能实现技巧

4.1 动态阈值预警

在实际业务中,不同商品的库存预警阈值可能不同。我们可以扩展模型,支持从数据库读取每行的独立阈值:

QVariant CustomSqlTableModel::data(const QModelIndex &index, int role) const { // ... 其他逻辑 if (role == Qt::BackgroundRole && warningColumn >= 0) { QModelIndex stockIndex = this->index(index.row(), warningColumn); QModelIndex thresholdIndex = this->index(index.row(), warningColumn + 1); int stockValue = QSqlTableModel::data(stockIndex, Qt::DisplayRole).toInt(); int thresholdValue = QSqlTableModel::data(thresholdIndex, Qt::DisplayRole).toInt(); if (stockValue < thresholdValue) { return warningColor; } } // ... }

4.2 多级预警颜色

根据库存严重程度,我们可以实现颜色梯度预警:

if (stockValue < thresholdValue) { // 计算短缺比例 double ratio = static_cast<double>(stockValue) / thresholdValue; if (ratio < 0.2) return QColor(255, 100, 100); // 严重短缺 if (ratio < 0.5) return QColor(255, 150, 150); // 中度短缺 return QColor(255, 200, 200); // 轻微短缺 }

4.3 性能优化策略

处理大型库存表时,这些技巧可以显著提升性能:

  1. 按需加载数据
model->setFetchSize(100); // 每次只获取100行
  1. 批量提交更改
model->setEditStrategy(QSqlTableModel::OnManualSubmit); // ...多次修改后 model->submitAll();
  1. 智能数据刷新
// 只刷新可见区域 connect(view->verticalScrollBar(), &QScrollBar::valueChanged, [=](){ QModelIndex top = view->indexAt(QPoint(0, 0)); QModelIndex bottom = view->indexAt(QPoint(0, view->height())); model->fetchMore(bottom); });

5. 完整示例代码实现

5.1 自定义模型类实现

// customsqltablemodel.cpp #include "customsqltablemodel.h" CustomSqlTableModel::CustomSqlTableModel(QObject *parent, QSqlDatabase db) : QSqlTableModel(parent, db) {} void CustomSqlTableModel::setWarningThreshold(int threshold) { warningThreshold = threshold; } void CustomSqlTableModel::setWarningColumn(int column) { warningColumn = column; } QVariant CustomSqlTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); // 库存预警逻辑 if (role == Qt::BackgroundRole && warningColumn >= 0) { QModelIndex stockIndex = this->index(index.row(), warningColumn); int stockValue = QSqlTableModel::data(stockIndex, Qt::DisplayRole).toInt(); if (stockValue < warningThreshold) { // 多级颜色预警 double ratio = static_cast<double>(stockValue) / warningThreshold; if (ratio < 0.2) return QColor(255, 100, 100); if (ratio < 0.5) return QColor(255, 150, 150); return QColor(255, 200, 200); } } // 文本对齐 if (role == Qt::TextAlignmentRole && index.column() >= 4) { return Qt::AlignRight + Qt::AlignVCenter; } return QSqlTableModel::data(index, role); } Qt::ItemFlags CustomSqlTableModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = QSqlTableModel::flags(index); // ID列和预警阈值列设为只读 if (index.column() == 0 || index.column() == 5) { flags &= ~Qt::ItemIsEditable; } return flags; }

5.2 主窗口集成

// mainwindow.cpp #include "mainwindow.h" #include "customsqltablemodel.h" #include <QTableView> #include <QHeaderView> #include <QSqlError> #include <QDebug> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setupDatabase(); setupUI(); } void MainWindow::setupDatabase() { db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("inventory.db"); if (!db.open()) { qCritical() << "Database error:" << db.lastError().text(); return; } // 创建示例表(如果不存在) QSqlQuery query; query.exec("CREATE TABLE IF NOT EXISTS inventory (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "product_code TEXT NOT NULL UNIQUE, " "product_name TEXT NOT NULL, " "category TEXT, " "current_stock INTEGER DEFAULT 0, " "warning_threshold INTEGER DEFAULT 10, " "last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"); // 插入示例数据 query.exec("INSERT OR IGNORE INTO inventory (product_code, product_name, " "category, current_stock, warning_threshold) VALUES " "('P1001', '高端显卡', '电脑配件', 5, 8), " "('P1002', '机械键盘', '外设', 15, 10), " "('P1003', '无线鼠标', '外设', 3, 5)"); } void MainWindow::setupUI() { // 创建模型 model = new CustomSqlTableModel(this, db); model->setTable("inventory"); model->setEditStrategy(QSqlTableModel::OnManualSubmit); model->select(); // 设置预警列和阈值 model->setWarningColumn(4); // current_stock列 model->setWarningThresholdColumn(5); // 从每行读取独立阈值 // 创建视图 tableView = new QTableView; tableView->setModel(model); tableView->setSelectionMode(QAbstractItemView::SingleSelection); tableView->setSelectionBehavior(QAbstractItemView::SelectRows); tableView->resizeColumnsToContents(); tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); // 设置列宽策略 tableView->setColumnWidth(1, 120); // product_code tableView->setColumnWidth(2, 200); // product_name tableView->horizontalHeader()->setStretchLastSection(true); setCentralWidget(tableView); resize(800, 600); }

6. 扩展功能与业务集成

6.1 库存预警信号机制

我们可以扩展模型,当库存状态变化时发出信号:

// 在头文件中添加信号声明 signals: void stockWarning(int productId, const QString &productName, int current, int threshold); // 修改data()方法 QVariant CustomSqlTableModel::data(const QModelIndex &index, int role) const { // ... if (role == Qt::BackgroundRole && warningColumn >= 0) { // ...预警逻辑 if (stockValue < thresholdValue) { emit stockWarning(id, productName, stockValue, thresholdValue); // ... } } // ... }

6.2 与QT Charts集成实现可视化

结合QT Charts模块,我们可以创建直观的库存分析图表:

#include <QtCharts> void MainWindow::createStockChart() { QChart *chart = new QChart; // 获取低库存商品 QSqlQuery query("SELECT product_name, current_stock, warning_threshold " "FROM inventory WHERE current_stock < warning_threshold"); QBarSeries *series = new QBarSeries; while (query.next()) { QString name = query.value(0).toString(); int stock = query.value(1).toInt(); int threshold = query.value(2).toInt(); QBarSet *set = new QBarSet(name); *set << stock << threshold; series->append(set); } chart->addSeries(series); chart->setTitle("低库存商品预警"); // 设置坐标轴 QBarCategoryAxis *axisX = new QBarCategoryAxis; axisX->append({"当前库存", "预警阈值"}); chart->addAxis(axisX, Qt::AlignBottom); series->attachAxis(axisX); QValueAxis *axisY = new QValueAxis; chart->addAxis(axisY, Qt::AlignLeft); series->attachAxis(axisY); // 显示图表 QChartView *chartView = new QChartView(chart); chartView->setRenderHint(QPainter::Antialiasing); chartView->resize(600, 400); chartView->show(); }

6.3 多线程数据加载

对于大型库存数据库,使用多线程加载数据可以避免界面冻结:

// 工作线程类 class DataLoader : public QThread { Q_OBJECT public: explicit DataLoader(QSqlDatabase db, QObject *parent = nullptr) : QThread(parent), db(db) {} void run() override { QSqlQuery query(db); query.exec("SELECT * FROM inventory"); QVector<InventoryItem> items; while (query.next()) { InventoryItem item; item.id = query.value(0).toInt(); // ...填充其他字段 items.append(item); } emit dataLoaded(items); } signals: void dataLoaded(const QVector<InventoryItem> &items); private: QSqlDatabase db; }; // 在主窗口中使用 void MainWindow::loadDataAsync() { DataLoader *loader = new DataLoader(db, this); connect(loader, &DataLoader::dataLoaded, this, &MainWindow::updateModel); connect(loader, &DataLoader::finished, loader, &QObject::deleteLater); loader->start(); }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询