You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt6 QTableView实现商品选择与UOM自动填充功能求助

问题解决思路与代码修正

一、明确:QTableView完全适配你的需求

QTableView是Qt官方用于表格数据展示、编辑的标准组件,配合自定义AbstractTableModel能灵活控制数据逻辑,完全满足你订单展示、商品选择联动UOM的需求,不用换组件。

二、先修复你的TableViewModel代码

原代码有几个致命问题导致无法运行,修正后的版本如下:

from PyQt6 import QtCore, QtGui, QtWidgets

class TableViewModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        # data建议用二维列表结构,比如[[1, "", "", 0, 0], [2, "", "", 0, 0]]
        self._data = data
        self.header = ["No.", "Products", "UOM", "Ordered", "Supplied"]
        
    def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
        if orientation == QtCore.Qt.Orientation.Horizontal and role == QtCore.Qt.ItemDataRole.DisplayRole:
            if section < len(self.header):
                return self.header[section]
        # 其他情况返回默认值
        return super().headerData(section, orientation, role)
        
    def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.ItemDataRole.DisplayRole):
        if not index.isValid():
            return None
            
        row = index.row()
        col = index.column()
        
        if role == QtCore.Qt.ItemDataRole.DisplayRole or role == QtCore.Qt.ItemDataRole.EditRole:
            # 返回对应单元格的数据,UOM列留空后续填充
            return self._data[row][col]
        
        return super().data(index, role)
        
    def rowCount(self, parent: QtCore.QModelIndex = QtCore.QModelIndex()):
        # 父索引无效时返回数据行数,表格模型标准写法
        if parent.isValid():
            return 0
        return len(self._data)
        
    def columnCount(self, parent: QtCore.QModelIndex = QtCore.QModelIndex()):
        if parent.isValid():
            return 0
        # 用表头长度更灵活,避免硬编码
        return len(self.header)
    
    def setData(self, index: QtCore.QModelIndex, value, role: int = QtCore.Qt.ItemDataRole.EditRole):
        if not index.isValid() or role != QtCore.Qt.ItemDataRole.EditRole:
            return False
            
        row = index.row()
        col = index.column()
        self._data[row][col] = value
        # 必须发信号通知视图更新,否则修改后界面不刷新
        self.dataChanged.emit(index, index)
        return True
    
    def flags(self, index: QtCore.QModelIndex):
        if not index.isValid():
            return QtCore.Qt.ItemFlag.NoItemFlags
        return QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsEditable

三、实现点击商品列弹出对话框+联动UOM

1. 写商品选择对话框(含数据库加载逻辑)

这里用模拟数据演示,你替换成实际数据库查询代码即可:

class ProductSelectDialog(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("选择商品")
        self.resize(400, 300)
        
        layout = QtWidgets.QVBoxLayout(self)
        
        # 商品列表视图
        self.table_view = QtWidgets.QTableView()
        # 替换成你的数据库查询结果:商品ID、名称、UOM
        self.product_data = [
            [1, "苹果", "箱"],
            [2, "香蕉", "串"],
            [3, "橙子", "袋"]
        ]
        # 用QStandardItemModel快速展示,也可以用自定义模型
        self.product_model = QtGui.QStandardItemModel()
        self.product_model.setHorizontalHeaderLabels(["ID", "商品名称", "包装单位"])
        for row in self.product_data:
            items = [QtGui.QStandardItem(str(item)) for item in row]
            self.product_model.appendRow(items)
        self.table_view.setModel(self.product_model)
        self.table_view.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
        
        # 确认按钮
        self.confirm_btn = QtWidgets.QPushButton("确认选择")
        self.confirm_btn.clicked.connect(self.accept)
        
        layout.addWidget(self.table_view)
        layout.addWidget(self.confirm_btn)
        
    # 获取选中的商品信息
    def get_selected_product(self):
        selected_rows = self.table_view.selectionModel().selectedRows()
        if not selected_rows:
            return None
        row = selected_rows[0].row()
        return (self.product_data[row][1], self.product_data[row][2])

2. 主窗口绑定点击事件,实现联动

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("客户订单管理")
        self.resize(800, 400)
        
        # 初始化模拟订单数据
        self.order_data = [
            [1, "", "", 0, 0],
            [2, "", "", 0, 0],
            [3, "", "", 0, 0]
        ]
        
        # 创建模型和视图
        self.table_model = TableViewModel(self.order_data)
        self.table_view = QtWidgets.QTableView()
        self.table_view.setModel(self.table_model)
        
        # 绑定点击事件
        self.table_view.clicked.connect(self.on_table_clicked)
        
        self.setCentralWidget(self.table_view)
        
    def on_table_clicked(self, index):
        # 只处理商品列(索引1)的点击
        if index.column() == 1:
            dialog = ProductSelectDialog(self)
            if dialog.exec() == QtWidgets.QDialog.DialogCode.Accepted:
                product_info = dialog.get_selected_product()
                if product_info:
                    product_name, uom = product_info
                    # 更新商品列
                    self.table_model.setData(self.table_model.index(index.row(), 1), product_name)
                    # 自动填充UOM列
                    self.table_model.setData(self.table_model.index(index.row(), 2), uom)

3. 运行主程序

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

四、补充说明

  • 数据库部分:在ProductSelectDialog的__init__里,把模拟的product_data替换成你的数据库查询逻辑(比如用sqlite3、SQLAlchemy等)
  • 添加新行:如果需要动态加订单行,可以给主窗口加按钮,调用模型的beginInsertRows和endInsertRows方法添加空行
  • 数据保存:修改订单数据后,把self.order_data写入数据库即可完成持久化

内容的提问来源于stack exchange,提问作者wondergod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 05:07:21