In my application im using a QTableView, QStandardItemModel and a QSortFilterProxyModel in between for filtering.
The content is updated via a method for columns 1 & 2, and I want there to be a 3rd column for user to select options. I would prefer to use a QComboBox.
I've got everything pretty much working, except that when I select the item from the QComboBox in any of the cells in column 3, it doesn't populate. Does it have something to do with my setModelData() method?
I also have a clear button that I would like to reset all of the QComboBoxes to the first item which is an empty entry. I am not sure how to tackle this, i've found such things as using deleteLater() or setting the QTableView's setItemDelegateForColumn() to None and re-apply.
Obviously these are not the most efficient. What am I missing?
Working example:
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_())