hejialiangya 发表于 2023-7-7 10:43:30

[Python,Pyqt]这里可以发悬赏帖吗?有偿修改代码,重写QComboBox委托,50-100左右

昨天发帖学习了委托,实验了以后实在是写不出来,老报错。想花钱请人帮忙,我自己顺便再跟着代码学一下
https://t3.wodetu.cn/2023/07/07/88b9fba9c140299fa8321df0dd34cc67.png
https://t4.wodetu.cn/2023/07/07/e3371affe2b7fa7fb35173febc6eca48.png
需求:
点修改按钮,TableView,第1,2列可编辑   (已实现)
双击price后,price清空,输入金额,sql会匹配,有返回值。就把返回值传给ComboBox,并将ComboBox显示在【挂号等级type】列。(未实现)
无返回值,则提示“没有价格为{price}的号”(已实现)

目前未完成的代码如下:

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)

    def actprice_open(self):
      a = self.windowTitle()
      if (a.split() == '门诊办'):
            self.clipricemodi_window.show()
      else:
            QMessageBox.critical(self, '没有操作权限', '您不是门诊办人员!')

#重写ComboBox委托
class ComboBoxDelegate(QStyledItemDelegate):
    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.ItemDataRole.DisplayRole)
      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(str(i))
      # 设置当前选中的项
      editor.setCurrentIndex(editor.findText(price))

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

    #触发事件:【价格price】变化,【挂号等级type】同步更新并传入ComboBox,类似触发器
    def onDataChanged(self, index):
      pass
      这一块还没写,不会写


#门诊办专区号表价格修改
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()

    #点击修改按钮,想实现的modify函数,tableview的【价格price】变化,【挂号等级type】同步更新并传入ComboBox
    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可编辑
      delegate2 = ComboBoxDelegate(self.tableView)
      self.tableView.setItemDelegateForColumn(0, delegate2)
      # 信号槽连接
      model.dataChanged.connect(self.onDataChanged)


第一次请人帮忙,价格暂定50-100左右,如果可以发咸鱼,我去拍。价格不对也请指正

陶远航 发表于 2023-7-7 10:45:02

首先,关于您的问题,这里并不是一个发布悬赏帖的平台。但是,我会尽力帮助您解决问题。

根据您的代码和需求,我对您的代码进行了修改。以下是修改后的代码:

# 省略了其他没有改动的部分

# 重写ComboBox委托
class ComboBoxDelegate(QStyledItemDelegate):
    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.ItemDataRole.DisplayRole)
      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()
      for i in sqlprice_result:
            editor.addItem(str(i))
      editor.setCurrentIndex(editor.findText(price))

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

    def onDataChanged(self, index):
      pass

# 省略了其他没有改动的部分

# 点击修改按钮,想实现的modify函数,tableview的【价格price】变化,【挂号等级type】同步更新并传入ComboBox
def cliprice_modify(self):
    self.tableView.selectColumn(0)
    self.tableView.setSelectionBehavior(QAbstractItemView.SelectColumns)
    delegate = QStyledItemDelegate()
    self.tableView.setItemDelegateForColumn(0, delegate)
    delegate2 = ComboBoxDelegate(self.tableView)
    self.tableView.setItemDelegateForColumn(1, delegate2)
    self.tableView.model().dataChanged.connect(self.onDataChanged)

# 省略了其他没有改动的部分


主要的修改:

1. 在cliprice_modify函数中,我改了您设置delegate和delegate2的方式。这样,第 0 列和第 1 列可以分别使用不同的委托。
2. 我删除了设置编辑触发器 ( setEditTriggers ) 的语句,因为您已经通过委托来控制编辑行为。

希望这些修改能帮助您完成您的需求。如果您还有其他问题,请随时提问。

sfqxx 发表于 2023-7-7 10:58:16

2#说法错误

新鱼油不可以发悬赏帖,理论上可以发,但只能设置鱼币悬赏

根据你提供的代码,我看到你已经完成了大部分工作。在`ComboBoxDelegate`类中,你可以添加一个新的方法来处理数据变化的信号槽连接。

