Ответ 1
Общие правила программирования
- Если вы должны использовать многопоточный код, никогда не обращайтесь к графическому интерфейсу из потока, отличного от GUI. Всегда вместо этого отправляйте сообщение в поток GUI, передавая сигнал или какой-либо другой механизм, защищенный потоками.
- Будьте осторожны с Model/View. TableView, TreeView и т.д. Их сложно программировать правильно, и любые ошибки приводят к беспроблемному сбою. Используйте "Тест модели" , чтобы убедиться, что ваша модель внутренне непротиворечива.
- Поймите, как управление объектами Qt взаимодействует с управлением объектами Python и случаями, когда это может пойти не так. См. http://python-camelot.s3.amazonaws.com/gpl/release/pyqt/doc/advanced/development.html
- Объекты Qt без родителя "принадлежат" Python; только Python может их удалить.
- Объекты Qt с родителем "принадлежат" Qt и будут удалены Qt, если их родительский элемент удален.
- Пример: Дамп ядра с PyQt4
- QObject обычно не имеет ссылки на его родителя или любого из его предков (слабые ссылки в порядке). Это приведет к утечке памяти в лучшем случае и случайным сбоям.
-
Помните о ситуациях, когда Qt автоматически удаляет объекты. Если оболочка python не была проинформирована о том, что объект С++ был удален, доступ к нему приведет к сбою. Это может произойти разными способами из-за сложности PyQt и PySide в отслеживании объектов Qt.
- Составные виджеты, такие как QScrollArea и его полосы прокрутки, QSpinBox и QLineEdit и т.д. (у Pyside нет этой проблемы)
- Удаление QObject будет автоматически удалить все его дочерние элементы (однако PyQt обычно справляется с этим правильно).
-
Удаление элементов из QTreeWidget приведет к удалению всех связанных с ними виджетов (установленных с помощью QTreeWidget.setItemWidget).
# Example: from PyQt4 import QtGui, QtCore app = QtGui.QApplication([]) # Create a QScrollArea, get a reference to one of its scroll bars. w = QtGui.QWidget() sa = QtGui.QScrollArea(w) sb = sa.horizontalScrollBar() # Later on, we delete the top-level widget because it was removed from the # GUI and is no longer needed del w # At this point, Qt has automatically deleted all three widgets. # PyQt knows that the QScrollArea is gone and will raise an exception if # you try to access it: sa.parent() Traceback (most recent call last): File "<stdin>", line 1, in <module> RuntimeError: underlying C/C++ object has been deleted # However, PyQt does not know that the scroll bar has also been deleted. # Since any attempt to access the deleted object will probably cause a # crash, this object is 'toxic'; remove all references to it to avoid # any accidents sb.parent() # Segmentation fault (core dumped)
Конкретные обходные пути/ошибки
- Изменение границ QGraphicsItems без вызова prepareGeometryChange() сначала может привести к сбою.
- Исключение исключений внутри QGraphicsItem.paint() может привести к сбоям. Всегда перехватывайте исключения внутри paint() и выводите сообщение, а не исключаете исключение.
- QGraphicsItems никогда не должны ссылаться на QGraphicsView, в котором они живут. (weakrefs в порядке).
- Повторное использование QTimer.singleShot может вызвать блокировки.
- Избегайте использования QGraphicsView с QGLWidget.
Практика предотвращения сбоев при выходе
- QGraphicsItems, которые не являются частью QGraphicsScene, могут привести к сбою при выходе.
- QObjects, ссылающиеся на своего родителя или любого предка, могут вызвать сбой выхода.
- QGraphicsScene без родителя может вызвать сбой выхода.
- Самый простой способ избежать сбоев выхода - вызвать os._exit(), прежде чем python начнет собирать объекты Qt. Однако это может быть опасно, потому что какая-то часть программы может полагаться на правильную обработку выхода для правильной работы (например, завершение файлов журнала или правильное закрытие дескрипторов устройств). Как минимум, нужно вызвать вызовы atexit перед вызовом os._exit().