【问题标题】:pyqt auto completion in a table表格中的pyqt自动完成
【发布时间】:2018-06-15 20:00:25
【问题描述】:

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

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

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_())

为了更清楚。我不想在TableItemCompleter 中添加completion_ls 列表,而是添加如下内容:

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

【问题讨论】:

    标签: python pyqt pyqt5 qtablewidget qcompleter


    【解决方案1】:

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

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

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

    En la siguiente sección muestros 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 中,您将找到一个示例,并且在下图中说明了操作,在第一个小部件中观察表格,在第二个小部件中转换为列表,在第三个中删除重复元素.


    如果您希望每个项目都有一个列表,可以做的是通过Qt.UserRole 方法通过Qt.UserRole 方法将列表存储在每个项目中,并通过该方法在委托中存储列表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_())
    

    【讨论】:

    • 非常感谢您的回答。但是,这并不是我想要的。我完成的来源不是桌子本身。这是另一个列表。但是每个单元格的源列表都不同。
    • @StephanF。好的,现在我明白了,并更新我的答案以满足您的要求:D
    • 完美,这正是我所需要的。请注意,我必须删除 it = QTableWidgetItem() 中的参数才能使其正常工作。
    • 你用的是python2还是python3?
    • 我正在使用python2。
    猜你喜欢
    • 1970-01-01
    • 2018-11-28
    • 2021-08-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多