Как использовать PyQt5 QCompleter для завершения кода
Я хочу создать QLineEdit
поле с базовой возможностью завершения кода, но до сих пор всякий раз, когда я выбираю атрибут элемента item.attr
, item.
заменяется attr
вместо вставки attr
после item.
, Кроме того, если это attr
имеет attr.subattr
, это невозможно предсказать, потому что item.
был заменен и attr.
не существует в корне моей модели.
Я создал относительно минимальный пример:
import sys
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication,QWidget,QVBoxLayout,QLineEdit,QCompleter
test_model_data = [
('tree',[ # tree
('branch', [ # tree.branch
('leaf',[])]), # tree.branch.leaf
('roots', [])]), # tree.roots
('house',[ # house
('kitchen',[]), # house.kitchen
('bedroom',[])]), # house.bedroom
('obj3',[]), # etc..
('obj4',[])
]
class codeCompleter(QCompleter):
def splitPath(self, path):
return path.split('.') #split table.member
class mainApp(QWidget):
def __init__(self):
super().__init__()
self.entry = QLineEdit(self)
self.model = QStandardItemModel(parent=self)
self.completer = codeCompleter(self.model, self)
self.entry.setCompleter(self.completer)
layout = QVBoxLayout()
layout.addWidget(self.entry)
self.setLayout(layout)
self.update_model() #normally called from a signal when new data is available
def update_model(self):
def addItems(parent, elements):
for text, children in elements:
item = QStandardItem(text)
parent.appendRow(item)
if children:
addItems(item, children)
addItems(self.model, test_model_data)
if __name__ == "__main__":
app = QApplication(sys.argv)
hwind = mainApp()
hwind.show()
sys.exit(app.exec_())
Я придумал этот подход из Документов Qt5 и пример с Qt4.6, но ни тот, ни другой не сочетают в себе все, что я пытаюсь достичь. Нужна ли мне другая структура модели? Нужно ли подкласс больше QCompleter
? Нужен ли мне другой Qt
учебный класс?
gif примера: (извините за качество)
Эпилог:
Для тех, кто заинтересован в фактическом завершении кода, я расширил свой код после интеграции ответа @ eyllanesc, чтобы текст перед сопоставленной последовательностью идентификаторов был оставлен в покое (текст перед сопоставляемой последовательностью не препятствует сопоставлению и не удаляется при новом совпадении). вставлена). Все, что потребовалось, было немного регулярного выражения, чтобы отделить часть, которую мы хотим завершить, от предыдущего текста:
class CodeCompleter(QCompleter):
ConcatenationRole = Qt.UserRole + 1
def __init__(self, parent=None, data=[]):
super().__init__(parent)
self.create_model(data)
self.regex = re.compile('((?:[_a-zA-Z]+\w*)(?:\.[_a-zA-Z]+\w*)*\.?)$')
def splitPath(self, path): #breaks lineEdit.text() into list of strings to match to model
match = self.regex.search(path)
return match[0].split('.') if match else ['']
def pathFromIndex(self, ix): #gets model node (QStandardItem) and returns "text" for lineEdit.setText(text)
return self.regex.sub(ix.data(CodeCompleter.ConcatenationRole), self.completionPrefix())
1 ответ
pathFromIndex()
Метод возвращает строку, которая будет помещена в QLineEdit, вместо этого он возвратит конкатенацию текста элемента и текстов его предшественников. Чтобы повысить его эффективность и не рассчитывать эту онлайн-конкатенацию, в модели, содержащей эти данные, будет создана новая роль.
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QCompleter
test_model_data = [
('tree',[ # tree
('branch', [ # tree.branch
('leaf',[])]), # tree.branch.leaf
('roots', [])]), # tree.roots
('house',[ # house
('kitchen',[]), # house.kitchen
('bedroom',[])]), # house.bedroom
('obj3',[]), # etc..
('obj4',[])
]
class CodeCompleter(QCompleter):
ConcatenationRole = Qt.UserRole + 1
def __init__(self, data, parent=None):
super().__init__(parent)
self.create_model(data)
def splitPath(self, path):
return path.split('.')
def pathFromIndex(self, ix):
return ix.data(CodeCompleter.ConcatenationRole)
def create_model(self, data):
def addItems(parent, elements, t=""):
for text, children in elements:
item = QStandardItem(text)
data = t + "." + text if t else text
item.setData(data, CodeCompleter.ConcatenationRole)
parent.appendRow(item)
if children:
addItems(item, children, data)
model = QStandardItemModel(self)
addItems(model, data)
self.setModel(model)
class mainApp(QWidget):
def __init__(self):
super().__init__()
self.entry = QLineEdit(self)
self.completer = CodeCompleter(test_model_data, self)
self.entry.setCompleter(self.completer)
layout = QVBoxLayout()
layout.addWidget(self.entry)
self.setLayout(layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
hwind = mainApp()
hwind.show()
sys.exit(app.exec_())