Автозаполнение в QLineEdit с текстом на фоне
Мой проект - аналог таких проектов, как Wox, ueli и PowerToys Run, которые в свою очередь аналоги Spotlight - функциональный поисковик в Mac OS.
Я пишу свой проект исключительно на PyQt5 и на данный момент моя задача - реализовать автозаполнение введенного пользователем текста по нажатию на Tab или стрелку вправо. Да, в PyQt5 есть класс QCompleter, созданный как раз для таких целей, но давайте взглянем на то, как это реализовано, например, в PowerToys Run:
А вот, как автозаполнение будет выглядеть в Pyt5 с использованием QCompleter:
Т.е. вместо того, чтобы сделать текст как бы на фоне, как placeholder, QCompleter вставляет текст и выделяет его, оставляя курсор на месте. Примерно так выглядит мой код:
lineEdit = QLineEdit(self)
strList = ['telegram', 'PyCharm', 'Yandex', 'Minecraft']
completer = QCompleter(strList, lineEdit)
lineEdit.setCompleter(completer)
Мне же нужно сделать как в первом случае. У меня есть 2 потенциально возможных варианта решения:
- Поиграться с
PlaceholderText. Возможно есть способ не убирать его, когда пользователь вводит текст. Тогда текст после введенного пользователем текста будет "в фоне" - Возможно такого результата можно добиться с помощью
setStyleSheet(), но я не уверен, что средствами css это можно сделать
Буду рад любым советам и идеям!
Ответы (1 шт):
Не знаю, правильно ли я вас понял, но как вариант предложу попробовать:
import sys
from PyQt5.Qt import *
class Completer(QCompleter):
def __init__(self, *args, **kwargs):
super(Completer, self).__init__(*args, **kwargs)
self.setCompletionMode(QCompleter.PopupCompletion)
self._le = args[-1]
self._path = ''
self._path_2 = ''
self._all_path = ''
self.lbl = QLabel(self._le)
self.lbl.setStyleSheet("""
QLabel {
font-family:'Consolas';
color: #777;
font: 25px;
background-color: #2b2b2b;
}
""")
self.lbl.hide()
def pathFromIndex(self, index):
rect = QRect(
self._le.cursorRect().x(),
self._le.cursorRect().y(),
self._le.width(),
self._le.completer().widget().height()
)
self.lbl.move(self._le.cursorRect().x()+8, self._le.cursorRect().y())
self.lbl.setText(index.data()[len(self._path_2):])
self.lbl.adjustSize()
self.lbl.show()
self._all_path = index.data()
return self._path
def splitPath(self, path):
self._path = self._le.text()
self._path_2 = path
return [path]
class LineEdit(QLineEdit):
def __init__(self):
super().__init__()
self._all_text = ''
self.multipleCompleter = None
def keyPressEvent(self, event):
super().keyPressEvent(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(" ")
text = self.multipleCompleter._all_path
if p == -1:
pass
else:
text = self.text()[:p+1] + self.multipleCompleter._all_path
self.multipleCompleter.lbl.hide()
QTimer.singleShot(10, lambda: self.allText(text))
def allText(self, text):
self.setText(text)
self._all_text = text
self.setFocus()
self.update()
def event(self, event):
if self.multipleCompleter:
if self.multipleCompleter.popup().currentIndex().row() == -1:
self.multipleCompleter.lbl.hide()
else:
if not self.multipleCompleter.popup().selectedIndexes():
# self.multipleCompleter.popup().hide()
self.multipleCompleter.lbl.hide()
QTimer.singleShot(10, lambda: self.allText(self.multipleCompleter._path))
return super().event(event)
def setMultipleCompleter(self, completer):
self.multipleCompleter = completer
self.multipleCompleter.setWidget(self)
completer.activated.connect(self.insertCompletion)
if __name__ == '__main__':
app = QApplication(sys.argv)
editor = LineEdit()
editor.setStyleSheet("""
LineEdit {
font-family:'Consolas';
color: #fff;
font: 25px;
background-color: #2b2b2b;
}
""")
strList = [
'def', 'Python', 'PyQt5', 'Qt', 'Django', 'QML',
'matthew','mark','morris','mickey',
'the', 'function', 'get_request', 'returns', 'list',
'of', 'names', 'taken', 'from', '112233',
'telegram', 'PyCharm', 'Yandex', 'Minecraft',
'telegram-2', 'PyQt6', 'Yandex-2', 'Minecraft-2',
]
completer = Completer(strList, editor)
editor.setCompleter(completer)
completer.setCaseSensitivity(Qt.CaseInsensitive) # без учета регистра
editor.setMultipleCompleter(completer)
editor.show()
editor.resize(670, 70)
sys.exit(app.exec_())


