一:【工程项目】运行结果

 1:生成测试数据

图片

图片

2:添加软件项目

图片

图片

3:修改软件项目(扈三娘 更改为 vico)

图片

图片

剩余各项功能不在全部演示出来,大家自己去测试!!!

二:【工程项目】使用技术栈

1:项目简介

本项目是一个专为软件公司设计的项目信息管理系统,能够高效管理大量项目数据。系统采用现代化的Qt6框架开发,具备高性能分页显示、智能搜索、数据导出等核心功能,特别针对大数据量场景进行了优化。

2:使用技术栈

  • Qt 6.5.3:跨平台GUI框架

  • C++17:现代C++标准

  • SQLite 3:轻量级数据库

  • QSql:Qt数据库模块

开发工具:

  • Qt Creator:集成开发环境

  • MinGW 64-bit:编译器

CMake/qmake:构建系统

三:【工程项目】源码分析

1:mainwindow.h文件--源码注释

#ifndef MAINWINDOW_H#define MAINWINDOW_H#include <QMainWindow>#include <QStandardItemModel>#include <QItemSelection>#include <QCalendarWidget>#include <QDialogButtonBox>#include <QLineEdit>#include <QComboBox>#include <QPushButton>#include <QLabel>#include <QProgressBar>#include <QThread>#include <QTimer>#include <QCloseEvent>QT_BEGIN_NAMESPACEclass QTableView;class QToolBar;class QAction;class QLabel;class QLineEdit;class QComboBox;class QPushButton;class QProgressBar;class QThread;class QTimer;QT_END_NAMESPACEclass DatabaseManager;class SimpleDialog;class SimplePaginationModel;class PaginationController;// 数据生成工作线程class DataGenerationWorker : public QObject{    Q_OBJECTpublic:    explicit DataGenerationWorker(QObject *parent = nullptr);    void stopGeneration();public slots:    void generateTestData(int totalRecords);signals:    void progressUpdated(int current, int total, double rate);    void generationCompleted(int totalRecords, int totalTime);    void generationFailed(const QString &error);private:    void generateBatchData(int startIndex, int batchSize, const QStringList &projectNames,                           const QStringList &managerNames, const QStringList &statuses,                           const QStringList &descriptions);    void saveProgress(int currentCount, int totalCount);    int loadProgress();    volatile bool m_shouldStop;};class MainWindow : public QMainWindow{    Q_OBJECTpublic:    explicit MainWindow(QWidget *parent = nullptr);    ~MainWindow();private slots:    void onAddProject();    void onDeleteProject();    void onEditProject();    void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);    void onSearch();    void onClearSearch();    void onRefreshData();    void onGenerateTestData();    void onDataGenerationProgress(int current, int total, double rate);    void onDataGenerationCompleted(int totalRecords, int totalTime);    void onDataGenerationFailed(const QString &error);    void onDataLoadingFinished();  // 数据加载完成后的处理    void onExportCSV();  // 导出CSV功能protected:    void resizeEvent(QResizeEvent *event) override;    void closeEvent(QCloseEvent *event) override;private:    void setupModel();    void setupViews();    void createToolbar();    void createSearchBar();    void createStatusBar();    void loadDataFromDatabase();    QDate getDateFromDialog(const QString &title, const QString &label, const QDate &defaultDate);    void updateStatusBar();    void adjustColumnWidths();    QString generateUniqueProjectId();    void highlightNewRecord();    QStandardItemModel *model;    SimplePaginationModel *paginationModel;    QTableView *tableView;    PaginationController *paginationController;    QLineEdit *searchLineEdit;    QComboBox *searchComboBox;    QPushButton *searchButton;    QPushButton *clearButton;    QLabel *statusLabel;    QProgressBar *progressBar;    DatabaseManager *dbManager;    int currentSelectedRow = -1;    bool isSearchMode = false;    bool usePagination = true;    bool shouldSelectNewRecord = false;  // 标记是否需要选中新添加的记录    bool shouldSelectEditedRecord = false;  // 标记是否需要选中编辑后的记录    int editedRecordRow = -1;  // 编辑后需要选中的行号    // 数据生成相关    QThread *dataGenerationThread;    DataGenerationWorker *dataGenerationWorker;    QTimer *progressUpdateTimer;};#endif // MAINWINDOW_H

2:mainwindow.cpp文件--源码注释

