在 PyQt 中避免崩溃/挂起的良好做法是什么? [英] What are good practices for avoiding crashes / hangs in PyQt?

查看:60
本文介绍了在 PyQt 中避免崩溃/挂起的良好做法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢 python 和 Qt,但对我来说很明显 Qt 的设计并没有考虑到 python.有多种方法可以使 PyQt/PySide 应用程序崩溃,其中许多方法即使使用适当的工具也很难调试.

I love both python and Qt, but it's pretty obvious to me that Qt was not designed with python in mind. There are numerous ways to crash a PyQt / PySide application, many of which are extraordinarily difficult to debug, even with the proper tools.

我想知道:在使用 PyQt 和 PySide 时,有哪些好的做法可以避免崩溃和锁定?这些可以是任何内容,从一般的编程技巧和支持模块到高度具体的解决方法和要避免的错误.

I would like to know: what are good practices for avoiding crashes and lockups when using PyQt and PySide? These can be anything from general programming tips and support modules down to highly specific workarounds and bugs to avoid.

推荐答案

一般编程实践

  • 如果您必须使用多线程代码,永远不要从非 GUI 线程访问 GUI.始终通过发出信号或其他一些线程安全机制向 GUI 线程发送消息.
  • 小心建模/查看任何东西.TableView、TreeView 等,它们很难正确编程,任何错误都会导致无法追踪的崩溃.使用模型测试来帮助确保您的模型在内部是一致的.
  • 了解 Qt 对象管理与 Python 对象管理交互的方式以及可能出错的情况.请参阅 http://python-camelot.s3.amazonaws.com/gpl/release/pyqt/doc/advanced/development.html
    • 没有父对象的 Qt 对象由 Python拥有";只有 Python 可以删除它们.
    • 具有父级的 Qt 对象归 Qt所有",如果删除其父级,Qt 将删除它们.
    • 示例:使用 PyQt4 进行核心转储
    • General Programming Practices

      • If you must use multi-threaded code, never-ever access the GUI from a non-GUI thread. Always instead send a message to the GUI thread by emitting a signal or some other thread-safe mechanism.
      • Be careful with Model/View anything. TableView, TreeView, etc. They are difficult to program correctly, and any mistakes lead to untraceable crashing. Use Model Test to help ensure your model is internally consistent.
      • Understand the way Qt object management interacts with Python object management and the cases where this can go wrong. See http://python-camelot.s3.amazonaws.com/gpl/release/pyqt/doc/advanced/development.html
        • Qt objects with no parent are "owned" by Python; only Python may delete them.
        • Qt objects with a parent are "owned" by Qt and will be deleted by Qt if their parent is deleted.
        • Example: Core dump with PyQt4
        • 注意 Qt 自动删除对象的情况.如果 python 包装器没有被告知 C++ 对象被删除,那么访问它会导致崩溃.由于 PyQt 和 PySide 在跟踪 Qt 对象方面存在困难,这可能以多种不同的方式发生.

          Be aware of situations where Qt auto-deletes objects. If the python wrapper has not been informed that the C++ object was deleted, then accessing it will cause a crash. This can happen in many different ways due to the difficulty PyQt and PySide have in tracking Qt objects.

          • 复合小部件,例如 QScrollArea 及其滚动条、QSpinBox 及其 QLineEdit 等(Pyside 没有此问题)
          • 删除 QObject 将自动删除其所有子项(但是 PyQt 通常会正确处理).
          • 从 QTreeWidget 中删除项目将导致任何关联的小部件(使用 QTreeWidget.setItemWidget 设置)被删除.

          • Compound widgets such as a QScrollArea and its scroll bars, QSpinBox and its QLineEdit, etc. (Pyside does not have this problem)
          • Deleting a QObject will automatically delete all of its children (however PyQt usually handles this correctly).
          • Removing items from QTreeWidget will cause any associated widgets (set with QTreeWidget.setItemWidget) to be deleted.

          # 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)
          

          • 在未先调用 prepareGeometryChange() 的情况下更改 QGraphicsItems 的边界可能会导致崩溃.
          • 在 QGraphicsItem.paint() 中引发异常会导致崩溃.始终在paint() 中捕获异常并显示一条消息,而不是让异常继续进行而不被捕获.
          • QGraphicsItems 永远不应该保留对它们所在的 QGraphicsView 的引用.(弱引用是可以的).
          • 重复使用 QTimer.singleShot 会导致锁定.
          • 避免将 QGraphicsView 与 QGLWidget 一起使用.
          • 不属于 QGraphicsScene 的 QGraphicsItem 可能导致退出时崩溃.
          • 引用其父级或任何祖先的 QObject 可能导致退出崩溃.
          • 没有父级的 QGraphicsScene 会导致退出崩溃.
          • 避免退出崩溃的最简单方法是在 python 开始收集 Qt 对象之前调用 os._exit().但是,这可能很危险,因为程序的某些部分可能依赖于正确的退出处理才能正常运行(例如,终止日志文件或正确关闭设备句柄).至少,应该在调用 os._exit() 之前手动调用 atexit 回调.

          这篇关于在 PyQt 中避免崩溃/挂起的良好做法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