在QTableView中正确使用QComboBox--数据设置和清除QComboBoxes的问题。

问题描述 投票:2回答:1

在我的应用程序中,我使用了一个QTableView,QStandardItemModel和一个QSortFilterProxyModel来进行过滤。

内容是通过一个方法更新的列1 & 2,我希望有一个第三列供用户选择选项。我希望使用QComboBox。

我已经把所有的东西都弄好了,只是当我在第3列的任何一个单元格中选择QComboBox中的项目时,它没有被填充。这是否与我的 setModelData() 方法?

我也有一个清除按钮,我想把所有的QComboBoxes重置为第一项,也就是一个空条目。我不知道如何解决这个问题,我发现了一些方法,比如使用 deleteLater() 或设置QTableView的 setItemDelegateForColumn() 为 "无",然后重新申请。

显然这些都不是最有效的。我缺少什么?

工作的例子:在我的应用程序中,我使用了一个QTableView,QStandardItemModel和一个QSortFilterProxy。

import win32com.client
from PyQt5 import QtCore, QtGui, QtWidgets

outApp = win32com.client.gencache.EnsureDispatch("Outlook.Application")
outGAL = outApp.Session.GetGlobalAddressList()
entries = outGAL.AddressEntries

class ComboDelegate(QtWidgets.QItemDelegate):

    def __init__(self,parent=None):
        super().__init__(parent)
        self.items = ['','To', 'CC']

    def createEditor(self, widget, option, index):
        editor = QtWidgets.QComboBox(widget)
        editor.addItems(self.items)
        return editor

    def setEditorData(self, editor, index):
        if index.column() == 2:
            editor.blockSignals(True)
            text = index.model().data(index, QtCore.Qt.EditRole)
            try:
                i = self.items.index(text)
            except ValueError:
                i = 0
            editor.setCurrentIndex(i)
            editor.blockSignals(False)
        else:
            QtWidgets.QItemDelegate.setModelData(editor,model,index)

    def setModelData(self, editor, model, index):
        if index.column() == 2:
            model.setData(index, editor.currentText())
        else:
            QtWidgets.QItemDelegate.setModelData(editor,model,index)

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

    def paint(self, painter, option, index):
        QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_ItemViewItem, option, painter)

class App(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        """This method creates our GUI"""
        self.centralwidget = QtWidgets.QWidget()
        self.setCentralWidget(self.centralwidget)
        self.lay = QtWidgets.QVBoxLayout(self.centralwidget)
        self.filterEdit = QtWidgets.QLineEdit()
        self.filterEdit.setPlaceholderText("Type to filter name.")
        self.label = QtWidgets.QLabel("Select an option for each person:")
        self.button = QtWidgets.QPushButton("Test Button")
        self.button.clicked.connect(self.runButton)
        self.resetbutton = QtWidgets.QPushButton("Clear")
        self.resetbutton.clicked.connect(self.clear)
        self.lay.addWidget(self.filterEdit)
        self.lay.addWidget(self.label)

        self.tableview=QtWidgets.QTableView(self.centralwidget)
        self.model=QtGui.QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['Name','Address','Option'])
        self.tableview.verticalHeader().hide()
        self.tableview.setSelectionBehavior(QtWidgets.QTableView.SelectRows)
        self.tableview.setEditTriggers(QtWidgets.QAbstractItemView.AllEditTriggers)
        self.proxyModel = QtCore.QSortFilterProxyModel(self)
        self.proxyModel.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxyModel.setSourceModel(self.model)
        self.proxyModel.sort(0,QtCore.Qt.AscendingOrder)
        self.proxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.tableview.setModel(self.proxyModel)

        self.model.insertRow(self.model.rowCount(QtCore.QModelIndex()))
        #self.fillModel(self.model) #uncomment if you have outlook

        self.tableview.resizeColumnsToContents()
        self.tableview.verticalHeader().setDefaultSectionSize(10)
        self.filterEdit.textChanged.connect(self.onTextChanged)
        self.lay.addWidget(self.tableview)
        self.delegate = ComboDelegate()
        self.tableview.setItemDelegateForColumn(2, self.delegate)
        self.lay.addWidget(self.button)
        self.lay.addWidget(self.resetbutton)

        self.setMinimumSize(450, 200)
        self.setMaximumSize(1500, 200)
        self.setWindowTitle('Application')

    def clear(self):
        ###clear tableview comboboxes in column 3
        print("clear")

    def runButton(self,index):
        print("Do stuff")

    def fillModel(self,model):
        """Fills model from outlook address book """
        nameList = []
        addressList = []
        for row,entry in enumerate(entries):
            if entry.Type == "EX":
                user = entry.GetExchangeUser()
                if user is not None:
                    if len(user.FirstName) > 0 and len(user.LastName) > 0:
                        nameItem = QtGui.QStandardItem(str(user.Name))
                        emailItem = QtGui.QStandardItem(str(user.PrimarySmtpAddress))
                        nameItem.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
                        emailItem.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
                        model.appendRow([nameItem,emailItem])

    @QtCore.pyqtSlot(str)
    def onTextChanged(self, text):
        self.proxyModel.setFilterRegExp(text)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = App()
    w.show()
    sys.exit(app.exec_())
python-3.x pyqt5 qtableview qcombobox
1个回答
3
投票

问题是你不必要地覆盖了paint方法,因为你不想定制任何东西。在覆盖之前,我建议你了解它的作用,为此你可以使用文档或源代码。但是总结一下,在QItemDelegate的情况下,paint方法在 "选项 "中建立了角色的信息,然后只需进行绘制,在这些信息中是文本。但在你的情况下,这不是必要的,所以没有必要覆盖。另一方面,如果你的委托人只有建立一个QComboBox的功能,那么你就不必验证列。考虑到以上所有情况,我将你的委托人简化为。

class ComboDelegate(QtWidgets.QItemDelegate):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.items = ["", "To", "CC"]

    def createEditor(self, widget, option, index):
        editor = QtWidgets.QComboBox(widget)
        editor.addItems(self.items)
        return editor

    def setEditorData(self, editor, index):
        editor.blockSignals(True)
        text = index.model().data(index, QtCore.Qt.EditRole)
        try:
            i = self.items.index(text)
        except ValueError:
            i = 0
        editor.setCurrentIndex(i)
        editor.blockSignals(False)

    def setModelData(self, editor, model, index):
        model.setData(index, editor.currentText())

另一方面,QItemEditorFactory使用qproperty user作为更新的参数,在QComboBox的情况下,它是 "currentText",所以可以利用这些信息进一步简化。

class ComboDelegate(QtWidgets.QItemDelegate):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.items = ["", "To", "CC"]

    def createEditor(self, widget, option, index):
        editor = QtWidgets.QComboBox(widget)
        editor.addItems(self.items)
        return editor

清除方法很简单: 遍历第三列的所有行,然后设置空文本。

def clear(self):
    # clear tableview comboboxes in column 3
    for i in range(self.model.rowCount()):
        index = self.model.index(i, 2)
        self.model.setData(index, "")
© www.soinside.com 2019 - 2024. All rights reserved.