4

I need to display some charts in my PyQt application, so I write down these code. It is works, but sometimes, draw a chart will spend a lot of time, it will "freeze" the main window.

I think do it in another thread should resolved it. But how can I do it? Or, there is another way to draw a chart in "non-block" mode?

from PyQt4 import QtGui
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas   
from matplotlib.figure import Figure

class MplCanvas(FigureCanvas):

    def __init__(self):
        self.fig = Figure()
        self.axes = self.fig.add_subplot(111)

        # do something...
        FigureCanvas.__init__(self, self.fig)
        FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)
        # do something...

    def draw(self):
        # do something...
1
  • Implementing something similar right now. Here is my thoughts. You have to use multiple classes, one would be based on PyQt's QDialog or similar for the GUI output. The other one would be worker class based on QThread. Once QThread is done plotting it would pass figure and canvas instances to the GUI object using PyQt signaling engine. I tried combining QDialog and QThread into one class but apparently you can not do it. (I am sure you can do it but it is easier to use 2 separate classes) Commented Apr 26, 2016 at 20:47

2 Answers 2

2

You should us QThreads in your Qt application (to make the frame work do all of the hard work for you)

  1. put your time consuming work in a worker class (that is derived from QObject)

  2. In you class that is caling the plotting add something like

    self.thread = QtCore.QThread(parent=self)
    
    self.worker = Worker(parent=None)
    self.worker.moveToThread(self.thread)
    self.thread.start()
    

and communicate with your worker via signals/slots. If you call it directly (as in self.worker.do_slow_stuff()), it will run on the thread you call it from, which will block the main event loop making the interface freeze.

A good explanation of how to (and not to) do threading with QThread (read both..the first one now describes the default behaviour)

Sign up to request clarification or add additional context in comments.

1 Comment

Just a question out of curiosity. Have you ever succeeded in getting a QThread application to work and be stable for long times on Windows without crashes? It drove me crazy that I eventually gave up and changed my whole program model to use multiprocessing.
1

The basics of Python threading for simple uses like this are really easy.

You'll need to

import threading

and then, instead of just calling x.draw(), create a thread and run it as follows:

draw_thread = threading.Thread(target=x.draw)
draw_thread.start()

That will probably get you 90% of the way at least. You can read the docs to detect things like still-running threads, waiting for threads, and so on. But at heart, it's not difficult and if ti's just simple interactive graphics this might even suffice.

Be aware, though, that if draw() references globals, there is the potential for race conditions to occur,making your program unreliable. This is a further advantage of writing code with good coupling, clean interfaces and no references to mutable globals (unless locking is used to protect those resources).

2 Comments

You have to use QThreads with PyQt. Plain old Thread would not work properly
Ah, news to me - thanks for the comment. Do QThreads play nice with threading threads?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.