首先,你需要导入`QtCore`模块:

from PySide6.QtCore import Qt, QObject, Signal
然后,在`ComboBoxDelegate`类中,添加如下方法:

class ComboBoxDelegate(QStyledItemDelegate):
    # ...

    def onDataChanged(self, index):
      # 获取编辑器的数据
      editor = self.sender()
      value = editor.currentText()

      # 获取当前行的价格值
      price_index = index.sibling(index.row(), 0)
      price = price_index.data(Qt.DisplayRole)

      # 进行价格匹配查询
      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_CODE GROUP BY A.CLINIC_TYPE) C " \
                   "WHERE C.PRICE = '{price}'".format(price=price)
      Dbconnect.cursor.execute(sqlprice)
      sqlprice_result = Dbconnect.cursor.fetchall()

      if sqlprice_result:
            # 如果有返回值,则将返回值传给ComboBox
            types = ) for i in sqlprice_result]
            self.setModelData(editor, None, index, types)
      else:
            # 如果没有返回值,则显示提示信息
            QMessageBox.information(None, '提示', '没有价格为{price}的号'.format(price=price))

    def setModelData(self, editor, model, index, types):
      # 清空ComboBox并添加新的选项
      editor.clear()
      editor.addItems(types)

      # 设置当前选中的项
      value = index.model().data(index, Qt.DisplayRole)
      editor.setCurrentIndex(editor.findText(value))

最后,在`CliPriceModifyWindow`类的`cliprice_modify`方法中,连接信号槽:

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_modify(self):
      # ...

      # 设置QTableView单列可编辑
      delegate = self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked)
      self.tableView.setItemDelegateForColumn(0, delegate)

      # 创建ComboBoxDelegate实例
      delegate2 = ComboBoxDelegate(self.tableView)

      # 设置代理编辑器的信号槽连接
      delegate2.dataChanged.connect(delegate2.onDataChanged)

      # 设置第1列的代理编辑器
      self.tableView.setItemDelegateForColumn(1, delegate2)

这样,当用户双击价格单元格时,会触发`ComboBoxDelegate`中的`onDataChanged`方法,根据价格匹配结果更新ComboBox的选项。如果有返回值,则将返回值传给ComboBox,并将其显示在挂号等级(type)列;如果没有返回值,则显示相应的提示信息。

希望这可以帮助到你,如果有任何进一步的问题,请随时提问。

hejialiangya 发表于 2023-7-7 11:46:32

本帖最后由 hejialiangya 于 2023-7-7 11:53 编辑

sfqxx 发表于 2023-7-7 10:58
2#说法错误

新鱼油不可以发悬赏帖,理论上可以发,但只能设置鱼币悬赏


   delegate2.dataChanged.connect(delegate2.onDataChanged)
    ^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'ComboBoxDelegate' object has no attribute 'dataChanged'. Did you mean: 'onDataChanged'?

我.不出dataChanged这个方法


还有一个问题,我从昨天开始就一直想问。
class ComboBoxDelegate(QStyledItemDelegate)
edit不是QComboBox的实例化吗?
为什么里面所有的def,只要是edit.都点不出来,【比如editor.addItem(str(i)),editor.setCurrentIndex(editor.findText(value))】,但是将edit替换成QComboBox就可以正常.出其方法

sfqxx 发表于 2023-7-7 11:48:41

hejialiangya 发表于 2023-7-7 11:46
delegate2.dataChanged.connect(delegate2.onDataChanged)
    ^^^^^^^^^^^^^^^^^^^^^
AttributeErr ...

对不起,我之前犯了一个错误。确实没有`dataChanged`信号,而是应该连接`editor`的`currentTextChanged`信号。请修改`ClipriceModifyWindow`类中的代码如下:

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_modify(self):
      # ...

      # 设置QTableView单列可编辑
      delegate = self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked)
      self.tableView.setItemDelegateForColumn(0, delegate)

      # 创建ComboBoxDelegate实例
      delegate2 = ComboBoxDelegate(self.tableView)

      # 连接代理编辑器的信号槽
      editor = delegate2.createEditor(None, None, None)
      if isinstance(editor, QComboBox):
            editor.currentTextChanged.connect(delegate2.onDataChanged)

      # 设置第1列的代理编辑器
      self.tableView.setItemDelegateForColumn(1, delegate2)

