1

PySide (Python 2.7.3、PySide 1.1.2、Qt 4.8.1) を使用して、Qt ドキュメントの「カスタム コンプリータの例」を再現しました。

終了時に win32 例外がスローされる (または Mac OS X ではアクセス違反例外) という問題があります。Mac ではスタック トレースを確認でき、ガベージ コレクション中に問題が発生します。QObjects への参照が明らかに一貫していないため、問題が発生します。

次の自己完結型スクリプトでこのクラッシュを確認できますが、完全な挿入が受け入れられた場合のみです。つまり、最初の数文字を入力してから、補完を受け入れます。

一方、完了リストのポップアップが表示されたが、完了を受け入れなかった場合、終了時にクラッシュは発生しません。

################################################################################
# Completer.py
#
# A PySide port of the Qt 4.8 "Custom Completer Example"
# http://qt-project.org/doc/qt-4.8/tools-customcompleter.html
#
################################################################################

from PySide.QtCore import *
from PySide.QtGui import *

class TextEdit(QPlainTextEdit):

    def __init__(self, parent=None):
        super(TextEdit, self).__init__(parent)
        self.c = None

    def completer(self):
        return self.c

    def setCompleter(self, completer):
        if self.c:
            QObject.disconnect(self.c, 0, self, 0)

        self.c = completer

        if not self.c:
            return

        self.c.setWidget(self)
        self.c.setCompletionMode(QCompleter.PopupCompletion)
        self.c.setCaseSensitivity(Qt.CaseInsensitive)
        self.c.activated.connect(self.insertCompletion)

    def insertCompletion(self, completion):
        if self.c.widget() is not self:
            return
        tc = self.textCursor()
        extra = len(completion) - len(self.c.completionPrefix())
        tc.movePosition(QTextCursor.Left)
        tc.movePosition(QTextCursor.EndOfWord)
        tc.insertText(completion[-extra:])
        self.setTextCursor(tc)

    def textUnderCursor(self):
        tc = self.textCursor()
        tc.select(QTextCursor.WordUnderCursor)
        return tc.selectedText()

    def focusInEvent(self, event):
        if self.c:
            self.c.setWidget(self)
        super(TextEdit, self).focusInEvent(event)

    def keyPressEvent(self, e):
        if self.c and self.c.popup().isVisible():
            if e.key() in (Qt.Key_Enter, 
                           Qt.Key_Return,
                           Qt.Key_Escape,
                           Qt.Key_Tab,
                           Qt.Key_Backtab):
                e.ignore()
                return

        # Check for the shortcut combination Ctrl+E
        isShortcut = (e.modifiers() & Qt.ControlModifier) and e.key() == Qt.Key_E
        # Do not process the shortcut when we have a completion
        if not self.c or not isShortcut:
            super(TextEdit, self).keyPressEvent(e)

        noText = not e.text()
        ctrlOrShift = e.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)
        if not self.c or (ctrlOrShift and noText):
            return

        eow = "~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-=" # End of word
        hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift
        completionPrefix = self.textUnderCursor()

        if not isShortcut and \
           (hasModifier or noText or len(completionPrefix) < 1 or e.text()[-1:] in eow):
            self.c.popup().hide()
            return

        if completionPrefix != self.c.completionPrefix():
            self.c.setCompletionPrefix(completionPrefix)
            self.c.popup().setCurrentIndex( self.c.completionModel().index(0,0) )

        cr = self.cursorRect()
        cr.setWidth(self.c.popup().sizeHintForColumn(0) + \
                    self.c.popup().verticalScrollBar().sizeHint().width())
        self.c.complete(cr)


class Completer(QMainWindow):

    words = ("one",
             "two",
             "three",
             "four")

    def __init__(self, parent=None):
        super(Completer, self).__init__(parent)


        self.setWindowTitle("Completer")
        self.textEdit = TextEdit()
        self.completer = QCompleter(self)
        self.completer.setModelSorting(QCompleter.CaseInsensitivelySortedModel)
        self.completer.setCaseSensitivity(Qt.CaseInsensitive)
        self.completer.setWrapAround(False)
        self.completer.setModel(QStringListModel(Completer.words, self.completer))
        self.textEdit.setCompleter(self.completer)

        self.setCentralWidget(self.textEdit)
        self.resize(500, 300)
        self.setWindowTitle("Completer")


if __name__ == '__main__':
    import sys
    from PySide.QtGui import QApplication

    app = QApplication(sys.argv)
    window = Completer()
    window.show()    
    sys.exit(app.exec_())
4

0 に答える 0