PyQt带有readline自动完成的LineEdit?

3
我一直在开发一个命令行工具,现在我想制作一个基于PyQT的GUI界面。我想把我目前使用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()

如果我无法在QLineEdit小部件中使用readline模块,我最终希望完成的是一个单词列表,具有多个单词,可以用符号如+-*/()等分隔。

谢谢!

1个回答

4
我可以告诉你,首先尝试将新功能与QCompleter结合起来是非常麻烦的。您必须能够满足所有QCompleter的接口,并将其桥接到realine代码周围。
您必须手动更新在QCompleter上设置的QStringListModel,并提供获取当前完成和给定搜索前缀的完成总数的实现。
这里有一个与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()方法中,我添加了您想要的额外功能,用于检测分隔符模式。您可以自行调整。但它将分离最后一部分并使用该值来检查完成情况,然后再次将结果与前缀重新连接。

用法

重要提示。您需要将QLineEdit的textChanged信号连接到自动完成器(completer)以强制更新。否则,自动完成器(completer)中不会使用任何功能。

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

这里有一些例子,展示了其他人如何在自定义行编辑器中填入功能,完全绕过自动完成的标准信号并自己触发它。你可以看到这需要一点努力。


我想从这个模块中获得的唯一功能是readline模块提供的跨多个单词继续执行制表符完成。例如,如果我的单词列表是aardvark aardwolf我希望能够输入:“aardvark-aardw”,然后按Tab键,然后完成它。有什么想法吗?如果这是一个简单的问题,我很抱歉,因为我对PyQt非常陌生... - Bradley Powers
是的,它完全涉及到正则表达式。您只需要定义如何分割它。无论有多少个分隔符都没关系。只要分割返回两个部分就可以了。学习正则表达式是一个单独的任务;)希望您不会将其作为接受此答案的要求。 - jdi
好的,我只是想确保这就是全部。谢谢你的帮助! - Bradley Powers
我刚刚更新了正则表达式,以包括您在上面的评论中指定的模式。\s表示“空格字符”,然后是您提到的其他明确字符。您只需将它们添加到该括号部分即可。 - jdi
谢谢!我实际上研究了正则表达式并解决了问题!它们是一种很好的工具。以前我很少使用它们,因为我是一个机器人学家,很少进行像现在这样的通用编程,但这是工具箱中的好工具。 - Bradley Powers
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接