Как построить собственное автоматическое завершение с частичным совпадением (как в PyCharm) для QPlainTextEdit? - PullRequest
0 голосов
/ 05 октября 2019

У меня есть такие данные автозаполнения: ['taste.sour', 'taste.salty', 'taste.sweet', 'taste.bitter']

Я хочу написать специальное автозаполнение, которое позволяет такие совпадения (как в PyCharm):

  1. ts (совпадение со словами начинается)-> должен показать 'taste.sour', 'taste.salty', 'taste.sweet'
  2. tb -> должен показать 'taste.bitter'
  3. tsa (совпадение со словами начинается, затем следующая буква) -> должен показать 'taste.salty'
  4. вкус.s (базовое соответствие) -> должен показать 'taste.sour', 'taste.salty', 'taste.sweet'
  5. вкус.са -> должен показать 'taste.salty'
  6. та (соответствует первому слову) -> шоудл шоу 'taste.', 'taste.sour', 'taste.salty', 'taste.sweet', 'taste.bitter'

Я написал код песочницы, который охватывает 4, 5, 6, но как это сделать 1. ts, 2. tb, 3. tsa - можете ли вы помочь мне с этим?

Я прочитал: https://doc.qt.io/qt-5/qabstractitemmodel.html но я понятия не имею, должен ли я использовать для этого разные QAbstractItemModel.

Я хочу также обновлять эту модель при добавлении каждого нового тега.

Это моя работакод с PyQt5:

import sys

from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import QStringListModel, Qt
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPlainTextEdit, QCompleter


class Application(QtWidgets.QApplication):
    pass


class SmartCompleter(QCompleter):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        model = QStringListModel()
        model.setStringList(['taste.sour', 'taste.salty', 'taste.sweet', 'taste.bitter'])
        self.setModel(model)


class SmartTextEdit(QPlainTextEdit):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.completer = SmartCompleter()
        self.completer.setWidget(self)
        self.completer.setCompletionMode(QCompleter.PopupCompletion)
        self.completer.setCaseSensitivity(Qt.CaseSensitive)
        self.completer.activated.connect(self.insert_completion)

    def insert_completion(self, completion):
        if completion == self.completer.completionPrefix():
            return
        text_cursor = self.textCursor()
        last_chars = len(completion) - len(self.completer.completionPrefix())
        text_cursor.insertText(completion[-last_chars:])
        self.setTextCursor(text_cursor)

    def text_before_cursor(self):
        text_cursor = self.textCursor()
        text_cursor.select(QtGui.QTextCursor.WordUnderCursor)
        return text_cursor.selectedText()

    def keyPressEvent(self, e: QtGui.QKeyEvent) -> None:
        if self.completer.popup().isVisible():
            key = e.key()
            if key in (Qt.Key_Enter, Qt.Key_Return):
                e.ignore()
                return

        super().keyPressEvent(e)

        text_before_cursor = self.text_before_cursor()
        print('text', self.text_before_cursor())
        if text_before_cursor != self.completer.currentCompletion():
            if text_before_cursor != self.completer.completionPrefix():
                print(text_before_cursor, self.completer.currentCompletion())
                self.completer.setCompletionPrefix(text_before_cursor)
                self.completer.popup().setCurrentIndex(self.completer.completionModel().index(0, 0))

                cursor_rectangle = self.cursorRect()
                popup = self.completer.popup()
                cursor_rectangle.setWidth(popup.sizeHintForColumn(0) + popup.verticalScrollBar().sizeHint().width())
                self.completer.complete(cursor_rectangle)
        else:
            self.completer.popup().hide()


class SmartEditWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        main_vertical_layout = QVBoxLayout()
        self.setLayout(main_vertical_layout)

        main_horizontal_layout = QHBoxLayout()
        main_vertical_layout.addLayout(main_horizontal_layout)

        text_edit = SmartTextEdit()
        main_horizontal_layout.addWidget(text_edit)


def main():
    app = Application(sys.argv)
    app.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)

    default_font = QFont()
    default_font.setPointSize(12)
    app.setFont(default_font)

    smart_edit_widget = SmartEditWidget()
    smart_edit_widget.showNormal()

    sys.exit(app.exec())


if __name__ == '__main__':
    main()
...