pyqt在表中自动完成

时间:2018-01-06 00:43:19

标签: python pyqt pyqt5 qtablewidget qcompleter

我需要在表格中自动完成。到目前为止,我可以使它工作,我得到整个表的相同列表。

但是,我需要每个单元格的动态列表。当我移动到单元格中的新位置时,如何更新列表?

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys


class mainWindow(QMainWindow):

    def __init__(self, parent = None):
        super(mainWindow, self).__init__(parent)

        self.initUI()


    def initUI(self):
        self.center_window = centerWindow(parent=self)
        self.setCentralWidget(self.center_window)


class centerWindow(QWidget):
    def __init__(self, parent=None):
        super(centerWindow, self).__init__(parent)

        table = QTableWidget()
        table.setItemDelegate(TableItemCompleter())
        table.setRowCount(5)
        table.setColumnCount(1)

        vbox = QVBoxLayout(self)
        vbox.addWidget(table)
        self.setLayout(vbox)


class TableItemCompleter(QStyledItemDelegate):
    def __init__(self, parent = None):
        super(TableItemCompleter, self).__init__(parent)

    def createEditor(self, parent, styleOption, index):
        editor = QLineEdit(parent)

        completion_ls = ['aaa', 'bbb', 'ccc']

        autoComplete = QCompleter(completion_ls)
        editor.setCompleter(autoComplete)
        return editor


if __name__ == '__main__':
    app = QApplication.instance()
    if app is None:
        app = QApplication(sys.argv)
    else:
        print('QApplication instance already exists: %s' % str(app))


    ex = mainWindow()
    ex.show()
    sys.exit(app.exec_())

使其更清晰。我没有在completion_ls中添加TableItemCompleter列表,而是想添加以下内容:

table.setItem(row, column) #add my new auto completion list

1 个答案:

答案 0 :(得分:1)

QCompleter可以建立一个用作自动填充源的模型,我们可以传递QModelIndex模型,提供方法createEditor(self, parent, option, index)index.model()但是问题是你只能采取一个列,而不是你想要的。

然后我们必须将tablemodel转换为listmodel,然后我们必须过滤重复的元素,以便完成者显示唯一元素,一种方法是通过代理,继承自QAbstractProxyModel的类,方案如下:

TableModel ----> ReadTable2ListProxyModel ----> DuplicateFilterProxyModel

En lasiguientesecciónsmuestros las clases:

class ReadTable2ListProxyModel(QIdentityProxyModel):
    def columnCount(self, parent=QModelIndex()):
        return 1

    def rowCount(self, parent=QModelIndex()):
        return self.sourceModel().rowCount() * self.sourceModel().columnCount()

    def mapFromSource(self, sourceIndex):
        if sourceIndex.isValid() and sourceIndex.column() == 0\
                and sourceIndex.row() < self.rowCount():
            r = sourceIndex.row()
            c = sourceIndex.column()
            row = sourceIndex.model().columnCount() * c + r
            return self.index(row, 0)
        return QModelIndex()

    def mapToSource(self, proxyIndex):
        r = proxyIndex.row() / self.sourceModel().columnCount()
        c = proxyIndex.row() % self.sourceModel().columnCount()
        return self.sourceModel().index(r, c)

    def index(self, row, column, parent=QModelIndex()):
        return self.createIndex(row, column)


class DuplicateFilterProxyModel(QSortFilterProxyModel):
    def setSourceModel(self, model):
        model.dataChanged.connect(lambda: self.invalidate())
        QSortFilterProxyModel.setSourceModel(self, model)

    def filterAcceptsRow(self, row, parent):
        value = self.sourceModel().index(row, self.filterKeyColumn())\
            .data(self.filterRole())
        if value is None:
            return False
        if row == 0:
            return True
        for i in reversed(range(0, row)):
            val = self.sourceModel().index(i, self.filterKeyColumn())\
                .data(self.filterRole())
            if val == value:
                return False
        return True

然后在委托中建立转换:

class TableItemCompleter(QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        editor = QLineEdit(parent)
        completer = QCompleter(parent)

        proxy1 = ReadTable2ListProxyModel(parent)
        proxy2 = DuplicateFilterProxyModel(parent)
        proxy1.setSourceModel(index.model())
        proxy2.setSourceModel(proxy1)

        completer.setModel(proxy2)
        editor.setCompleter(completer)
        return editor

在下面的link中,您将找到一个示例,并在下图中显示操作,在第一个窗口小部件中观察表,在第二个窗口中转换为列表,在第三个窗口中删除列表重复元素。

enter image description here

如果您希望每个项目都有一个列表,可以做的是通过Qt.UserRole方法通过setData()未使用的角色将列表存储在每个项目中,并且通过data()

的方法QModelIndex进行委派
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import random

class TableItemCompleter(QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        editor = QLineEdit(parent)
        completion_ls = index.data(Qt.UserRole) # get list
        completer = QCompleter(completion_ls, parent)
        editor.setCompleter(completer)
        return editor

class Widget(QWidget):
    def __init__(self, *args, **kwargs):
        QWidget.__init__(self, *args, **kwargs)
        lay = QHBoxLayout(self)
        tv = QTableWidget(3, 4, self)
        lay.addWidget(tv)
        l = ["AA", "AB", "AC", "AD", "BA", "BB", "BC"]
        for i in range(tv.rowCount()):
            for j in range(tv.columnCount()):
                it = QTableWidgetItem(f"{i},{j}")
                tv.setItem(i, j, it)
                it.setData(Qt.UserRole, random.sample(l, 3)) # set list
        tv.setItemDelegate(TableItemCompleter(tv))


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())