PyQt LineEdit с завершением строки чтения?

Я работал над инструментом командной строки, для которого сейчас делаю графический интерфейс PyQT. Я хотел бы взять свою текущую реализацию автозаполнения с помощью модуля readline и поместить ее в текстовое поле QLineEdit. Это возможно? У вас есть какие-нибудь рекомендации?

Вот пример того, что я делаю с модулем readline:

import readline

values = ['these','are','my','autocomplete','words']
completions = {}

def completer(text,state):
    try:
        matches = completions[text]
    except KeyError:
        matches = [value for value in values if text.upper() in value.upper()]
        completions[text] = matches
    try:
        return matches[state]
    except IndexError:
        return None

readline.set_completer(completer)
readline.parse_and_bind('tab: menu-complete')

whie 1:
    text = raw_input('> ')
    text.dostuff()

В конечном счете, если я не могу заставить модуль readline работать в виджете QLineEdit, то, что я в конечном итоге хотел бы сделать, это завершить список слов с возможностью разделения нескольких слов символами, такими как +-*/( ) и т.д...

Спасибо!


person Bradley Powers    schedule 09.07.2012    source источник


Ответы (1)


Я могу сказать вам, что, во-первых, очень сложно попытаться обернуть QCompleter вокруг новой функциональности. Вы должны быть в состоянии удовлетворить весь интерфейс QCompleter и соединить его с этим реальным кодом.

Вы должны вручную обновить набор QStringListModel в QCompleter и обеспечить реализацию получения текущего завершения и общего количества завершений для данного префикса поиска.

Вот рабочий пример, совместимый с режимом PopupCompletion:

import re

class ReadlineCompleter(QtGui.QCompleter):

    def __init__(self, completeFn, *args, **kwargs):
        super(ReadlineCompleter, self).__init__(*args, **kwargs)
        self._completer = completeFn
        self.setModel(QtGui.QStringListModel())
        self.update()

    def setCompletionPrefix(self, val):
        super(ReadlineCompleter, self).setCompletionPrefix(val)
        self.update()

    def currentCompletion(self):
        state = self.currentRow()
        return self._completionAt(state)

    def completionCount(self):
        state = 0
        while True:
            result = self._completionAt(state)
            if not result:
                break
            state += 1
        return state

    def update(self):
        matches = [self._completionAt(i) for i in xrange(self.completionCount())]
        self.model().setStringList(matches)

    def _completionAt(self, state):
        text = str(self.completionPrefix())

        # regex to split on any whitespace, or the char set +*/^()-
        match = re.match(r'^(.*)([\s+*/^()-]+)(.*)$', text)
        if match:
            prefix, sep, text = match.groups()

        result = self._completer(str(text), state)

        if result and match:
            result = sep.join([prefix, result])

        return '' if result is None else result     

Обратите внимание, что в методе _completionAt() я добавил дополнительные функции, которые вы хотели, для обнаружения шаблона разделителя. Вы можете настроить это, очевидно. Но он отделит последнюю часть и будет использовать это значение для проверки завершения, а затем снова объединит результат с префиксом.

Использование

Важный. Вам нужно подключить сигнал textChanged от QLineEdit к компоновщику, чтобы принудительно обновить. В противном случае никакая функциональность в компоновщике использоваться не будет.

line = QtGui.QLineEdit()
comp = ReadlineCompleter(completer)
comp.setCompletionMode(comp.PopupCompletion)
line.setCompleter(comp)
# important
line.textChanged.connect(comp.setCompletionPrefix)

Здесь есть примеры показывая, как другим людям приходилось заполнять функциональные возможности в пользовательском редактировании строки, где они полностью обходят стандартную сигнализацию средства завершения и запускают его сами. Вы можете видеть его немного усилий.

person jdi    schedule 09.07.2012
comment
Единственная функциональность, которую я также хотел бы получить из этого, которая предлагается в модуле readline, — это продолжение выполнения табуляции для нескольких слов. Например, если мой список слов — трубкозуб, аардвулф, я хочу иметь возможность ввести: аардварк-аардв и нажать клавишу Tab, а затем завершить его. Любые идеи? Извините, если это простая проблема, я очень новичок в PyQt... - person Bradley Powers; 10.07.2012
comment
Хорошо, я только что понял, что ближе всего я могу сделать эту работу без необходимости создания подкласса QLineEdit. Я также добавил вашу часть об обнаружении разделителя и продолжении завершения. - person jdi; 10.07.2012
comment
Отлично, большое спасибо за вашу помощь! Есть две вещи, которые ваша текущая реализация не делает, и я хотел бы видеть. Во-первых, он разделяет только дефисы, и в моем OP я упомянул о желании разделить несколько операторов, таких как +-/^(). Мои знания о регулярных выражениях фактически равны нулю, но я предполагаю, что это достижимо? Во-вторых, это будет разделяться только один раз. Например, мне по-прежнему нужно завершение с помощью табуляции, если я делаю «трубкозуб + трубкозубbab», чтобы соответствовать babel в моем списке слов. Мысли? - person Bradley Powers; 10.07.2012
comment
Да, все дело в регулярном выражении. Вам просто нужно определить, как разделить его. Неважно, сколько разделителей. Пока раскол возвращает две части, он будет работать. Изучение регулярных выражений - отдельная задача;) надеюсь, вы не делаете это частью требования принять этот ответ. - person jdi; 10.07.2012
comment
Справедливо. Я просто хотел убедиться, что это все. Спасибо за вашу помощь! - person Bradley Powers; 10.07.2012
comment
Я только что обновил регулярное выражение, включив в него шаблон, указанный вами в комментариях выше. \s означает пробельные символы, за которыми следуют другие явные символы, которые вы упомянули. Вы просто добавляете их в этот раздел скобок. - person jdi; 10.07.2012
comment
Спасибо! Я на самом деле изучил регулярные выражения и понял это! Они отличный инструмент. Раньше я не особо использовал их, так как я робототехник и очень мало занимаюсь программированием общего назначения, как сейчас, но это хороший инструмент для набора инструментов. - person Bradley Powers; 11.07.2012