kazak
kazak

Reputation: 131

PyQt5 sending signals between classes?

I have two couple classes(A, B, C, D), one of them is GUI class(A) which contains progressbar. So is it possible to send progress signals from B, C, D classes to A class ?

in pseudo-code it's something like:

from a import A
from PyQt5.Core import pyqtSignal

 class B(QObject):
     ...
     self.gui = A()
     progress = pyqtSignal(int)

     def connect_and_send(self, value):
         self.progress.connect(self.gui.progressBar)
         self.progress.emit(value)

But maybe there's something better, that my messy approach ?

Upvotes: 2

Views: 4347

Answers (1)

Marcus
Marcus

Reputation: 1713

As far as I see you have got the basic idea right. :) Few things could be improved upon.

Firstly, calling connect_and_send(...) would cause the signal-slot-connection to be created each time you call the function. So it'll be better to create the connection elsewhere.

Secondly, you have used the new style signal-slots, good for you, but the connection is erroneous. You have the line self.progress.connect(self.gui.progressBar). This will cause the progressbar object itself to be called like this self.gui.progressBar() and trigger a TypeError:

Traceback (most recent call last):
  File "...", line ..., in ...
TypeError: 'QProgressBar' object is not callable

Change self.progress.connect( self.gui.progressBar ) to self.progress.connect( self.gui.progressBar.setValue ). This call will result in self.gui.progressBar.setValue( <some_integer_value> ) which is what you want.

So your final code could be changed to something like::

from a import A
from PyQt5.Core import pyqtSignal

class B( QObject ) :
    ...
    progress = pyqtSignal(int)
    ...

    def prepareGui( self ) :
        self.gui = A()
        self.gui.progressBar.setRange( 0, 100 )
        self.progress.connect( self.gui.progressBar.setValue )

        # You'll want to show the GUI
        self.gui.show()       

    def some_function( self ) :
        ...
        ...
        ...

        self.progress.emit( <some_number> )

Take care to call the prepareGui() function before calling some_function(), otherwise, the connection will not have been made, and progress bar will not get updated.

[b]Edit:[/b] The more I think about this question, the more I feel that the classes should be reversed, in ideal case, unless you are calling the GUI from the command line, which is quite unlikely.

Since, B, C and D are non-gui, you may want to instantiate them in A like this:

class B(QObject):
    progress = pyqtSignal( int )

    # Other class constructs/functions/members
    ...
    ...

class A( QMainWindow ) :
    """Qt Application Details
    """

    def __init__( self ) :
        """Class initialiser
        """

        ...

        self.createGUI()
        self.setupBCD()

    def createGUI( self ) :

        # Create you progress bars and other gui
        ...
        ...

        self.progressBar = QProgressBar( self )
        self.progressBar.setRange( ... )

    def setupBCD( self ) :

        # Setup classes B, C and D
        self.classB = B()
        self.classB.progress.connect( self.progressBar.setValue )

        # Similar connection for others
        ...
        ...

This way the GUI is shown first. Then the non-gui elements start their work, and interact with the GUI to display the progress in the progressBar

Upvotes: 3

Related Questions