hejialiangya 发表于 2023-7-6 10:08:13

QTableView内嵌QComboBox,请问如何实现,我写不出来了

https://t1.wodetu.cn/2023/07/06/23d6a93dcc28bfe646dd339b22902c23.png
column1为price
column2为type
price和type通过sql语句关联(sql语句已完成)

当column1输入price的时候,column2显示与price对应的QComboBox(type值传入QComboBox)
https://t4.wodetu.cn/2023/07/06/b9b00565716ebd60438ffc3f816f52f7.png



    def cliprice_save(self):
      # 取当前单元格index
      index = self.tableView.selectionModel().currentIndex()
      edittrigger = self.tableView.editTriggers()

      if index.row() < 0:
            QMessageBox.warning(self, '注意', '鼠标未选取记录\n请选取表格内某一条记录再操作!')
      else:
            if edittrigger == QAbstractItemView.EditTrigger.NoEditTriggers:
                QMessageBox.warning(self, '注意', '【价格】处于不可编辑状态,\n请点击【修改】按钮编辑')
            else:
                clinictype = index.sibling(index.row(), 1).data()
                price = index.sibling(index.row(), 0).data()
                sqlprice = "SELECT C.CLINIC_TYPE FROM(SELECT A.CLINIC_TYPE,SUM(B.PRICE) AS PRICE " \
                           "FROM CLINIC_TYPE_SETTING A,CURRENT_PRICE_LIST B" \
                           "WHERE A.PRICE_ITEM=B.ITEM_CODEGROUP BY A.CLINIC_TYPE) C " \
                           "WHERE C.PRICE={price}".format(price=price)
                Dbconnect.cursor.execute(sqlprice)
                sqlprice_result = Dbconnect.cursor.fetchall()
                if clinictype not in sqlprice_result:
                  QMessageBox.warning(self, '注意', '没有价格为'+str(price)+'元的号')
                else:
                  pass(这一部分我想嵌入QComboBox并实现功能)

陶远航 发表于 2023-7-6 10:08:29

要在QTableView中嵌入QComboBox,并实现相应的功能,您可以使用QItemDelegate类来自定义单元格的编辑器。以下是一个示例代码:

python
from PyQt5.QtWidgets import QStyledItemDelegate, QComboBox

class ComboBoxDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
      super(ComboBoxDelegate, self).__init__(parent)

    def createEditor(self, parent, option, index):
      editor = QComboBox(parent)
      # 在此处设置QComboBox的选项
      editor.addItem("Option 1")
      editor.addItem("Option 2")
      editor.addItem("Option 3")
      return editor

    def setEditorData(self, editor, index):
      # 将数据设置到QComboBox中
      value = index.model().data(index, role=Qt.DisplayRole)
      editor.setCurrentText(value)

    def setModelData(self, editor, model, index):
      # 将QComboBox中的选择项保存到数据模型中
      value = editor.currentText()
      model.setData(index, value, role=Qt.EditRole)

    def updateEditorGeometry(self, editor, option, index):
      editor.setGeometry(option.rect)

# 在需要的地方使用自定义的委托类
delegate = ComboBoxDelegate()
tableView.setItemDelegateForColumn(1, delegate)


在示例代码中,我们创建了一个名为ComboBoxDelegate的自定义委托类,继承自QStyledItemDelegate。在createEditor方法中,我们创建了一个QComboBox作为单元格的编辑器,并设置了选项。在setEditorData方法中,我们将单元格的数据显示在QComboBox中。在setModelData方法中,我们将QComboBox中的选择项保存到数据模型中。最后,我们使用setItemDelegateForColumn方法将自定义委托类应用于需要的列(这里是第2列)。

需要注意的是,示例代码只是演示了如何在QTableView中嵌入QComboBox,并没有涉及到与数据库相关的功能。您需要根据您的具体需求修改代码并添加适当的逻辑。

希望这可以帮助到您!如果还有其他疑问,请随时向我提问。

isdkz 发表于 2023-7-6 10:09:53

