Qt 将MySQL中符合条件数据顺序插入到QTableWidget中

本文讲解了使用QSqlQuery和QTableWidget在Qt中操作数据库,通过查询筛选后,将符合条件的数据行插入到表格中,包括查询判断、数据清理和插入步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇文章解决了如何将数据库中数据插入到QTableWidget的问题

首先,我们需要首先包含
#include <QSqlQuery>
#include <QSqlRecord>
这两个头文件

由于我的界面中有个查询按钮,所以会有一个是否有匹配记录的判断,以此来决定是否执行后续代码,如果不需要这一段可以不看

    QSqlQuery query;
    query.exec("select * from t_modify where `修改时间` like '%" + str +"%'");

    if(query.size() == 0)
    {
        QMessageBox::about(this,"查询","没有与之匹配的查询记录");
        return;
    }

其中,t_modify是我自己的表名

接下来,步入正题,将符合查询条件的记录插入QTableWidget中:

	dlog->show();
    dlog->ShowRecord(&query);

dlog是我自定义的一个QDialog类对话框,我的QTableWidget就在这个对话框中

然后将对话框显示并执行ShowRecord函数,以下为ShowRecord定义。

void RecordDialog::ShowRecord(QSqlQuery *query)
{
//每次插入新记录前删除表中原有记录
    for(int i=ui->QueryWidget->rowCount();i>0;i--) ui->QueryWidget->removeRow(0);
   
    QSqlRecord rec = query->record();
    while(query->next())
    {
        rec = query->record();
        int m_num = rec.indexOf("序号");
        int m_process = rec.indexOf("修改进程");
        int m_address = rec.indexOf("修改地址");
        int m_text = rec.indexOf("修改内容");
        int m_time = rec.indexOf("修改时间");
        int index = ui->QueryWidget->rowCount();
        ui->QueryWidget->insertRow(index);
        ui->QueryWidget->setItem(index, 0, new QTableWidgetItem(query->value(m_num).toString()));
        ui->QueryWidget->setItem(index, 1, new QTableWidgetItem(query->value(m_process).toString()));
        ui->QueryWidget->setItem(index, 2, new QTableWidgetItem(query->value(m_address).toString()));
        ui->QueryWidget->setItem(index, 3, new QTableWidgetItem(query->value(m_text).toString()));
        ui->QueryWidget->setItem(index, 4, new QTableWidgetItem(query->value(m_time).toString()));
    }
}

当然,如果在一个函数中,你只需要将我的ShowRecord代码中的内容复制下来,并且将query-> 改为 query. 即可。

最后,执行结果如下:
请添加图片描述

