持续分类的选择qcombobox-qcompleter弹出窗口



我有一个从QCombobox派生的自定义类,带有基础自定义列表模型(源自QAbstractListModel(。该模型允许用户从选项(通过检查成员(中进行多个选择。COMBOBOX是由在QAbstractTableModel派生的实例上工作的代表(衍生自QItemDelegate(创建的。这个想法是,从选择中,表模型将选择的选择将选择成员存储为列表,并将其显示为列表的字符串表示形式。

到目前为止,我的实施有效,但我还没有完成两件事:

  1. 用户将文本插入完成器后,所显示的结果列表未按字母顺序排序(在完成者的弹出窗口上(。
  2. 每次我单击完成者的输出列表(弹出窗口(时,视图皮革/关闭(我不确定哪一个(一次阻止一次选择多个项目。

这是我实现的一个简短(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_()

好的,所以我找到了两个问题的解决方案。

首先,对于完成器输出的排序:我将QLineEdit.textEdited信号连接到ComboBox中的自定义插槽。该插槽迫使QSortFilterProxyModel实例按第0列对基础模型进行排序。

第二,对于完工弹出窗口上的"单击"问题:这是一个头钩。几个小时后,在活动和过滤器上进行了几个小时的播放,我意识到视图上的鼠标Realease事件(弹出窗口(发出了点击信号(多亏了该文档(,我相信,此信号已连接到的"隐藏"插槽风景。因此,我的解决方案是一个丑陋的黑客,但同样,它可以起作用。我写了自己的观点,源自QListView,并覆盖mouseReleaseEvent方法,在该方法上,我在其上阻止了所有信号,然后处理该事件。为了实现这一目标,我必须通过Combobox实例我的视图类。

这是经过修改或添加到初始发布的代码以工作的类:

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)

相关内容

  • 没有找到相关文章

最新更新