这样,当用户选择ComboBox中的项时,会触发`ComboBoxDelegate`中的`onDataChanged`方法。

非常抱歉给你带来困扰,请试试这个修改后的代码看是否可以正常工作。如果还有其他问题,请随时提问。

Threebody1 发表于 2023-7-7 11:52:51

sfqxx 发表于 2023-7-7 11:48
对不起,我之前犯了一个错误。确实没有`dataChanged`信号,而是应该连接`editor`的`currentTextChanged` ...

......

sfqxx 发表于 2023-7-7 12:03:36

Threebody1 发表于 2023-7-7 11:52
......

……

hejialiangya 发表于 2023-7-7 12:09:29

本帖最后由 hejialiangya 于 2023-7-7 13:57 编辑

sfqxx 发表于 2023-7-7 11:48
对不起,我之前犯了一个错误。确实没有`dataChanged`信号,而是应该连接`editor`的`currentTextChanged` ...


调试时断点不触发onDataChanged的事件,
调试会提示:TypeError: ComboBoxDelegate.setModelData() missing 1 required positional argument: 'types'

sfqxx 发表于 2023-7-7 14:15:58

hejialiangya 发表于 2023-7-7 12:09
调试时断点不触发onDataChanged的事件,
调试会提示:TypeError: ComboBoxDelegate.setModelData()...

非常抱歉,我之前的代码有误。在`ComboBoxDelegate`类中,`setModelData`方法确实缺少一个必需的参数`types`,我会为你修复这个问题。

请将`ComboBoxDelegate`类的代码修改如下:

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

    def createEditor(self, parent, option, index):
      editor = QComboBox(parent)
      editor.currentTextChanged.connect(self.onDataChanged)
      return editor

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

    def setModelData(self, editor, model, index):
      value = editor.currentText()
      if value not in self.types:
            QMessageBox.information(None, '提示', '没有价格为{value}的诊所类型'.format(value=value))
            return
      super(ComboBoxDelegate, self).setModelData(editor, model, index)

    def setTypes(self, types):
      self.types = types

    def onDataChanged(self, text):
      editor = self.sender()
      self.commitData.emit(editor)

然后,在`cliprice_modify`方法中,将设置代理编辑器的代码修改如下:

def cliprice_modify(self):
    # ...

    # 创建ComboBoxDelegate实例
    delegate2 = ComboBoxDelegate(self.tableView)

    # 设置第1列的代理编辑器
    self.tableView.setItemDelegateForColumn(1, delegate2)

    # 获取当前行的价格值
    price_idx = self.tableView.model().index(row, 0)
    price = price_idx.data(Qt.DisplayRole)

    # 进行价格匹配查询
    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_CODE GROUP BY A.CLINIC_TYPE) C " \
               "WHERE C.PRICE = '{price}'".format(price=price)
    Dbconnect.cursor.execute(sqlprice)
    sqlprice_result = Dbconnect.cursor.fetchall()

    if sqlprice_result:
      # 如果有返回值,则将返回值传给ComboBox
      types = ) for i in sqlprice_result]
      delegate2.setTypes(types)
    else:
      # 如果没有返回值,则显示提示信息
      QMessageBox.information(None, '提示', '没有价格为{price}的号'.format(price=price))

这样,当进入编辑状态并选择其他诊所类型时,会触发`ComboBoxDelegate`中的`onDataChanged`方法。

非常抱歉之前给你带来的困惑,请尝试这个更新后的代码,并再次进行调试。如果还有任何问题,请随时告诉我。
页: [1]
查看完整版本: [Python,Pyqt]这里可以发悬赏帖吗?有偿修改代码,重写QComboBox委托,50-100左右