【问题标题】:PyQt LineEdit with readline completer?PyQt LineEdit 与 readline 完成器?
【发布时间】:2012-07-09 19:00:19
【问题描述】:

我一直在开发一个命令行工具,现在我正在为它制作一个 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()

最终,如果我无法让 readline 模块在 QLineEdit 小部件中工作,我最终想做的是完成一个单词列表,并且能够让多个单词用 +- 等符号分隔*/() 等...

谢谢!

【问题讨论】:

    标签: pyqt readline qlineedit qcompleter


    【解决方案1】:

    我可以告诉你,首先,尝试将 QCompleter 包装在新功能周围是一件非常痛苦的事情。您必须能够满足 QCompleter 的所有接口,并围绕该实时代码桥接它。

    您必须手动更新 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 信号连接到完成者以强制更新。否则,完成程序中将不会使用任何功能。

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

    examples here 展示了其他人如何在自定义行编辑中填写功能,他们完全绕过完成者的标准信号并自己触发它。你可以看到它的一点点努力。

    【讨论】:

    • 我还想摆脱 readline 模块中提供的唯一功能是继续跨多个单词执行制表符补全。例如,如果我的单词列表是 aardvark aardwolf,我希望能够输入:“aardvark-aardw”并点击 tab,然后完成。有任何想法吗?抱歉,如果这是一个简单的问题,我对 PyQt 很陌生...
    • 好的,我刚刚找到了最接近的方法,无需继承 QLineEdit。我还添加了您关于检测分隔符并继续完成的部分。
    • 太好了,非常感谢您的帮助!我希望看到您当前的实现没有做的两件事。一个是它只在连字符上分开,在我的 OP 中,我提到想要在多个运算符上分开,比如 +-/^()。我对正则表达式的了解实际上为零,但我猜这是可以实现的吗?其次,这只会分裂一次。例如,如果我使用 'aardvark+aardwolvesbab' 来匹配单词列表中的 babel,我仍然需要制表符补全。想法?
    • 是的,这都是关于正则表达式的。您只需要定义如何拆分它。多少个分隔符无关紧要。只要拆分返回两个部分,它就会起作用。学习正则表达式是一项单独的任务;)希望您不要将这部分要求作为接受此答案的要求。
    • 很公平。我只是想确保这就是它的全部。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 1970-01-01
    • 1970-01-01
    • 2016-01-07
    • 1970-01-01
    • 2014-08-07
    • 1970-01-01
    相关资源
    最近更新 更多