当前位置: 首页 > article >正文

QT 使用QTableView读取数据库数据,表格分页,跳转,导出,过滤功能

文章目录

      • 效果图
      • 概述
      • 功能点
      • 代码分析
        • 导航栏
        • 表格更新视图
        • 表格导出
        • 表格过滤
      • 总结

效果图

概述

  • 本案例用于对数据库中的数据进行显示等其他操作。数据库的映射,插入等功能看此博客
  • 框架:数据模型使用QSqlTableModel,视图使用QTableView,表格的一些字体或者控件之类的使用QStyledItemDelegate实现。
    导航栏的变化实时的传回给表格,所有的数据库表都实现继承一个表格类,根据表格本身的特性可以设置自己的委托。数据库使用一个单列类进行管理,包括数据库的读取 ,创建,数据插入,以及对模型的映射等。

功能点

  1. 自选每页显示行数
  2. 跳转指定页面
  3. 上下翻页,最后/最前一页跳转
  4. 表格导出
  5. 表格查询

代码分析

导航栏
  • 该部分不复杂主要和tableView进行联动
    void PageNavigator::SetCurrentPage(int page)
    {
        if (m_curPage == page)
        {
            return;
        }
    
        if (page < 1)
        {
            page = 1;
        }
    
        if (page > (int)m_maxPage)
        {
            page = m_maxPage;
        }
    
        m_curPage = page;
        ui->labelCurPage->setText(QString("第%1页/共%2页").arg(m_curPage).arg(m_maxPage));
    
        UpdateButtonState();
    
        emit SigCurrentPageChanged(m_curPage); // 通知 table 刷新
    }
    
表格更新视图
  • 每次使用过滤时要格外注意语句的条件
    void QTablePages::updateTableView()
    {
        if (!m_dataModel)
            return;
        if (m_filter != QString()) // 有过滤条件的情况
        {
            int offset = (m_currentPage - 1) * m_pageLines;
            // 使用正则表达式来匹配LIMIT和OFFSET后面的数字
            QRegExp limitRegex("LIMIT\\s*(\\d+)");
            QRegExp offsetRegex("OFFSET\\s*(\\d+)");
            // 替换LIMIT
            m_filter.replace(limitRegex, QString("LIMIT %1").arg(m_pageLines));
            // 替换OFFSET
            m_filter.replace(offsetRegex, QString("OFFSET %1").arg(offset));
            m_dataModel->setFilter(m_filter);
            m_dataModel->select();
            return;
        }
        int offset = (m_currentPage - 1) * m_pageLines; // 计算偏移量 要减1,因为从0开始
        m_dataModel->setFilter(QString("1=1 ORDER BY time DESC LIMIT %1 OFFSET %2").arg(m_pageLines).arg(offset));
        m_dataModel->select();
    }
    
表格导出
  • 简单的导出为csv格式,要是为excel格式,则需要引入excel的库
void QTablePages::exportToCSV()
{
    if (!m_dataModel)
        return;

    QFileDialog dialog(this);
    dialog.setOptions(QFileDialog::DontUseNativeDialog);
    dialog.setWindowTitle(tr("表格导出"));
    dialog.setAcceptMode(QFileDialog::AcceptSave);
    dialog.setNameFilter(tr("CSV Files (*.csv)"));

    dialog.setStyleSheet("color: white;");
    QString saveFileName;
    if (dialog.exec())
    {
        saveFileName = dialog.selectedFiles().first();
        QFileInfo fileInfo(saveFileName);
        if (fileInfo.suffix().toLower() != "csv")
        {
            saveFileName += ".csv"; // 如果用户没有输入.csv,则添加它
        }
    }
    // 如果用户取消了操作,则返回
    if (saveFileName.isEmpty())
        return;

    // 打开一个文件用于写入
    QFile file(saveFileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        // 处理错误
        return;
    }
    /// 重置过滤条件-查询所有数据
    int offset = getOffest();
    int totalPages = getTotalPages();
    QString filter = getFilter();
    m_dataModel->setFilter(QString("1=1"));
    m_dataModel->select();
    QTextStream out(&file);

    int columnCount = m_dataModel->columnCount() - 1;
    // 写入列标题 操作列不写入
    for (int i = 1; i < columnCount; i++)
    {
        out << m_dataModel->headerData(i, Qt::Horizontal).toString();
        if (i < columnCount - 1)
            out << ",";
    }
    out << "\n";
    // 写入数据
    auto formatDateTime = [](const QDateTime &dateTime)
    {
        return dateTime.toString("yyyy-MM-dd HH:mm:ss");
    };
    for (int i = 0; i < m_dataModel->rowCount(); i++)
    {
        QSqlRecord record = m_dataModel->record(i);
        for (int j = 1; j < columnCount; j++)
        {
            QSqlField field = record.field(j);
            if (field.type() == QVariant::DateTime)
            {
                // 如果字段是日期时间类型,则格式化输出
                QDateTime dateTime = field.value().toDateTime();
                out << formatDateTime(dateTime);
            }
            else
            {
                // 其他字段按原样输出
                out << field.value().toString();
            }
            if (j < columnCount - 1)
                out << ",";
        }
        out << "\n";
    }

    // 关闭文件
    file.close();

    // 恢复过滤条件
    if (filter != QString())
    {
        m_dataModel->setFilter(filter);
    }
    else
    {
        m_dataModel->setFilter(QString("1=1 ORDER BY time DESC LIMIT %1 OFFSET %2").arg(totalPages).arg(offset));
    }
    m_dataModel->select();
}
表格过滤
  • 数据过滤的条件,要和导航栏的偏移分开获取,不然过滤会出现问题