你想要实现的功能应该是在QTableView中嵌入QComboBox。这种情况下,你需要使用委托 (delegate) 来处理。这个委托需要创建一个QComboBox,然后这个QComboBox用来显示你查询的数据。

首先,你需要创建一个新的委托类,这个类应该继承自 QItemDelegate 或者 QStyledItemDelegate 。然后在这个类中,你需要重写两个函数, createEditor()和setEditorData() 。createEditor() 函数用来创建编辑器,也就是你要嵌入的QComboBox。而 setEditorData() 函数用来设置编辑器的数据,也就是你的查询结果。

以下是一个简单的示例:

from PyQt5.QtWidgets import QItemDelegate, QComboBox

class ComboBoxDelegate(QItemDelegate):
    def __init__(self, parent=None):
      super(ComboBoxDelegate, self).__init__(parent)

    def createEditor(self, parent, option, index):
      editor = QComboBox(parent)
      return editor

    def setEditorData(self, editor, index):
      # 这个函数用来设置编辑器的数据
      # 这里应该是你的查询结果
      data = index.model().data(index, Qt.EditRole)
      
      sqlprice = "SELECT C.CLINIC_TYPE FROM(SELECT A.CLINIC_TYPE,SUM(B.PRICE) AS PRICE " \
                   "FROM CLINIC_TYPE_SETTING A,CURRENT_PRICE_LIST B" \
                   "WHERE A.PRICE_ITEM=B.ITEM_CODEGROUP BY A.CLINIC_TYPE) C " \
                   "WHERE C.PRICE={price}".format(price=data)
      Dbconnect.cursor.execute(sqlprice)
      sqlprice_result = Dbconnect.cursor.fetchall()
      
      # 添加到ComboBox中
      for i in sqlprice_result:
            editor.addItem(i)
      
      # 设置当前选中的项
      editor.setCurrentIndex(editor.findText(data))

    def setModelData(self, editor, model, index):
      # 当编辑器关闭时,将编辑器的数据写入模型
      value = editor.currentText()
      model.setData(index, value, Qt.EditRole)


然后,你需要为你的视图设置这个委托:

self.tableView.setItemDelegateForColumn(1, ComboBoxDelegate())


请注意,你可能需要根据你的实际需求对这段代码进行一些修改。我建议你更加了解一下Qt的模型/视图编程和委托,这将有助于你理解和实现这个功能。

sfqxx 发表于 2023-7-6 10:16:57

要在QTableView内嵌QComboBox实现该功能,可以创建一个自定义的委托类,并将其应用于需要显示QComboBox的列。

首先,在你的代码中添加以下引用:


from PyQt5.QtWidgets import QStyledItemDelegate, QComboBox

然后,创建一个自定义的委托类,继承自QStyledItemDelegate,并重写createEditor()、setEditorData()和setModelData()方法。

class ComboBoxDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
      super().__init__(parent)

    def createEditor(self, parent, option, index):
      combobox = QComboBox(parent)
      # 在这里设置QComboBox的选项
      return combobox

    def setEditorData(self, editor, index):
      # 获取数据并设置QComboBox的选择项
      data = index.model().data(index, Qt.DisplayRole)
      combobox = editor
      combobox.setCurrentText(data)

    def setModelData(self, editor, model, index):
      # 获取QComboBox的选中项并进行保存
      combobox = editor
      data = combobox.currentText()
      model.setData(index, data, Qt.EditRole)

接下来,在你的代码中使用自定义的委托类。
# 创建委托对象
delegate = ComboBoxDelegate(self.tableView)
# 将委托对象应用于需要显示QComboBox的列(假设是第2列,索引为1)
self.tableView.setItemDelegateForColumn(1, delegate)

最后,在createEditor()方法中设置QComboBox的选项。你可以根据你的需求从数据库中获取数据,然后将其添加到QComboBox中。

