使用 QLineEdit 和 QItemDelegate 完成



我正在尝试实现我们可以在小部件/工具/自定义完成器源中找到的QCompleter示例。我想要的是当我键入一些文本时,如果有一些匹配项,则选择可用的第一行完成行,因此如果我按回车键(并且仅当我按下它时(,完成就完成了。

但是在我的代码中,该行从未被选中。我认为我的问题位于keyPressEvent中,但我不知道在哪里。这是一个最小的例子,用pyqt5(5.10(和Python 3.5.2编写。

任何帮助都非常感谢:)

此致敬意

import sys
from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant
from PyQt5.QtWidgets import (QApplication, QCompleter, QItemDelegate,
                             QLineEdit, QMainWindow, QTableView)

class MyLineEdit(QLineEdit):
    def __init__(self, parent=None, completer=None):
        super().__init__(parent)
        if completer:
            self.setCompleter(completer)
    def setCompleter(self, completer):
        if completer:
            completer.setWidget(self)
            completer.setCompletionMode(QCompleter.PopupCompletion)
            completer.setCaseSensitivity(Qt.CaseInsensitive)
            completer.setModelSorting(
                QCompleter.CaseSensitivelySortedModel)
            completer.setMaxVisibleItems(15)
            completer.activated.connect(self.insertCompletion)
        super().setCompleter(completer)
    def insertCompletion(self, completion):
        completer = self.completer()
        if completer and completer.widget() == self:
            completer.widget().setText(completion)
    def keyPressEvent(self, event):
        completer = self.completer()
        if event.key() in (Qt.Key_Return, Qt.Key_Enter,
                           Qt.Key_Tab, Qt.Key_Backtab):
            self.returnPressed.emit()
            if completer and completer.popup().isHidden():
                return
        super().keyPressEvent(event)
        input_text = self.text()
        if completer:
            if not event.text():
                completer.popup().hide()
                return
            if input_text and input_text != completer.completionPrefix():
                completer.setCompletionPrefix(input_text)
                completer.popup().setCurrentIndex(
                    completer.completionModel().index(0, 0))

class MyDelegate(QItemDelegate):
    def __init__(self, parent):
        super().__init__(parent)
    def createEditor(self, parent, option, index):
        strings = ('tata', 'tete', 'titi', 'toto', 'tutu')
        completer = QCompleter(strings)
        editor = MyLineEdit(parent)
        editor.setCompleter(completer)
        editor.editingFinished.connect(self.commitAndCloseEditor)
        editor.returnPressed.connect(self.commitAndCloseEditor)
        return editor
    def commitAndCloseEditor(self):
        editor = self.sender()
        self.commitData.emit(editor)
        self.closeEditor.emit(editor)
    def setEditorData(self, editor, index):
        if editor:
            editor.setText(index.model().data[0])
    def setModelData(self, editor, model, index):
        if editor:
            model.setData(index, editor.text(), Qt.EditRole)

class Model(QAbstractTableModel):
    def __init__(self):
        super().__init__()
        self.data = ['hello']
    def rowCount(self, parent=None):
        return 1
    def columnCount(self, parent=None):
        return 1
    def data(self, index, role):
        if not index.isValid():
            return QVariant()
        if role in (Qt.DisplayRole, Qt.EditRole):
            return self.data[0]
        return QVariant()
    def setData(self, index, value, role):
        if role == Qt.EditRole:
            self.data[0] = value
            top_left = self.index(0, 0)
            bottom_right = self.index(
                self.rowCount() + 1, self.columnCount())
            self.dataChanged.emit(top_left, bottom_right,
                                  [Qt.DisplayRole])
            return True
        return False
    def flags(self, index):
        return Qt.ItemIsEditable | super().flags(index)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.model = Model()
        self.table = QTableView()
        self.table.setModel(self.model)
        delegate = MyDelegate(self.table)
        self.table.setItemDelegateForColumn(0, delegate)
    def initUI(self):
        self.show()
        self.setCentralWidget(self.table)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.initUI()
    sys.exit(app.exec_())

试试看:

import sys
from PyQt5 import QtCore, QtWidgets 
class LineEdit(QtWidgets.QLineEdit):
    def __init__(self, *args, **kwargs):
        QtWidgets.QLineEdit.__init__(self, *args, **kwargs)
        self.multipleCompleter = None
    def keyPressEvent(self, event):
        QtWidgets.QLineEdit.keyPressEvent(self, event)
        if not self.multipleCompleter:
            return
        c = self.multipleCompleter
        if self.text() == "":
            return
        c.setCompletionPrefix(self.cursorWord(self.text()))
        if len(c.completionPrefix()) < 1:
            c.popup().hide()
            return
        c.complete()
    def cursorWord(self, sentence):
        p = sentence.rfind(" ")
        if p == -1:
            return sentence
        return sentence[p + 1:]
    def insertCompletion(self, text):
        p = self.text().rfind(" ")
        if p == -1:
            self.setText(text)
        else:
            self.setText(self.text()[:p+1]+ text)
    def setMultipleCompleter(self, completer):
        self.multipleCompleter = completer
        self.multipleCompleter.setWidget(self)
        completer.activated.connect(self.insertCompletion)

def main():
    app = QtWidgets.QApplication(sys.argv)
    w   = LineEdit()
    completer = QtWidgets.QCompleter(['tata', 'tete', 'titi', 'toto', 'tutu'])
    completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
    w.setMultipleCompleter(completer)
    w.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

终于找到了解决方案。我使用了QTextEdit,它不适用于QLineEdit,我不知道为什么。我仍然有一个小问题,当我点击返回键时无法关闭完成弹出窗口,所以我必须按回车键,两次。问题不大。

import sys
from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant, pyqtSignal
from PyQt5.QtGui import QTextCursor, QTextOption
from PyQt5.QtWidgets import (QAbstractItemDelegate, QApplication, QCompleter,
                             QItemDelegate, QMainWindow, QTableView, QTextEdit)

class MyLineEdit(QTextEdit):
    returnPressed = pyqtSignal()
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptRichText(False)
        self.setWordWrapMode(QTextOption.NoWrap)
        self.setUndoRedoEnabled(False)
        self.setTabChangesFocus(True)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.completer = None
        self.textChanged.connect(self.textHasChanged)
    def setCompleter(self, completer):
        if completer:
            completer.setWidget(self)
            completer.setCompletionMode(QCompleter.PopupCompletion)
            completer.setCaseSensitivity(Qt.CaseInsensitive)
            completer.setModelSorting(
                QCompleter.CaseSensitivelySortedModel)
            completer.setMaxVisibleItems(15)
            completer.activated.connect(self.insertCompletion)
            self.completer = completer
    def insertCompletion(self, completion):
        print('>>> insertCompletion')
        if self.completer and self.completer.widget() == self:
            self.completer.widget().setPlainText(completion)
            self.completer.widget().moveCursor(QTextCursor.EndOfLine)
            self.completer.widget().ensureCursorVisible()
    def focusInEvent(self, event):
        print('>>> focusInEvent')
        if self.completer:
            self.completer.setWidget(self)
        super().focusInEvent(event)
    def keyPressEvent(self, event):
        print('>>> keyPressEvent')
        if self.completer and self.completer.popup().isVisible():
            if event.key() in (Qt.Key_Return, Qt.Key_Enter,
                               Qt.Key_Tab, Qt.Key_Backtab, Qt.Key_Escape):
                event.ignore()
                return
        else:
            if event.key() in(Qt.Key_Return, Qt.Key_Enter):
                self.returnPressed.emit()
                return
        super().keyPressEvent(event)
        if not self.toPlainText():
            self.completer.popup().hide()
            return
        self.completer.setCompletionPrefix(self.toPlainText())
        self.completer.popup().setCurrentIndex(
            self.completer.completionModel().index(0, 0))
        self.completer.complete()
    def textHasChanged(self):
        # remove new lines and strip left blank characters
        self.blockSignals(True)
        cursor = self.textCursor()
        self.setPlainText(' '.join(self.toPlainText().splitlines()).lstrip())
        self.setTextCursor(cursor)
        self.ensureCursorVisible()
        self.blockSignals(False)

class MyDelegate(QItemDelegate):
    def __init__(self, parent):
        super().__init__(parent)
    def createEditor(self, parent, option, index):
        strings = ('tata', 'tada', 'tadam', 'tete', 'titi', 'toto', 'tutu')
        completer = QCompleter(strings)
        editor = MyLineEdit(parent)
        editor.setCompleter(completer)
        editor.returnPressed.connect(self.commitAndCloseEditor)
        return editor
    def commitAndCloseEditor(self):
        print('>>> commitAndCloseEditor')
        editor = self.sender()
        self.commitData.emit(editor)
        self.closeEditor.emit(editor)
    def setEditorData(self, editor, index):
        if editor:
            editor.setText(index.model().data[0])
            editor.selectAll()
    def setModelData(self, editor, model, index):
        if editor:
            model.setData(index, editor.toPlainText(), Qt.EditRole)

class Model(QAbstractTableModel):
    def __init__(self):
        super().__init__()
        self.data = ['hello']
    def rowCount(self, parent=None):
        return 1
    def columnCount(self, parent=None):
        return 1
    def data(self, index, role):
        if not index.isValid():
            return QVariant()
        if role in (Qt.DisplayRole, Qt.EditRole):
            return self.data[0]
        return QVariant()
    def setData(self, index, value, role):
        if role == Qt.EditRole:
            self.data[0] = value
            top_left = self.index(0, 0)
            bottom_right = self.index(
                self.rowCount() + 1, self.columnCount())
            self.dataChanged.emit(top_left, bottom_right,
                                  [Qt.DisplayRole])
            return True
        return False
    def flags(self, index):
        return Qt.ItemIsEditable | super().flags(index)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.model = Model()
        self.table = QTableView()
        self.table.setModel(self.model)
        delegate = MyDelegate(self.table)
        self.table.setItemDelegateForColumn(0, delegate)
    def initUI(self):
        self.show()
        self.setCentralWidget(self.table)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mw = MainWindow()
    mw.initUI()
    sys.exit(app.exec_())

相关内容

  • 没有找到相关文章

最新更新