Search code examples
pythonqtpyqtwxpythonpyside

Equivalent to wxPython's Freeze and Thaw in PyQt / PySide


When I do multiple updates on a widget in wxPython (like loading content of tables, trees, un-hiding widgets etc.) I often use Freeze to disable the widget re-drawing and when I am done, I call Thaw so the new content appears all at once. Is there a similar way in Qt?

Related question: Python/Tkinter: Turn on/off screen updates like wxPython Freeze/Thaw?


Solution

  • In Qt it shouldn't be necessary to do it, since the update events are compressed and won't be delivered until the control returns to the event loop. For example, the following will only result in one repaint of the label:

    void test(QLabel * label) {
      label->setText("foo");
      // update is called internally by setText, but the extra call is harmless here
      label->update(); 
      label->setText("bar");
      label->setText("baz");
    }
    

    If you are certain that your updates are interspersed with returns to the event loop, then you can implement the freeze/thaw as follows by filtering the update events. The below is in C++, feel free to translate it to Python :)

    class UpdateFilter : public QObject {
      Q_OBJECT
      QSet<QObject> m_deferredUpdates;
      Q_SLOT void isDestroyed(QObject * obj) {
        m_deferredUpdates.remove(obj);
      }
      Q_OBJECT bool eventFilter(QObject * obj, QEvent * ev) {
        if (ev->type() == QEvent::UpdateRequest) {
          if (! m_deferredUpdates.contains(obj) {
            m_deferredUpdates.insert(obj);
            connect(obj, SIGNAL(destroyed(QObject*)), SLOT(isDestroyed(QObject*)));
          }
          return true;
        }
        return false;
      }
    public:
      void thaw(QWidget * w) {
        if (m_deferredUpdates.contains(w)) {
          w->update();
          m_deferredUpdates.remove(w);
        }
    };
    
    // This instance is only created on the first call to freeze.
    Q_GLOBAL_STATIC(UpdateFilter, updateFilter)
    
    void freeze(QWidget * w) { w->installEventFilter(&updateFilter()); }
    void thaw(QWidget * w) { updateFilter().thaw(w); }