使用QCompleter进行全局输入?

时间:2013-04-23 00:00:34

标签: python regex pyqt glob qcompleter

我在QCompleter中实现了标准PyQt QLineEdit,其内容是:

self.cam_completer = QtGui.QCompleter( self.cameras, self )
self.cam_completer.setCaseSensitivity( 0 )
self.cam_completer.setCompletionMode( 2 )
self.CamerasSearch.setCompleter( self.cam_completer )

其中self.cameraslist字符串,例如:

['cam0001:left', 'cam0001:right', 'cam0002:left', 'cam0002:right', etc...]

QLineEdit内,输入cam将返回所有项目,cam0001将仅返回前2位等。但是,当我输入cam*时,不会返回任何内容

我希望能够在搜索时为模式添加动画,包括*?。例如,搜索cam000?:left会从结果中消除cam0010:left

1 个答案:

答案 0 :(得分:3)

看起来你将不得不实施自己的完成者。以下是使用正则表达式过滤完成的示例:

#!/usr/bin/env python
#-*- coding:utf-8 -*-

#---------
# IMPORT
#---------
import sys, random

import sip
sip.setapi('QString', 2)
sip.setapi('QVariant', 2)

from PyQt4 import QtGui, QtCore

#---------
# DEFINE
#---------
class QDialogTest(QtGui.QDialog):
    def __init__(self, parent=None):
        super(QDialogTest, self).__init__(parent)

        self.maxVisibleItems = 7

        self.lineEdit = QtGui.QLineEdit(self)
        self.lineEdit.textChanged.connect(self.on_lineEdit_textChanged)

        self.standardItemModel = QtGui.QStandardItemModel(self)

        with open("/usr/share/dict/words", "r") as fileInput:
            for line in  random.sample(fileInput.readlines(), 111):
                self.standardItemModel.appendRow(
                    QtGui.QStandardItem(line.strip())
                )

        self.sortFilterProxyModel = QtGui.QSortFilterProxyModel(self)
        self.sortFilterProxyModel.setSourceModel(self.standardItemModel)
        self.sortFilterProxyModel.setFilterKeyColumn(0)

        self.tableView = QtGui.QTableView(self)
        self.tableView.horizontalHeader().setStretchLastSection(True)
        self.tableView.setModel(self.sortFilterProxyModel)

        self.pushButtonClose = QtGui.QPushButton(self)
        self.pushButtonClose.setText("Close")
        self.pushButtonClose.clicked.connect(sys.exit)

        self.layoutVertical = QtGui.QVBoxLayout(self)
        self.layoutVertical.addWidget(self.tableView)
        self.layoutVertical.addWidget(self.lineEdit)
        self.layoutVertical.addWidget(self.pushButtonClose)

        self.tableViewPopup = QtGui.QTableView(self)
        self.tableViewPopup.setModel(self.sortFilterProxyModel)
        self.tableViewPopup.setWindowFlags(QtCore.Qt.Popup)
        self.tableViewPopup.setFocusPolicy(QtCore.Qt.NoFocus)
        self.tableViewPopup.setFocusProxy(self.lineEdit)
        self.tableViewPopup.setMouseTracking(True)
        self.tableViewPopup.setEditTriggers(QtGui.QTableView.NoEditTriggers)
        self.tableViewPopup.setSelectionBehavior(QtGui.QTableView.SelectRows)
        self.tableViewPopup.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Plain)
        self.tableViewPopup.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.tableViewPopup.horizontalHeader().setStretchLastSection(True)
        self.tableViewPopup.horizontalHeader().hide()
        self.tableViewPopup.verticalHeader().hide()
        self.tableViewPopup.verticalHeader().setDefaultSectionSize(20)
        self.tableViewPopup.doubleClicked.connect(self.setCurrentCompletion)
        self.tableViewPopup.installEventFilter(self)

    def setCurrentCompletion(self):
        self.closePopup()

        indexes = self.tableViewPopup.selectionModel().selectedIndexes()

        self.lineEdit.blockSignals(True)
        self.lineEdit.setText(indexes[0].data(QtCore.Qt.DisplayRole))
        self.lineEdit.blockSignals(False)

    def closePopup(self):
        self.tableViewPopup.hide()
        self.lineEdit.setFocus()

    def eventFilter(self, obj, event):
        if obj != self.tableViewPopup:
            return False

        elif event.type() == QtCore.QEvent.MouseButtonPress:
            self.closePopup()

        elif event.type() == QtCore.QEvent.KeyPress:
            if event.key() in [
                QtCore.Qt.Key_Enter,
                QtCore.Qt.Key_Return
            ]:
                self.setCurrentCompletion()

            elif event.key() in [
                QtCore.Qt.Key_Escape
            ]:
                self.closePopup()

            elif not event.key() in [
                QtCore.Qt.Key_Up,
                QtCore.Qt.Key_Down,
                QtCore.Qt.Key_Home,
                QtCore.Qt.Key_End,
                QtCore.Qt.Key_PageUp,
                QtCore.Qt.Key_PageDown
            ]:
                self.lineEdit.event(event)

        return super(QDialogTest, self).eventFilter(obj, event)

    @QtCore.pyqtSlot(str)
    def on_lineEdit_textChanged(self, text):
        self.tableViewPopup.hide()

        if text != "":
            self.setCompletionPrefix(text)

    def setCompletionPrefix(self, prefix):
        self.sortFilterProxyModel.setFilterRegExp(QtCore.QRegExp(prefix))

        if self.sortFilterProxyModel.rowCount():
            self.complete()

    def complete(self):
        self.tableViewPopup.move(
            self.lineEdit.mapToGlobal(
                QtCore.QPoint(0, self.lineEdit.height())
            )
        )
        self.tableViewPopup.resize(
            self.lineEdit.width(), 
            self.tableViewPopup.verticalHeader().defaultSectionSize() * min(
                self.maxVisibleItems,
                self.sortFilterProxyModel.rowCount()
            ) + 2
        )
        self.tableViewPopup.setFocus()
        self.tableViewPopup.show()       

#---------
# MAIN
#---------
if __name__ == "__main__":    
    app = QtGui.QApplication(sys.argv)
    app.setApplicationName('QDialogTest')

    main = QDialogTest()
    main.resize(333, 333)
    main.exec_()

    sys.exit(app.exec_())