<think>我们之前使用的数据库查询返回的是元组列表,每个元组代表一行,通过索引访问字段。 如果连接池配置为返回字典(例如使用pymysql.cursors.DictCursor),那么查询结果将是字典列表,每个字典的键是字段名,值是对应的值。 为了适应这种变化,我们需要修改代码中处理查询结果的部分。 修改点: 1. 在连接池配置中指定cursorclass为pymysql.cursors.DictCursor。 2. 在查询数据时,使用字段名(而不是索引)来访问数据。 3. 在EditWindow中,根据字段名获取数据并填充表单。 4. 在主窗口加载数据到表格时,使用字段名来获取每列的值。 下面我们修改代码以支持返回字典。</think>如果数据库连接池返回的是字典列表(即每行数据是一个字典,键为列名),我们需要调整代码以适应这种数据结构。以下是修改后的完整实现,使用字典格式处理查询结果: ```python import sys from PyQt5.QtWidgets import ( QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QMenu, QAction, QMessageBox, QAbstractItemView, QVBoxLayout, QLabel, QLineEdit, QPushButton, QWidget, QStatusBar, QTextEdit, QFormLayout ) from PyQt5.QtCore import Qt, pyqtSignal import pymysql from pymysql.cursors import DictCursor from dbutils.pooled_db import PooledDB # 数据库连接池配置 - 使用DictCursor返回字典 DB_POOL = PooledDB( creator=pymysql, maxconnections=5, host='localhost', user='your_user', password='your_password', database='medical_db', charset='utf8mb4', cursorclass=DictCursor # 关键:使用字典游标 ) class EditWindow(QMainWindow): """编辑症状详细信息窗口""" operation_completed = pyqtSignal() # 自定义信号,操作完成时发射 def __init__(self, symptom_id=None, symptom_name=None, parent=None): """ 初始化编辑窗口 :param symptom_id: 症状ID :param symptom_name: 症状名称 :param parent: 父窗口 """ super().__init__(parent) self.symptom_id = symptom_id self.symptom_name = symptom_name self.setWindowTitle(f'编辑症状: {symptom_name}' if symptom_name else '添加新症状') self.setGeometry(300, 300, 600, 500) # 设置窗口大小 # 设置中央部件 self.central_widget = QWidget() self.setCentralWidget(self.central_widget) # 设置状态栏 self.status_bar = QStatusBar() self.setStatusBar(self.status_bar) # 初始化UI self.setup_ui() # 如果是编辑模式,加载症状详细信息 if symptom_id: self.load_symptom_details() def setup_ui(self): """设置UI界面""" # 主布局 main_layout = QVBoxLayout(self.central_widget) # 表单布局 form_layout = QFormLayout() # 症状名称 self.name_edit = QLineEdit() form_layout.addRow(QLabel("症状名称:"), self.name_edit) # 症状描述 self.description_edit = QTextEdit() self.description_edit.setMinimumHeight(100) form_layout.addRow(QLabel("症状描述:"), self.description_edit) # 常见病因 self.causes_edit = QTextEdit() self.causes_edit.setMinimumHeight(80) form_layout.addRow(QLabel("常见病因:"), self.causes_edit) # 治疗方法 self.treatment_edit = QTextEdit() self.treatment_edit.setMinimumHeight(100) form_layout.addRow(QLabel("治疗方法:"), self.treatment_edit) # 相关科室 self.department_edit = QLineEdit() form_layout.addRow(QLabel("相关科室:"), self.department_edit) # 添加到主布局 main_layout.addLayout(form_layout) # 提交按钮 self.submit_btn = QPushButton("提交") self.submit_btn.clicked.connect(self.submit_data) main_layout.addWidget(self.submit_btn) # 取消按钮 self.cancel_btn = QPushButton("取消") self.cancel_btn.clicked.connect(self.close) main_layout.addWidget(self.cancel_btn) def load_symptom_details(self): """从数据库加载症状详细信息(字典格式)""" conn = DB_POOL.connection() cursor = conn.cursor() try: # 查询症状详细信息 - 返回字典 sql = """ SELECT id, name, description, common_causes, treatment, department FROM symptoms WHERE id = %s """ cursor.execute(sql, (self.symptom_id,)) symptom_data = cursor.fetchone() # 返回字典 if symptom_data: # 使用字段名访问数据 self.name_edit.setText(symptom_data['name']) self.description_edit.setText(symptom_data['description']) self.causes_edit.setText(symptom_data['common_causes']) self.treatment_edit.setText(symptom_data['treatment']) self.department_edit.setText(symptom_data['department']) else: self.status_bar.showMessage("未找到该症状的详细信息", 3000) except Exception as e: QMessageBox.critical(self, "数据库错误", f"加载数据失败: {str(e)}") finally: cursor.close() conn.close() def submit_data(self): """提交更新后的症状信息""" # 获取表单数据 name = self.name_edit.text().strip() description = self.description_edit.toPlainText().strip() causes = self.causes_edit.toPlainText().strip() treatment = self.treatment_edit.toPlainText().strip() department = self.department_edit.text().strip() # 验证输入 if not name: self.status_bar.showMessage("症状名称不能为空!", 5000) return if not description: self.status_bar.showMessage("症状描述不能为空!", 5000) return # 获取数据库连接 conn = DB_POOL.connection() cursor = conn.cursor() try: if self.symptom_id: # 更新现有症状 - 使用字典格式参数 sql = """ UPDATE symptoms SET name = %(name)s, description = %(description)s, common_causes = %(causes)s, treatment = %(treatment)s, department = %(department)s WHERE id = %(id)s """ params = { 'name': name, 'description': description, 'causes': causes, 'treatment': treatment, 'department': department, 'id': self.symptom_id } cursor.execute(sql, params) self.status_bar.showMessage("症状信息更新成功!", 3000) else: # 添加新症状 - 使用字典格式参数 sql = """ INSERT INTO symptoms (name, description, common_causes, treatment, department) VALUES (%(name)s, %(description)s, %(causes)s, %(treatment)s, %(department)s) """ params = { 'name': name, 'description': description, 'causes': causes, 'treatment': treatment, 'department': department } cursor.execute(sql, params) self.status_bar.showMessage("新症状添加成功!", 3000) # 获取新添加的症状ID self.symptom_id = cursor.lastrowid conn.commit() # 发射操作完成信号 self.operation_completed.emit() self.close() except Exception as e: conn.rollback() QMessageBox.critical(self, "数据库错误", f"操作失败: {str(e)}") finally: cursor.close() conn.close() class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("症状管理系统") self.setGeometry(100, 100, 1000, 600) # 创建表格 self.table = QTableWidget() # 列配置 - 与数据库字段对应 self.columns = ['id', 'name', 'description', 'common_causes', 'treatment', 'department'] self.column_headers = ['ID', '症状名称', '描述', '常见病因', '治疗方法', '相关科室'] self.table.setColumnCount(len(self.columns)) self.table.setHorizontalHeaderLabels(self.column_headers) self.table.setSelectionBehavior(QAbstractItemView.SelectRows) self.table.setSelectionMode(QAbstractItemView.SingleSelection) # 设置列宽 self.table.setColumnWidth(0, 50) # ID self.table.setColumnWidth(1, 150) # 名称 self.table.setColumnWidth(2, 200) # 描述 self.table.setColumnWidth(3, 200) # 病因 self.table.setColumnWidth(4, 200) # 治疗 self.table.setColumnWidth(5, 100) # 科室 # 设置右键菜单策略 self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.show_context_menu) self.setCentralWidget(self.table) self.load_data() # 加载初始数据 # 存储编辑窗口引用 self.edit_window = None def load_data(self): """从数据库加载症状数据到表格(字典格式)""" conn = DB_POOL.connection() cursor = conn.cursor() try: cursor.execute("SELECT id, name, description, common_causes, treatment, department FROM symptoms") rows = cursor.fetchall() # 返回字典列表 self.table.setRowCount(len(rows)) for row_idx, row_data in enumerate(rows): for col_idx, col_name in enumerate(self.columns): value = row_data.get(col_name, "") item = QTableWidgetItem(str(value) if value is not None else "") # 设置为不可编辑 item.setFlags(item.flags() & ~Qt.ItemIsEditable) # 对于长文本,设置工具提示 if col_name in ['description', 'common_causes', 'treatment'] and value and len(value) > 20: item.setToolTip(value[:100] + "..." if len(value) > 100 else value) self.table.setItem(row_idx, col_idx, item) except Exception as e: QMessageBox.critical(self, "数据库错误", f"加载数据失败: {str(e)}") finally: cursor.close() conn.close() def show_context_menu(self, pos): """显示右键菜单""" menu = QMenu() # 创建菜单项 add_action = QAction("添加症状", self) edit_action = QAction("编辑症状", self) delete_action = QAction("删除症状", self) # 连接信号 add_action.triggered.connect(self.add_symptom) edit_action.triggered.connect(self.edit_symptom) delete_action.triggered.connect(self.delete_symptom) # 添加到菜单 menu.addAction(add_action) menu.addAction(edit_action) menu.addAction(delete_action) # 显示菜单 menu.exec_(self.table.viewport().mapToGlobal(pos)) def add_symptom(self): """添加新症状""" # 关闭已存在的编辑窗口 if self.edit_window: self.edit_window.close() self.edit_window = EditWindow(parent=self) self.edit_window.operation_completed.connect(self.load_data) # 连接操作完成信号 self.edit_window.setWindowModality(Qt.ApplicationModal) # 设置为模态窗口 self.edit_window.show() def edit_symptom(self): """编辑选中症状""" selected_rows = self.table.selectionModel().selectedRows() if not selected_rows: QMessageBox.warning(self, "警告", "请先选择一行记录") return row_idx = selected_rows[0].row() symptom_id = int(self.table.item(row_idx, 0).text()) # ID列 symptom_name = self.table.item(row_idx, 1).text() # 名称列 # 关闭已存在的编辑窗口 if self.edit_window: self.edit_window.close() # 创建编辑窗口,传入症状ID和名称 self.edit_window = EditWindow( symptom_id=symptom_id, symptom_name=symptom_name, parent=self ) self.edit_window.operation_completed.connect(self.load_data) # 连接操作完成信号 self.edit_window.setWindowModality(Qt.ApplicationModal) # 设置为模态窗口 self.edit_window.show() def delete_symptom(self): """删除选中症状""" selected_rows = self.table.selectionModel().selectedRows() if not selected_rows: QMessageBox.warning(self, "警告", "请先选择一行记录") return row_idx = selected_rows[0].row() symptom_id = int(self.table.item(row_idx, 0).text()) symptom_name = self.table.item(row_idx, 1).text() # 确认对话框 reply = QMessageBox.question( self, '确认删除', f"确定要删除症状 '{symptom_name}' (ID: {symptom_id}) 吗?", QMessageBox.Yes | QMessageBox.No ) if reply == QMessageBox.Yes: conn = DB_POOL.connection() cursor = conn.cursor() try: cursor.execute("DELETE FROM symptoms WHERE id = %s", (symptom_id,)) conn.commit() self.load_data() # 刷新表格 QMessageBox.information(self, "成功", "症状已成功删除") except Exception as e: conn.rollback() QMessageBox.critical(self, "数据库错误", f"删除失败: {str(e)}") finally: cursor.close() conn.close() if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_()) ``` ### 关键修改点说明 1. **数据库连接池配置字典游标**: ```python DB_POOL = PooledDB( # ...其他配置... cursorclass=DictCursor # 关键:使用字典游标 ) ``` - 添加 `cursorclass=DictCursor` 参数使查询结果返回字典格式 2. **编辑窗口加载数据(字典访问)**: ```python def load_symptom_details(self): # ... cursor.execute(sql, (self.symptom_id,)) symptom_data = cursor.fetchone() # 返回字典 if symptom_data: self.name_edit.setText(symptom_data['name']) self.description_edit.setText(symptom_data['description']) # ...其他字段... ``` - 使用字段名(如 `'name'`, `'description'`)而不是索引访问数据 3. **数据库操作使用命名参数**: ```python # 更新操作使用命名参数 sql = """ UPDATE symptoms SET name = %(name)s, description = %(description)s, common_causes = %(causes)s, treatment = %(treatment)s, department = %(department)s WHERE id = %(id)s """ params = { 'name': name, 'description': description, 'causes': causes, 'treatment': treatment, 'department': department, 'id': self.symptom_id } cursor.execute(sql, params) ``` - 使用命名参数使SQL语句更清晰 - 参数传递使用字典格式 4. **主窗口加载表格数据(字典访问)**: ```python # 定义列名映射 self.columns = ['id', 'name', 'description', 'common_causes', 'treatment', 'department'] self.column_headers = ['ID', '症状名称', '描述', '常见病因', '治疗方法', '相关科室'] # 加载数据 for row_idx, row_data in enumerate(rows): for col_idx, col_name in enumerate(self.columns): value = row_data.get(col_name, "") item = QTableWidgetItem(str(value) if value is not None else "") ``` - 使用列名字典访问数据 - 通过 `row_data.get(col_name, "")` 安全获取值 ### 字典格式的优势 1. **代码可读性**: - 使用字段名(如 `row_data['name']`)比索引(如 `row_data[1]`)更直观 - 减少因列顺序变化导致的错误 2. **灵活性**: - 更容易处理可选字段(使用 `get()` 方法提供默认值) - 添加新字段时只需扩展列名列表,无需修改大量索引 3. **安全性**: - 避免因列顺序变化导致的错误 - 更清晰的SQL语句参数绑定 ### 使用字典格式的注意事项 1. **数据库表结构变化**: - 如果数据库表结构变化(如添加/删除列),需要更新代码中的字段名列表 - 建议使用常量定义字段名 2. **性能考虑**: - 字典格式比元组格式占用更多内存 - 对于大数据查询,需考虑内存使用情况 3. **字段名大小写**: - 不同数据库字段名大小写处理不同 - MySQL默认不区分大小写,但建议代码中保持一致性 ### 完整工作流程 1. **主窗口加载数据**: - 执行SQL查询,返回字典列表 - 遍历字典列表,使用字段名获取值填充表格 2. **编辑症状**: - 选择症状行,获取ID和名称 - 打开编辑窗口,传入ID和名称 - 编辑窗口根据ID查询,返回单个字典 - 使用字段名填充表单控件 3. **提交修改**: - 获取表单数据 - 构建参数字典 - 执行SQL更新/插入操作 - 发射信号通知主窗口刷新 ### 扩展功能:动态列处理 如果需要处理动态变化的列结构,可以这样实现: ```python def load_data(self): conn = DB_POOL.connection() cursor = conn.cursor() try: # 获取列信息 cursor.execute("SHOW COLUMNS FROM symptoms") columns_info = cursor.fetchall() self.columns = [col['Field'] for col in columns_info] self.column_headers = [col['Field'].replace('_', ' ').title() for col in columns_info] # 更新表格列 self.table.setColumnCount(len(self.columns)) self.table.setHorizontalHeaderLabels(self.column_headers) # 查询数据 cursor.execute("SELECT * FROM symptoms") rows = cursor.fetchall() self.table.setRowCount(len(rows)) for row_idx, row_data in enumerate(rows): for col_idx, col_name in enumerate(self.columns): value = row_data.get(col_name, "") item = QTableWidgetItem(str(value) if value is not None else "") item.setFlags(item.flags() & ~Qt.ItemIsEditable) self.table.setItem(row_idx, col_idx, item) # ...错误处理... ``` 这样代码会根据数据库表结构动态调整列,更加灵活。 ### 字典格式的最佳实践 1. **使用常量定义字段名**: ```python class SymptomFields: ID = 'id' NAME = 'name' DESCRIPTION = 'description' CAUSES = 'common_causes' TREATMENT = 'treatment' DEPARTMENT = 'department' ``` 2. **安全访问字段**: ```python # 使用get()方法提供默认值 name = symptom_data.get(SymptomFields.NAME, "未知") ``` 3. **处理空值**: ```python # 使用三元表达式处理空值 description = symptom_data[SymptomFields.DESCRIPTION] if symptom_data[SymptomFields.DESCRIPTION] else "无描述" ``` 4. **字段验证**: ```python required_fields = [SymptomFields.NAME, SymptomFields.DESCRIPTION] for field in required_fields: if field not in symptom_data or not symptom_data[field]: raise ValueError(f"缺少必要字段: {field}") ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值