#include "mainwindow.h"#include "databasemanager.h"#include "simpledialog.h"#include "simplepaginationmodel.h"#include "paginationcontroller.h"#include <QTableView>#include <QToolBar>#include <QAction>#include <QVBoxLayout>#include <QHBoxLayout>#include <QMessageBox>#include <QInputDialog>#include <QDate>#include <QDateTime>#include <QTime>#include <QRandomGenerator>#include <QMetaObject>#include <QThread>#include <QTimer>#include <QHeaderView>#include <QDialog>#include <QCalendarWidget>#include <QDialogButtonBox>#include <QLabel>#include <QLineEdit>#include <QComboBox>#include <QPushButton>#include <QProgressBar>#include <QStatusBar>#include <QApplication>#include <QTimer>#include <QResizeEvent>#include <QSqlQuery>#include <QFile>#include <QTextStream>#include <QThread>#include <QFileDialog>#include <QStandardPaths>#include <QEventLoop>#include <QStringConverter>MainWindow::MainWindow(QWidget *parent)    : QMainWindow(parent), model(new QStandardItemModel(this)), tableView(new QTableView(this)){    // 设置窗口属性    setWindowTitle("承载千万级数据存储--软件项目管理 v3.0");    resize(1400, 900);  // 增大窗口尺寸以更好地显示表格    // 初始化数据库管理器    dbManager = &DatabaseManager::getInstance();    // 初始化分页模型    paginationModel = new SimplePaginationModel(this);    paginationController = new PaginationController(this);    // 初始化数据生成工作线程    dataGenerationThread = new QThread(this);    dataGenerationWorker = new DataGenerationWorker(); // 不设置父对象,因为要移动到其他线程    dataGenerationWorker->moveToThread(dataGenerationThread);    // 连接工作线程信号    connect(dataGenerationWorker, &DataGenerationWorker::progressUpdated,            this, &MainWindow::onDataGenerationProgress);    connect(dataGenerationWorker, &DataGenerationWorker::generationCompleted,            this, &MainWindow::onDataGenerationCompleted);    connect(dataGenerationWorker, &DataGenerationWorker::generationFailed,            this, &MainWindow::onDataGenerationFailed);    // 启动工作线程    dataGenerationThread->start();    // 初始化模型和视图    setupModel();    setupViews();    createToolbar();    createSearchBar();    createStatusBar();    // 延迟加载数据,让界面先显示出来    QTimer::singleShot(100, this, &MainWindow::loadDataFromDatabase);}MainWindow::~MainWindow(){    // 停止数据生成    if (dataGenerationWorker) {        dataGenerationWorker->stopGeneration();    }    // 正确清理工作线程    if (dataGenerationThread && dataGenerationThread->isRunning()) {        // 请求线程退出        dataGenerationThread->quit();        // 等待线程结束(最多等待3秒)        if (!dataGenerationThread->wait(3000)) {            // 如果线程没有在3秒内结束,强制终止            qDebug() << "强制终止工作线程";            dataGenerationThread->terminate();            dataGenerationThread->wait();        }    }    // 删除工作线程对象(先删除worker,再删除thread)    if (dataGenerationWorker) {        dataGenerationWorker->deleteLater();        dataGenerationWorker = nullptr;    }    // 删除线程对象    if (dataGenerationThread) {        dataGenerationThread->deleteLater();        dataGenerationThread = nullptr;    }}void MainWindow::closeEvent(QCloseEvent *event){    // 停止数据生成    if (dataGenerationWorker) {        dataGenerationWorker->stopGeneration();    }    // 等待工作线程结束    if (dataGenerationThread && dataGenerationThread->isRunning()) {        dataGenerationThread->quit();        if (!dataGenerationThread->wait(2000)) {            // 如果2秒内没有结束,强制终止            dataGenerationThread->terminate();            dataGenerationThread->wait();        }    }    // 接受关闭事件    event->accept();}void MainWindow::setupModel(){    // 设置表头    QStringList headers;    headers << "项目ID" << "项目名称" << "项目经理" << "开始日期"            << "结束日期" << "预算(万元)" << "状态" << "描述";    model->setHorizontalHeaderLabels(headers);}void MainWindow::setupViews(){    // 设置表格视图属性    if (usePagination) {        tableView->setModel(paginationModel);    } else {        tableView->setModel(model);    }    tableView->setSelectionMode(QAbstractItemView::SingleSelection);    tableView->setSelectionBehavior(QAbstractItemView::SelectRows);    tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);    // 显示行号,不隐藏左侧编号    tableView->verticalHeader()->setVisible(true);    tableView->verticalHeader()->setDefaultSectionSize(25);    // 设置列宽 - 让表格填充满整个窗口    tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);  // 项目ID - 固定宽度    tableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);          // 项目名称 - 拉伸填充    tableView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents); // 项目经理 - 固定宽度    tableView->horizontalHeader()->setSectionResizeMode(3, QHeaderView::ResizeToContents); // 开始日期 - 固定宽度    tableView->horizontalHeader()->setSectionResizeMode(4, QHeaderView::ResizeToContents); // 结束日期 - 固定宽度    tableView->horizontalHeader()->setSectionResizeMode(5, QHeaderView::ResizeToContents); // 预算 - 固定宽度    tableView->horizontalHeader()->setSectionResizeMode(6, QHeaderView::ResizeToContents); // 状态 - 固定宽度    tableView->horizontalHeader()->setSectionResizeMode(7, QHeaderView::Stretch);          // 描述 - 拉伸填充    // 设置表格样式    tableView->setAlternatingRowColors(true);  // 交替行颜色    tableView->setGridStyle(Qt::SolidLine);    // 网格线样式    tableView->setShowGrid(true);              // 显示网格线    tableView->setSortingEnabled(true);        // 启用排序    // 连接选择变化信号    connect(tableView->selectionModel(), &QItemSelectionModel::selectionChanged,            this, &MainWindow::onSelectionChanged);    // 连接分页控制器信号    if (usePagination) {        connect(paginationController, &PaginationController::pageChanged,                paginationModel, &SimplePaginationModel::setCurrentPage);        connect(paginationController, &PaginationController::pageSizeChanged,                paginationModel, &SimplePaginationModel::setPageSize);        connect(paginationController, &PaginationController::refreshRequested,                paginationModel, &SimplePaginationModel::refreshData);        connect(paginationModel, &SimplePaginationModel::pageChanged,                paginationController, &PaginationController::setCurrentPage);        connect(paginationModel, &SimplePaginationModel::totalRecordsChanged,                paginationController, &PaginationController::setTotalRecords);        // 连接pageChanged信号来更新总页数        connect(paginationModel, &SimplePaginationModel::pageChanged,                [this](int /*currentPage*/, int totalPages) {                    paginationController->setTotalPages(totalPages);                });        connect(paginationModel, &SimplePaginationModel::dataLoadingStarted,                [this]() { paginationController->setLoading(true); });        connect(paginationModel, &SimplePaginationModel::dataLoadingFinished,                [this]() {                    paginationController->setLoading(false);                    onDataLoadingFinished();  // 数据加载完成后处理选中逻辑                });    }    // 设置中心部件 - 让表格填充满整个窗口    QWidget *centralWidget = new QWidget(this);    QVBoxLayout *layout = new QVBoxLayout(centralWidget);    layout->setContentsMargins(0, 0, 0, 0);  // 移除边距    layout->addWidget(tableView);    // 添加分页控制器    if (usePagination) {        layout->addWidget(paginationController);    }    centralWidget->setLayout(layout);    setCentralWidget(centralWidget);}void MainWindow::createToolbar(){    QToolBar *toolBar = addToolBar("操作");    QAction *addAction = new QAction(QIcon(":/new/prefix1/images/add001.ico"), "添加项目", this);    QAction *deleteAction = new QAction(QIcon(":/new/prefix1/images/delete001.ico"), "删除项目", this);    QAction *editAction = new QAction(QIcon(":/new/prefix1/images/edit001.ico"), "编辑项目", this);    QAction *refreshAction = new QAction("刷新系统数据", this);    QAction *generateTestDataAction = new QAction("生成测试数据", this);    QAction *exportCSVAction = new QAction("导出数据(CSV格式)", this);    // 设置工具按钮样式    addAction->setShortcut(QKeySequence::New);    deleteAction->setShortcut(QKeySequence::Delete);    editAction->setShortcut(Qt::Key_Return);    refreshAction->setShortcut(QKeySequence::Refresh);    exportCSVAction->setShortcut(QKeySequence::SaveAs);    toolBar->addAction(addAction);    toolBar->addAction(deleteAction);    toolBar->addAction(editAction);    toolBar->addSeparator();    toolBar->addAction(refreshAction);    toolBar->addAction(generateTestDataAction);    toolBar->addAction(exportCSVAction);    // 连接信号槽    connect(addAction, &QAction::triggered, this, &MainWindow::onAddProject);    connect(deleteAction, &QAction::triggered, this, &MainWindow::onDeleteProject);    connect(editAction, &QAction::triggered, this, &MainWindow::onEditProject);    connect(refreshAction, &QAction::triggered, this, &MainWindow::onRefreshData);    connect(generateTestDataAction, &QAction::triggered, this, &MainWindow::onGenerateTestData);    connect(exportCSVAction, &QAction::triggered, this, &MainWindow::onExportCSV);}void MainWindow::createSearchBar(){    QWidget *searchWidget = new QWidget();    QHBoxLayout *searchLayout = new QHBoxLayout(searchWidget);    searchLineEdit = new QLineEdit();    searchLineEdit->setPlaceholderText("输入搜索关键词...");    searchLineEdit->setMaximumWidth(200);    searchComboBox = new QComboBox();    searchComboBox->addItems({"全部", "项目名称", "项目经理", "状态", "项目ID"});    searchComboBox->setMaximumWidth(100);    searchButton = new QPushButton("搜索");    clearButton = new QPushButton("清除");    searchLayout->addWidget(new QLabel("搜索:"));    searchLayout->addWidget(searchLineEdit);    searchLayout->addWidget(searchComboBox);    searchLayout->addWidget(searchButton);    searchLayout->addWidget(clearButton);    searchLayout->addStretch();    // 添加到工具栏    QToolBar *searchToolBar = addToolBar("搜索");    searchToolBar->addWidget(searchWidget);    // 连接信号槽    connect(searchButton, &QPushButton::clicked, this, &MainWindow::onSearch);    connect(clearButton, &QPushButton::clicked, this, &MainWindow::onClearSearch);    connect(searchLineEdit, &QLineEdit::returnPressed, this, &MainWindow::onSearch);}void MainWindow::createStatusBar(){    statusLabel = new QLabel("就绪");    progressBar = new QProgressBar();    progressBar->setVisible(false);    progressBar->setMaximumWidth(200);    statusBar()->addWidget(statusLabel);    statusBar()->addPermanentWidget(progressBar);}void MainWindow::loadDataFromDatabase(){    if (!dbManager->isConnected()) {        QMessageBox::critical(this, "错误", "数据库连接失败: " + dbManager->getLastError());        return;    }    // 设置进度条为确定模式,总共100步    progressBar->setVisible(true);    progressBar->setRange(0, 100);    progressBar->setValue(0);    statusLabel->setText("正在初始化高性能数据模型... (0%)");    QApplication::processEvents();    // 步骤1: 检查数据库连接 (10%)    progressBar->setValue(10);    statusLabel->setText("检查数据库连接... (10%)");    QApplication::processEvents();    QThread::msleep(50); // 短暂延迟让用户看到进度    // 步骤2: 检查数据量 (20%)    progressBar->setValue(20);    statusLabel->setText("检查数据量... (20%)");    QApplication::processEvents();    QThread::msleep(50);    int totalRecords = dbManager->getProjectCount();    if (totalRecords > 10000) {        usePagination = true; // 大数据量强制使用分页模式        qDebug() << "检测到大量数据(" << totalRecords << "条),自动启用分页模式";    }    // 步骤3: 选择显示模式 (30%)    progressBar->setValue(30);    statusLabel->setText("选择显示模式... (30%)");    QApplication::processEvents();    QThread::msleep(50);    if (usePagination) {        // 步骤4: 初始化分页模型 (40%)        progressBar->setValue(40);        statusLabel->setText("初始化分页模型... (40%)");        QApplication::processEvents();        QThread::msleep(50);        // 步骤5: 设置数据库连接 (50%)        progressBar->setValue(50);        statusLabel->setText("设置数据库连接... (50%)");        QApplication::processEvents();        QThread::msleep(50);        paginationModel->setDatabase(dbManager->getDatabase());        paginationModel->setPageSize(100); // 每页100条记录        paginationModel->setCacheSize(20); // 设置缓存20页,提高分页响应速度                // 确保分页控制器的页面大小与模型一致        paginationController->setPageSize(100);        // 步骤6: 计算总记录数 (60%)        progressBar->setValue(60);        statusLabel->setText("计算总记录数... (60%)");        QApplication::processEvents();        QThread::msleep(50);        // 步骤7: 准备分页数据 (70%)        progressBar->setValue(70);        statusLabel->setText("准备分页数据... (70%)");        QApplication::processEvents();        QThread::msleep(50);        // 步骤8: 准备加载第一页数据 (80%)        progressBar->setValue(80);        statusLabel->setText("准备加载第一页数据... (80%)");        QApplication::processEvents();        QThread::msleep(50);        // 步骤9: 启动分页数据加载 (90%)        progressBar->setValue(90);        statusLabel->setText("启动分页数据加载... (90%)");        QApplication::processEvents();        QThread::msleep(50);        // 步骤10: 完成初始化 (100%)        progressBar->setValue(100);        statusLabel->setText(QString("高性能分页模式已启用 (共%1条记录)").arg(totalRecords));        QApplication::processEvents();        QThread::msleep(100);        // 异步启动分页数据加载,避免阻塞UI        QTimer::singleShot(500, this, [this]() {            paginationModel->refreshData();        });    } else {        // 使用传统模型        progressBar->setValue(40);        statusLabel->setText("使用传统模式加载数据... (40%)");        QApplication::processEvents();        QThread::msleep(50);        progressBar->setValue(60);        statusLabel->setText("加载项目数据... (60%)");        QApplication::processEvents();        QThread::msleep(50);        if (dbManager->loadProjects(model)) {            progressBar->setValue(80);            statusLabel->setText("更新状态栏... (80%)");            QApplication::processEvents();            QThread::msleep(50);            updateStatusBar();            progressBar->setValue(100);            statusLabel->setText("数据加载完成 (100%)");            QApplication::processEvents();            QThread::msleep(100);            // 调整列宽以填充满表格            QTimer::singleShot(100, this, &MainWindow::adjustColumnWidths);        } else {            progressBar->setValue(100);            QMessageBox::critical(this, "错误", "加载数据失败: " + dbManager->getLastError());            statusLabel->setText("数据加载失败");        }    }    // 延迟隐藏进度条,让用户看到100%完成状态    QTimer::singleShot(1000, this, [this]() {        progressBar->setVisible(false);    });}void MainWindow::updateStatusBar(){    int totalProjects = dbManager->getProjectCount();    double totalBudget = dbManager->getTotalBudget();    QStringList statusStats = dbManager->getProjectStatusStats();    QString statusText = QString("总项目数: %1 | 总预算: %2万元 | %3")                             .arg(totalProjects)                             .arg(totalBudget, 0, 'f', 2)                             .arg(statusStats.join(" | "));    statusLabel->setText(statusText);}void MainWindow::adjustColumnWidths(){    // 获取表格的可用宽度    int tableWidth = tableView->width();    int availableWidth = tableWidth - 20; // 留出一些边距    // 计算固定宽度列的总宽度    int fixedWidth = 0;    fixedWidth += 80;  // 项目ID    fixedWidth += 100; // 项目经理    fixedWidth += 100; // 开始日期    fixedWidth += 100; // 结束日期    fixedWidth += 100; // 预算    fixedWidth += 80;  // 状态    // 计算可拉伸列的宽度    int stretchWidth = (availableWidth - fixedWidth) / 2; // 项目名称和描述各占一半    // 设置列宽    tableView->setColumnWidth(0, 80);   // 项目ID    tableView->setColumnWidth(1, stretchWidth);  // 项目名称    tableView->setColumnWidth(2, 100);  // 项目经理    tableView->setColumnWidth(3, 100);  // 开始日期    tableView->setColumnWidth(4, 100);  // 结束日期    tableView->setColumnWidth(5, 100);  // 预算    tableView->setColumnWidth(6, 80);   // 状态    tableView->setColumnWidth(7, stretchWidth);  // 描述}void MainWindow::onSearch(){    QString keyword = searchLineEdit->text().trimmed();    if (keyword.isEmpty()) {        QMessageBox::information(this, "提示", "请输入搜索关键词");        return;    }    QString filterType = "all";    switch (searchComboBox->currentIndex()) {    case 0: filterType = "all"; break;    case 1: filterType = "name"; break;    case 2: filterType = "manager"; break;    case 3: filterType = "status"; break;    case 4: filterType = "id"; break;    }    progressBar->setVisible(true);    progressBar->setRange(0, 0);    statusLabel->setText("正在搜索...");    QApplication::processEvents();    if (usePagination) {        // 使用分页模型搜索        paginationModel->setSearchFilter(keyword, filterType);        statusLabel->setText(QString("搜索完成,关键词: %1").arg(keyword));    } else {        // 使用传统搜索        QStandardItemModel* searchModel = dbManager->searchProjects(keyword, filterType);        if (searchModel) {            // 保存原始模型            if (!isSearchMode) {                // 这里可以保存原始模型的引用            }            // 设置搜索结果模型            tableView->setModel(searchModel);            isSearchMode = true;            statusLabel->setText(QString("搜索完成,找到 %1 条结果").arg(searchModel->rowCount()));        } else {            QMessageBox::warning(this, "搜索失败", dbManager->getLastError());            statusLabel->setText("搜索失败");        }    }    progressBar->setVisible(false);}void MainWindow::onClearSearch(){    if (usePagination) {        // 使用分页模型清除搜索        paginationModel->clearSearchFilter();        searchLineEdit->clear();        searchComboBox->setCurrentIndex(0);        statusLabel->setText("已清除搜索");    } else if (isSearchMode) {        loadDataFromDatabase();        isSearchMode = false;        searchLineEdit->clear();        searchComboBox->setCurrentIndex(0);        statusLabel->setText("已清除搜索");    }}void MainWindow::onRefreshData(){    if (usePagination) {        // 使用分页模型刷新        paginationModel->refreshData();        searchLineEdit->clear();        searchComboBox->setCurrentIndex(0);        statusLabel->setText("数据已刷新");    } else {        loadDataFromDatabase();        isSearchMode = false;        searchLineEdit->clear();        searchComboBox->setCurrentIndex(0);    }}QDate MainWindow::getDateFromDialog(const QString &title, const QString &label, const QDate &defaultDate){    QDialog dialog(this);    dialog.setWindowTitle(title);    QCalendarWidget *calendar = new QCalendarWidget(&dialog);    calendar->setSelectedDate(defaultDate);    QDialogButtonBox *buttons = new QDialogButtonBox(        QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);    QVBoxLayout *layout = new QVBoxLayout(&dialog);    layout->addWidget(new QLabel(label));    layout->addWidget(calendar);    layout->addWidget(buttons);    connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);    connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);    if (dialog.exec() == QDialog::Accepted) {        return calendar->selectedDate();    }    return QDate();}void MainWindow::onAddProject(){    SimpleDialog dialog(this);    dialog.setEditMode(false);    // 生成唯一的项目ID    QString newId = generateUniqueProjectId();    // 设置项目ID    QStringList initialData;    initialData << newId << "" << "" << "" << "" << "" << "" << "";    dialog.setProjectData(initialData);    if (dialog.exec() == QDialog::Accepted) {        QStringList projectData = dialog.getProjectData();        // 添加到数据库        if (dbManager->addProject(projectData)) {            qDebug() << "项目添加成功,开始刷新数据...";            // 设置标记,表示需要在数据加载完成后选中新记录            shouldSelectNewRecord = true;            // 刷新数据            if (usePagination) {                qDebug() << "使用分页模式刷新数据";                // 确保跳转到第一页显示新记录                paginationModel->setCurrentPage(1);                paginationModel->refreshData();                // 高亮显示新添加的记录(第一行)                paginationModel->setHighlightedRow(0);                // 3秒后清除高亮                QTimer::singleShot(3000, paginationModel, &SimplePaginationModel::clearHighlight);            } else {                qDebug() << "使用非分页模式刷新数据";                loadDataFromDatabase();                highlightNewRecord();                // 非分页模式立即选中新记录                if (tableView->model() && tableView->model()->rowCount() > 0) {                    qDebug() << "非分页模式:立即选中新添加的记录,行号: 0";                    tableView->selectRow(0);                    currentSelectedRow = 0;                    tableView->setFocus();                    tableView->scrollToTop();                }            }            qDebug() << "数据刷新完成";            QMessageBox::information(this, "成功", QString("项目 %1 添加成功!").arg(newId));        } else {            QMessageBox::critical(this, "错误", "添加项目失败: " + dbManager->getLastError());        }    }}void MainWindow::onDeleteProject(){    if (currentSelectedRow == -1) {        QMessageBox::warning(this, "警告", "请先选择要删除的项目!");        return;    }    QString projectId;    QString projectName;    // 根据模式获取项目信息    if (usePagination) {        // 分页模式:从分页模型获取数据        QModelIndex idIndex = paginationModel->index(currentSelectedRow, 0);        QModelIndex nameIndex = paginationModel->index(currentSelectedRow, 1);        projectId = paginationModel->data(idIndex, Qt::DisplayRole).toString();        projectName = paginationModel->data(nameIndex, Qt::DisplayRole).toString();    } else {        // 非分页模式:从标准模型获取数据        projectId = model->item(currentSelectedRow, 0)->text();        projectName = model->item(currentSelectedRow, 1)->text();    }    int ret = QMessageBox::question(this, "确认删除",                                    QString("确定要删除项目:\n\n%1 - %2\n\n此操作不可撤销!").arg(projectId).arg(projectName),                                    QMessageBox::Yes | QMessageBox::No);    if (ret == QMessageBox::Yes) {        // 使用项目ID删除,而不是行号        if (dbManager->deleteProjectById(projectId)) {            qDebug() << "项目删除成功,开始刷新数据...";            // 刷新数据            if (usePagination) {                qDebug() << "使用分页模式刷新数据";                paginationModel->refreshData();            } else {                qDebug() << "使用非分页模式刷新数据";                loadDataFromDatabase();            }            currentSelectedRow = -1;            qDebug() << "数据刷新完成";            QMessageBox::information(this, "成功", "项目已删除");        } else {            QMessageBox::critical(this, "错误", "删除项目失败: " + dbManager->getLastError());        }    }}void MainWindow::onEditProject(){    if (currentSelectedRow == -1) {        QMessageBox::warning(this, "警告", "请先选择要编辑的项目!");        return;    }    // 获取当前项目数据    QStringList currentData;    // 根据模式获取项目数据    if (usePagination) {        // 分页模式:从分页模型获取数据        for (int i = 0; i < 8; ++i) {            QModelIndex index = paginationModel->index(currentSelectedRow, i);            QString data = paginationModel->data(index, Qt::DisplayRole).toString();            currentData << data;        }    } else {        // 非分页模式:从标准模型获取数据        for (int i = 0; i < 8; ++i) {            QStandardItem *item = model->item(currentSelectedRow, i);            if (item) {                currentData << item->text();            } else {                currentData << "";            }        }    }    SimpleDialog dialog(this);    dialog.setEditMode(true);    dialog.setProjectData(currentData);    if (dialog.exec() == QDialog::Accepted) {        QStringList projectData = dialog.getProjectData();        // 获取项目ID用于更新        QString projectId = currentData[0]; // 项目ID在第一列        // 更新数据库        if (dbManager->updateProjectById(projectId, projectData)) {            qDebug() << "项目更新成功,开始刷新数据...";            // 保存当前选中的行号            int selectedRow = currentSelectedRow;            // 设置标记,表示需要在数据加载完成后选中编辑后的记录            shouldSelectEditedRecord = true;            editedRecordRow = selectedRow;            // 刷新数据            if (usePagination) {                qDebug() << "使用分页模式刷新数据";                paginationModel->refreshData();            } else {                qDebug() << "使用非分页模式刷新数据";                loadDataFromDatabase();                // 非分页模式立即选中编辑后的记录                if (tableView->model() && tableView->model()->rowCount() > 0 &&                    selectedRow >= 0 && selectedRow < tableView->model()->rowCount()) {                    qDebug() << "非分页模式:立即选中编辑后的记录,行号:" << selectedRow;                    tableView->selectRow(selectedRow);                    currentSelectedRow = selectedRow;                    tableView->setFocus();                    tableView->scrollTo(tableView->model()->index(selectedRow, 0));                }            }            qDebug() << "数据刷新完成";            QMessageBox::information(this, "成功", QString("项目 %1 更新成功!").arg(projectData[0]));        } else {            QMessageBox::critical(this, "错误", "更新项目失败: " + dbManager->getLastError());        }    }}void MainWindow::onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected){    Q_UNUSED(deselected);    if (selected.indexes().isEmpty()) {        currentSelectedRow = -1;    } else {        currentSelectedRow = selected.indexes().first().row();    }}void MainWindow::resizeEvent(QResizeEvent *event){    QMainWindow::resizeEvent(event);    // 延迟调整列宽,确保表格已经完成大小调整    QTimer::singleShot(50, this, &MainWindow::adjustColumnWidths);}QString MainWindow::generateUniqueProjectId(){    if (!dbManager->isConnected()) {        return "PRJ001";    }    // 查询数据库中最大的项目ID    QSqlQuery query("SELECT MAX(CAST(SUBSTR(project_id, 4) AS INTEGER)) FROM projects", *dbManager->getDatabase());    int maxId = 0;    if (query.exec() && query.next()) {        maxId = query.value(0).toInt();    }    // 生成新的唯一ID    QString newId;    int attempts = 0;    do {        maxId++;        newId = QString("PRJ%1").arg(maxId, 3, 10, QLatin1Char('0'));        // 检查ID是否已存在        QSqlQuery checkQuery("SELECT COUNT(*) FROM projects WHERE project_id = ?", *dbManager->getDatabase());        checkQuery.bindValue(0, newId);        if (checkQuery.exec() && checkQuery.next()) {            if (checkQuery.value(0).toInt() == 0) {                break; // ID不存在,可以使用            }        }        attempts++;    } while (attempts < 1000); // 防止无限循环    return newId;}void MainWindow::highlightNewRecord(){    if (!usePagination && model->rowCount() > 0) {        // 为非分页模式设置第一行高亮        for (int col = 0; col < model->columnCount(); ++col) {            QStandardItem *item = model->item(0, col);            if (item) {                item->setBackground(QColor(173, 216, 230)); // 浅蓝色背景                item->setForeground(QColor(0, 0, 139)); // 深蓝色文字            }        }        // 3秒后清除高亮        QTimer::singleShot(3000, [this]() {            if (model->rowCount() > 0) {                for (int col = 0; col < model->columnCount(); ++col) {                    QStandardItem *item = model->item(0, col);                    if (item) {                        item->setBackground(QBrush()); // 恢复默认背景                        item->setForeground(QBrush()); // 恢复默认前景色                    }                }            }        });    }}void MainWindow::onGenerateTestData(){    // 安全检查    if (!dataGenerationWorker || !dataGenerationThread) {        QMessageBox::critical(this, "错误", "数据生成工作线程未正确初始化");        return;    }    if (!progressBar || !statusLabel) {        QMessageBox::critical(this, "错误", "UI组件未正确初始化");        return;    }    // 确认对话框    QMessageBox::StandardButton reply = QMessageBox::question(        this,        "测试数据",        "确定要生成10万条测试数据吗?\n根据情况设置100万 或者 1000万等\n这可能需要几分钟时间。\n\n注意:生成过程中窗口仍可正常操作。",        QMessageBox::Yes | QMessageBox::No,        QMessageBox::No        );    if (reply != QMessageBox::Yes) {        return;    }    // 注意:工具栏按钮通过QAction控制,这里不需要禁用按钮    // 显示进度条    progressBar->setVisible(true);    progressBar->setRange(0, 0); // 不确定进度    statusLabel->setText("正在生成测试数据,请稍候...");    // 启动数据生成工作线程    const int totalRecords = 100000; // 10万条记录,备注根据情况来设置此工作线程    try {        QMetaObject::invokeMethod(dataGenerationWorker, "generateTestData",                                  Qt::QueuedConnection, Q_ARG(int, totalRecords));    } catch (const std::exception& e) {        QMessageBox::critical(this, "错误", QString("启动数据生成失败: %1").arg(e.what()));        progressBar->setVisible(false);        statusLabel->setText("数据生成启动失败");    } catch (...) {        QMessageBox::critical(this, "错误", "启动数据生成时发生未知错误");        progressBar->setVisible(false);        statusLabel->setText("数据生成启动失败");    }}void MainWindow::onDataGenerationProgress(int current, int /*total*/, double rate){    // 更新进度显示    statusLabel->setText(QString("已生成 %1 条记录,速度: %2 条/秒")                             .arg(current).arg(QString::number(rate, 'f', 0)));}void MainWindow::onDataGenerationCompleted(int totalRecords, int totalTime){    // 隐藏进度条    progressBar->setVisible(false);    // 刷新数据    if (usePagination) {        paginationModel->refreshData();    } else {        loadDataFromDatabase();    }    // 显示完成信息    QMessageBox::information(this, "完成",                             QString("测试数据生成完成!\n\n"                                     "生成记录数: %1 条\n"                                     "耗时: %2 秒\n"                                     "平均速度: %3 条/秒")                                 .arg(totalRecords)                                 .arg(totalTime / 1000.0, 0, 'f', 1)                                 .arg(QString::number((double)totalRecords / totalTime * 1000, 'f', 0)));    statusLabel->setText(QString("测试数据生成完成,共 %1 条记录").arg(totalRecords));    qDebug() << "测试数据生成完成,共" << totalRecords << "条记录,耗时" << totalTime << "毫秒";}void MainWindow::onDataGenerationFailed(const QString &error){    // 隐藏进度条    progressBar->setVisible(false);    // 显示错误信息    QMessageBox::critical(this, "错误", "数据生成失败: " + error);    statusLabel->setText("数据生成失败");    qDebug() << "数据生成失败:" << error;}// DataGenerationWorker 实现DataGenerationWorker::DataGenerationWorker(QObject *parent)    : QObject(parent), m_shouldStop(false){}void DataGenerationWorker::stopGeneration(){    m_shouldStop = true;}

由于篇幅有限,关注UP主后进群下载工程项目源码研究学习。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