def createEditor(self, parent, option, index):
    combobox = QComboBox(parent)
    # 获取与价格对应的类型列表
    price = index.sibling(index.row(), 0).data()
    sqlprice = "SELECT C.CLINIC_TYPE FROM(SELECT A.CLINIC_TYPE,SUM(B.PRICE) AS PRICE " \
               "FROM CLINIC_TYPE_SETTING A,CURRENT_PRICE_LIST B" \
               "WHERE A.PRICE_ITEM=B.ITEM_CODEGROUP BY A.CLINIC_TYPE) C " \
               "WHERE C.PRICE={price}".format(price=price)
    Dbconnect.cursor.execute(sqlprice)
    sqlprice_result = Dbconnect.cursor.fetchall()
    # 将类型列表添加到QComboBox中
    for item in sqlprice_result:
      combobox.addItem(item)
    return combobox
通过以上步骤,你可以在QTableView中实现嵌入QComboBox的功能。当用户在"price"列输入价格时,"type"列将显示与价格对应的QComboBox,并且选择项会保存到数据模型中。
以下是一个完整的示例,展示了如何在QTableView内嵌QComboBox实现该功能:

from PyQt5.QtWidgets import QApplication, QMainWindow, QStyledItemDelegate, QComboBox, QTableView, QMessageBox
from PyQt5.QtCore import Qt


class ComboBoxDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
      super().__init__(parent)

    def createEditor(self, parent, option, index):
      combobox = QComboBox(parent)
      return combobox

    def setEditorData(self, editor, index):
      data = index.model().data(index, Qt.DisplayRole)
      combobox = editor
      combobox.setCurrentText(data)

    def setModelData(self, editor, model, index):
      combobox = editor
      data = combobox.currentText()
      model.setData(index, data, Qt.EditRole)


class MainWindow(QMainWindow):
    def __init__(self):
      super().__init__()
      self.setupUi()

    def setupUi(self):
      self.tableView = QTableView(self)
      self.setCentralWidget(self.tableView)

      # 创建数据模型(假设有两列)
      model = QStandardItemModel(4, 2, self)
      model.setHorizontalHeaderLabels(["price", "type"])
      self.tableView.setModel(model)

      # 设置第2列为QComboBox
      delegate = ComboBoxDelegate(self.tableView)
      self.tableView.setItemDelegateForColumn(1, delegate)

      # 示例数据
      model.setData(model.index(0, 1), "Type1")
      model.setData(model.index(1, 1), "Type2")
      model.setData(model.index(2, 1), "Type3")
      model.setData(model.index(3, 1), "Type4")

      # 信号槽连接
      model.dataChanged.connect(self.onDataChanged)

    def onDataChanged(self, index):
      column = index.column()
      if column == 0:
            price = index.data(Qt.DisplayRole)
            type_index = index.sibling(index.row(), 1)
            type_data = type_index.data(Qt.DisplayRole)
            if type_data != "":
                QMessageBox.information(self, "Info", f"Price: {price}, Type: {type_data}")


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())
在这个示例中,我们创建了一个包含两列的QTableView,并将第2列设置为QComboBox。当用户在第1列输入价格时,第2列对应的QComboBox将显示相应的选项。当数据改变时,我们通过信号槽连接,在数据改变时打印出价格和类型。你可以根据自己的需求进行进一步的处理。注意,这里使用的是PyQt5库,所以在运行之前请确保已经安装了该库。

求最佳答案{:10_254:}

hejialiangya 发表于 2023-7-6 15:05:55

isdkz 发表于 2023-7-6 10:09
你想要实现的功能应该是在QTableView中嵌入QComboBox。这种情况下,你需要使用委托 (delegate) 来处理。这 ...

三位大哥的思路我都学习了一遍,并尝试写了一下。暂时采用了您的。

以下是全部功能代码

from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
import sys
import Dbconnect
import MenuWindow
import CliPriceModifyWindow

class MenuWindow(MenuWindow.Ui_MainWindow,QMainWindow):
    def __init__(self):
      super(MenuWindow, self).__init__()
      self.setupUi(self)
      #定义QAction触发逻辑
      self.clipricemodi_window = CliPriceModifyWindow()
      self.actprice.triggered.connect(self.actprice_open)
      self.mExit.aboutToShow.connect(sys.exit)

