我有一个从QCombobox
派生的自定义类,它带有一个基础自定义列表模型(派生自QAbstractListModel
)。该模型允许用户从选项中进行多项选择(通过检查成员)。组合框是从委托(从QItemDelegate
派生)创建的,该委托在QAbstractTableModel
派生实例上工作。这个想法是,从选择中,表模型将选择存储为包含选择成员的列表,并将其显示为列表的字符串表示。
到目前为止,我的实施工作正常,但我还没有完成两件事:
以下是我的实施的简短(pyside)示例:
from PySide.QtCore import *
from PySide.QtGui import *
class MyCombobox(QComboBox):
def __init__(self, parent = None):
super(MyCombobox, self).__init__(parent)
self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True)
self.filter = QSortFilterProxyModel(self)
self.filter.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.completer = QCompleter(self.filter, self)
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.completer.setModelSorting(QCompleter.CaseInsensitivelySortedModel)
self.setCompleter(self.completer)
#signals
self.activated.connect(self._comboActivated)
self.lineEdit().textEdited[unicode].connect(self.filter.setFilterFixedString)
self.completer.activated['QModelIndex'].connect(self._completerActivated)
self._pressed = True
def _completerActivated(self, index):
if index.isValid():
self._itemPressed(index)
def setModel(self, model):
super(MyCombobox, self).setModel(model)
self.filter.setSourceModel(model)
self.completer.setModel(self.filter)
def _itemPressed(self, index):
row = index.row()
col = index.column()
index2 = self.filter.index(row, col)
index = self.filter.mapToSource(index2)
model = self.model()
state = model.data(index, role = Qt.CheckStateRole)
if state == Qt.Checked:
model.setData(index, Qt.Unchecked, Qt.CheckStateRole)
self._pressed = True
return
elif state == Qt.Unchecked:
model.setData(index, Qt.Checked, Qt.CheckStateRole)
self._pressed = True
return
else:
self._pressed = False
return
def _comboActivated(self, pos):
model = self.model()
index = model.index(pos, 0)
state = model.data(index, role = Qt.CheckStateRole)
if state == Qt.Checked:
model.setData(index, Qt.Unchecked, Qt.CheckStateRole)
self._pressed = True
return
elif state == Qt.Unchecked:
model.setData(index, Qt.Checked, Qt.CheckStateRole)
self._pressed = True
return
else:
self._pressed = False
return
def hidePopup(self):
if not self._pressed:
super(MyCombobox, self).hidePopup()
self._pressed = True
else:
self._pressed = False
class MyDelegate(QItemDelegate):
def __init__(self, parent = None):
super(MyDelegate, self).__init__(parent)
def createEditor(self, parent, option, index):
cb = MyCombobox(parent)
tableModel = index.model()
sel = tableModel._table[0][0]
model = MyModel(parent)
for k, name in enumerate(model._base):
model._checked[k] = name in sel
cb.setModel(model)
return cb
def setModelData(self, editor, model, index):
mymodel = editor.model()
sel = mymodel._checked
base = mymodel._base
myselection = [ name for k, name in enumerate(base) if sel[k] ]
model.setData(index, myselection, role = Qt.DisplayRole)
class MyModel(QAbstractListModel):
def __init__(self, parent = None):
super(MyModel, self).__init__(parent)
self._base = ["one", "two", "three", "four", "five"]
self._checked = [False for k in range(len(self._base))]
def rowCount(self, index = None):
return len(self._base)
def data(self, index, role = Qt.DisplayRole):
i = index.row()
if 0 <= i < self.rowCount():
if role == Qt.DisplayRole:
return self._base[i]
elif role == Qt.CheckStateRole:
if self._checked[i]:
return Qt.Checked
else:
return Qt.Unchecked
else:
pass
else:
pass
def setData(self, index, value, role = Qt.CheckStateRole):
i = index.row()
if 0 <= i < self.rowCount():
if role == Qt.CheckStateRole:
self._checked[i] = value == Qt.Checked
self.dataChanged.emit(index, index)
return True
else:
return super(MyModel, self).setData(index, value, role)
else:
return False
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsUserCheckable
class MyTableModel(QAbstractTableModel):
def __init__(self, table, parent = None):
super(MyTableModel, self).__init__(parent)
self._table = table
def rowCount(self, index = None):
return len(self._table)
def columnCount(self, index = None):
if self._table: return len(self._table[0])
return 0
def data(self, index, role = Qt.DisplayRole):
i, j = index.row(), index.column()
if role == Qt.DisplayRole:
return unicode(self._table[i][j])
def setData(self, index, value, role = Qt.DisplayRole):
i, j = index.row(), index.column()
if role == Qt.DisplayRole:
self._table[i][j] = value
def flags(self, index):
return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
if __name__ == '__main__':
app = QApplication("test")
tableView = QTableView()
model = MyTableModel([[["numbers"]]])
tableView.setModel(model)
delegate = MyDelegate(tableView)
tableView.setItemDelegate(delegate)
tableView.show();
app.exec_()
答案 0 :(得分:0)
好的,所以我找到了解决这两个问题的方法。
首先,对于完成输出的排序:我将QLineEdit.textEdited
信号连接到组合框中的自定义插槽。此插槽强制QSortFilterProxyModel
实例按列0对基础模型进行排序。不是很好,但有效。
第二,点击&#34;点击&#34;完成弹出窗口的问题:这是一个头脑。在玩了几个小时的事件和过滤器后,我意识到视图上的鼠标重新发布事件(弹出窗口)发出了点击的信号(感谢文档),我相信,这个信号已连接到&#34;隐藏& #34;视图的插槽。所以我的解决方案是一个丑陋的黑客,但同样,它的工作原理。我编写了自己的QListView
视图,并覆盖mouseReleaseEvent
方法,我阻止所有信号然后处理事件。为了实现这一点,我不得不将组合框实例传递给我的视图类。
以下是为了工作而修改或添加到初始发布代码的类:
class MyCombobox(QComboBox):
def __init__(self, parent=None):
super(MyCombobox, self).__init__(parent)
self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True)
self.filter = QSortFilterProxyModel(self)
self.filter.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.completer = QCompleter(self.filter, self)
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.completer.setModelSorting(QCompleter.CaseInsensitivelySortedModel)
self.setCompleter(self.completer)
# signals
self.activated.connect(self._comboActivated)
self.lineEdit().textEdited[unicode].connect(self.filter.setFilterFixedString)
self.lineEdit().textEdited[unicode].connect(self._sort)
self.completer.activated['QModelIndex'].connect(self._completerActivated)
mlview = MyListView(self)
mlview.setEditTriggers(self.view().editTriggers())
self.completer.setPopup(mlview)
self._pressed = True
def _completerActivated(self, index):
if index.isValid():
self._itemPressed(index)
def setModel(self, model):
super(MyCombobox, self).setModel(model)
self.filter.setSourceModel(model)
self.completer.setModel(self.filter)
def _itemPressed(self, index):
row = index.row()
col = index.column()
index2 = self.filter.index(row, col)
index = self.filter.mapToSource(index2)
model = self.model()
state = model.data(index, role = Qt.CheckStateRole)
if state == Qt.Checked:
model.setData(index, Qt.Unchecked, Qt.CheckStateRole)
self._pressed = True
return
elif state == Qt.Unchecked:
model.setData(index, Qt.Checked, Qt.CheckStateRole)
self._pressed = True
return
else:
self._pressed = False
return
def _comboActivated(self, pos):
model = self.model()
index = model.index(pos, 0)
state = model.data(index, role = Qt.CheckStateRole)
if state == Qt.Checked:
model.setData(index, Qt.Unchecked, Qt.CheckStateRole)
self._pressed = True
return
elif state == Qt.Unchecked:
model.setData(index, Qt.Checked, Qt.CheckStateRole)
self._pressed = True
return
else:
self._pressed = False
return
def _sort(self, arg = None):
self.filter.sort(0)
def hidePopup(self):
if not self._pressed:
super(MyCombobox, self).hidePopup()
self._pressed = True
else:
self._pressed = False
class MyListView(QListView):
def __init__(self, widget, parent = None):
super(MyListView, self).__init__(parent)
self._widget = widget
self.setSelectionMode(QListView.SingleSelection)
self.setFocusPolicy(Qt.StrongFocus)
self.setSelectionBehavior(QListView.SelectItems)
def mouseReleaseEvent(self, event):
self.blockSignals(True)
super(MyListView, self).mouseReleaseEvent(event)
self.blockSignals(False)
index = self.currentIndex()
if not index.isValid(): return
self._widget._itemPressed(index)