void QTablePages::refreshData(const QString &dateFrom, const QString &dateTo, const QString &content)
{
    if (m_dataModel == nullptr)
        return;
    QString filter;
    // 获取日期范围
    QString dateFilter = "time BETWEEN '" + dateFrom + "' AND '" + dateTo + "'";
    // 获取内容过滤条件
    QString contentFilter;
    if (!content.isEmpty())
    {
        contentFilter = "content LIKE '%" + content + "%'";
    }
    // 构建最终的过滤条件
    if (!filter.isEmpty())
    {
        if (!dateFilter.isEmpty())
        {
            filter += " AND " + dateFilter;
        }
        if (!contentFilter.isEmpty())
        {
            filter += " AND " + contentFilter;
        }
    }
    else
    {
        if (!dateFilter.isEmpty())
        {
            filter = dateFilter;
            if (!contentFilter.isEmpty())
            {
                filter += " AND " + contentFilter;
            }
        }
        else if (!contentFilter.isEmpty())
        {
            filter = contentFilter;
        }
    }

    // 重置导航条数据
    m_dataModel->setFilter(filter);
    m_dataModel->select();
    m_pageNavBar->updateNavbar(m_dataModel->rowCount(), m_pageLines);

    // 计算偏移量,要减1,因为从0开始
    int offset = (m_currentPage - 1) * m_pageLines;
    // 添加排序、限制和偏移量到过滤条件
    if (!filter.isEmpty())
    {
        filter += " ORDER BY time DESC LIMIT " + QString::number(m_pageLines) + " OFFSET " + QString::number(offset);
    }
    else
    {
        filter = "1=1 ORDER BY time DESC LIMIT " + QString::number(m_pageLines) + " OFFSET " + QString::number(offset);
    }
    m_filter = filter;
    // 应用最终的过滤条件
    m_dataModel->setFilter(filter);
    m_dataModel->select();
}

总结

  • 知识理应共享,源码在此
  • 导航栏,表格这些功能基本上都是单独封装好的,可以直接拿来用的

http://www.kler.cn/a/511035.html

相关文章:

  • 第十三章:数据库技术
  • 基于Python的心电图报告解析与心电吸引子绘制
  • 高效实现 Markdown 转 PDF 的跨平台指南20250117
  • Redis 中 TTL 的基本知识与禁用缓存键的实现策略(Java)
  • LabVIEW时域近场天线测试
  • Linux 管道操作
  • ASP.NET Core--依赖注入(DI)--在ASP.NET Core中使用依赖注入
  • 通过内核模块按fd强制tcp的quickack方法
  • 从零到一:构建高效稳定的电商数据API接口
  • HarmonyOS开发中模拟器TextInput表单类的无法输入中文字符问题
  • (python)数据分析-描述性统计
  • Linux中的基本指令(一)
  • QT 如何禁止QComboBox鼠标滚轮
  • Android系统开发(十):标准协议和通讯的桥梁:探索蓝牙、NFC、WLAN 的工作原理
  • JavaEE之CAS
  • Go os/exec 使用实践
  • Low-Level 大一统:如何使用Diffusion Models完成视频超分、去雨、去雾、降噪等所有Low-Level 任务?
  • 构建高可用和高防御力的云服务架构第五部分:PolarDB(55)
  • STM32 FreeRTOS软件定时器
  • 力扣面试150 长度最小的子数组 滑动窗口
  • 【从算法小白到 csp-j 一等 第三节】递推与递归
  • Rust 的核心工具链
  • JS宏进阶:正则表达式的使用
  • windows蓝牙驱动开发-BLE音频(二)
  • ROS2 与机器人视觉入门教程(ROS2 OpenCV)
  • 高通8255 Android STR 启动失败要因分析调查