#门诊办专区号表价格修改
#重写ComboBox委托的方法
class ComboBoxDelegate(QItemDelegate):
    def __init__(self, parent=None):
      super(ComboBoxDelegate, self).__init__(parent)

    def createEditor(self, parent, option, index):
      editor = QComboBox(parent)
      return editor

    def setEditorData(self, editor, index):
      # 这个函数用来设置编辑器的数据
      price = index.model().data(index, Qt.EditRole)
      sqlprice = "SELECT C.CLINIC_TYPE FROM(SELECT A.CLINIC_TYPE,SUM(B.PRICE) AS PRICE " \
                  "FROM CLINIC_TYPE_SETTING A,CURRENT_PRICE_LIST B" \
                  "WHERE A.PRICE_ITEM=B.ITEM_CODEGROUP BY A.CLINIC_TYPE) C " \
                  "WHERE C.PRICE={price}".format(price=price)
      Dbconnect.cursor.execute(sqlprice)
      sqlprice_result = Dbconnect.cursor.fetchall()
      # 添加到ComboBox中
      for i in sqlprice_result:
            editor.addItem(i)
      # 设置当前选中的项
      editor.setCurrentIndex(editor.findText(data))

    def setModelData(self, editor, model, index):
      # 当编辑器关闭时,将编辑器的数据写入模型
      value = editor.currentText()
      model.setData(index, value, Qt.EditRole)

class CliPriceModifyWindow(CliPriceModifyWindow.Ui_Form,QWidget):
    def __init__(self):
      super(CliPriceModifyWindow, self).__init__()
      self.setupUi(self)
      self.pBtnQuery.clicked.connect(self.cliprice_query)
      self.pBtnModify.clicked.connect(self.cliprice_modify)
      self.pBtnSave.clicked.connect(self.cliprice_save)
      self.pBtnReset.clicked.connect(self.cliprice_reset)

      # 号表查询
    def cliprice_query(self):
      # 通过住院号查询
      cliniclabel = self.lineEditClinic.text()
      # 查询明细,返回结果
      sql = "SELECT C.PRICE,A.CLINIC_TYPE,A.CLINIC_LABEL,B.DEPT_NAME,A.SHBLX,A.CLINIC_POSITION " \
                "FROM CLINIC_INDEX A,DEPT_DICT B, " \
                "(SELECT A.CLINIC_TYPE,SUM(B.PRICE) AS PRICE FROM CLINIC_TYPE_SETTING A,CURRENT_PRICE_LIST B" \
                "WHERE A.PRICE_ITEM=B.ITEM_CODEGROUP BY A.CLINIC_TYPE) C " \
                "WHEREA.CLINIC_DEPT=B.DEPT_CODE AND A.CLINIC_TYPE=C.CLINIC_TYPE " \
                "AND A.CLINIC_DEPT LIKE '01%' " \
                "AND A.CLINIC_LABEL LIKE '%{cliniclabel}%' " \
                "ORDER BY A.CLINIC_LABEL".format(cliniclabel=cliniclabel)
      Dbconnect.cursor.execute(sql)
      sql_result = Dbconnect.cursor.fetchall()

      # 创建QStandardItemModel实例
      model = QStandardItemModel()
      # 设置此模型的列标题
      model.setHorizontalHeaderLabels(['价格', '挂号等级', '号别', '科室', '号别类型', '楼层'])
      # 填充单元格数据
      row = len(sql_result)
      column = model.columnCount()
      for i in range(row):
            for j in range(column):
                item = QStandardItem(str(sql_result))
                model.setItem(i, j, item)
      self.tableView.setModel(model)
      # 框体不可编辑
      self.tableView.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
      self.tableView.show()

    def cliprice_modify(self):
      # 定位到【价格】列
      self.tableView.selectColumn(0)
      self.tableView.setSelectionBehavior(QAbstractItemView.SelectColumns)
      # 设置QTableView单列可编辑
      #第0列price可编辑
      delegate = self.tableView.setEditTriggers(QAbstractItemView.EditTrigger.DoubleClicked)
      self.tableView.setItemDelegateForColumn(0, delegate)
      #第1列type可编辑(此处通过ComboBoxDelegate的SQL语句传入像column1传入type)
      delegate2 = ComboBoxDelegate(self.tableView)
      self.tableView.setItemDelegateForColumn(1, delegate2)

