我已经使用 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_())