https://t3.wodetu.cn/2023/07/06/18e99858af7fd2bed8ac77644d966c92.png

调试还是有点问题。还请务必帮忙解答一下
1.ComboBoxDelegate类里Qt.EditRole我点不出来。但是可以Qt.ItemDataRole.EditRole,是否需要更换
2.点击修改后,传参似乎有问题,没有取到price,取到了“专科”
https://t4.wodetu.cn/2023/07/06/e1ee991532a6f694d8cca6ac3f1c89ab.png
应该是入参错误导致的sql报错,如何才能取到price

isdkz 发表于 2023-7-6 15:08:51

hejialiangya 发表于 2023-7-6 15:05
三位大哥的思路我都学习了一遍,并尝试写了一下。暂时采用了您的。

以下是全部功能代码


对于问题1, Qt.EditRole 和 Qt.ItemDataRole.EditRole 的作用是相同的,都是用来获取或设置用于编辑数据的角色。如果 Qt.EditRole 不能工作,你可以试试 Qt.ItemDataRole.EditRole 。Qt的版本可能会影响这个问题。

对于问题2,由于你在 setEditorData 函数中设置了 price 作为查询参数,你可能需要确保在模型中正确设置了价格数据。否则,你可能会获取到错误的数据。你需要检查你的数据模型和查询代码,确保你正在查询正确的列,并且在模型中正确设置了数据。

另外, createEditor 和 setEditorData 函数通常是在用户开始编辑单元格时调用的。你可以检查一下这些函数是否在正确的时间和地点调用。如果有需要,你可以添加一些打印语句,来帮助你调试问题。

你在使用 setEditorData 的时候,取到的是选中单元格的数据,但是这个数据是关联到你单元格的model的,你需要确保model里面的数据是你想要的。从你的描述看, setEditorData 拿到的数据是"专科"而不是价格,这个看起来像是拿到的是你单元格的显示数据而不是隐藏的价格数据。

我猜测你可能将价格作为隐藏数据存储在单元格中,而显示的数据是其他的。如果是这样的话,你需要在获取价格数据的时候,使用正确的角色(role)从模型中获取数据。在Qt中,每一个单元格的数据都可以通过不同的角色获取到。例如, Qt.DisplayRole 用来获取显示的数据, Qt.EditRole 用来获取编辑的数据。

你可能需要将价格数据存储在 Qt.UserRole 或者其他的自定义角色中,然后在 setEditorData 函数中,使用这个角色来获取价格数据。

例如:

def setEditorData(self, editor, index):
    # 这个函数用来设置编辑器的数据
    price = index.model().data(index, Qt.UserRole)
    ...


然后在你设置模型数据的时候,你也需要使用这个角色来设置价格数据:

# 填充单元格数据
row = len(sql_result)
column = model.columnCount()
for i in range(row):
    for j in range(column):
      item = QStandardItem(str(sql_result))
      # 使用UserRole来设置价格数据
      item.setData(sql_result, Qt.UserRole)
      model.setItem(i, j, item)


请注意,你可能需要根据你的实际需求对这段代码进行一些修改。

hejialiangya 发表于 2023-7-6 19:39:29

isdkz 发表于 2023-7-6 15:08
对于问题1, Qt.EditRole 和 Qt.ItemDataRole.EditRole 的作用是相同的,都是用来获取或设置用于编辑数据 ...

越说越迷糊了,如何才能取到修改后的值price=25。
页: [1]
查看完整版本: QTableView内嵌QComboBox,请问如何实现,我写不出来了