3.9. Internal Messenging and Signal Dispatching

Supplied by: Horst Herb

The gnumed client depends on two different types of messages:

  1. Messages coming form the backend. Example: a receptionist queues patients as they arrive into a waiting room widget. On the doctors screen there should be a small widget informing him about the number of patients waiting for him. This is achieved through asynchronous messages from the backend.

  2. Client-internal messages. They allow widgets to communicate. Example: One widget allows the doctor to select the active patient. This widget, after selection, has to notify other widgets depending on this information (like widgets displaying the patients past medical history, his allergies etc.) to update themselves.

Both types of messages are handled via a global dispatcher module called gmDispatcher.py

Procedure changing "global" data that may affect any other widget, must post a message through gmDispatcher.

Widgets depending on backend data must register their interest through gmDispatcher.

A table listing all available message labels ("signals") and their meanings can be found here. However, these message strings should never be hardcoded. Developers must instead use the embedding variables as listed in the module gmSignals.py .

Developers writing code that creates new signals must update this webpage via CVS.

Examples:

  1. A widget allows to select the current patient.

    1. It first registers it's interest in all patients added, modified or deleted with the backend as it should always be able to display the most current status of the backend data. For that purpose, it defines a callback function "self.OnDemographicsUpdated()".

    2. Then, it registers this callback function with the dispatcher for all signals that would modify the patient database.

      If anybody within a gnumed system modifies demographic information, this widget would be automatically notified about this.

    3. Once the user has interactively selected a patient, it has to alert all other widgets that this has happened. For that purpose, the event handler reacting to a patient being selected notifies the gmDispatcher about this.

           def __init__(self):
      
               #register our interest in the patients stored on the backend
      
               gmDispatcher.connect(self.OnDemographicsUpdated, gmSignals.demographics_updated())
      
              	     	
              	     
          def OnDemographicsUpdated(self, id):
      	"when the patients have changed on the backed, update the ones we display"
      
              #id is irrelevant here; we just update the whole displayed list
      
              self.UpdatePatientList()
              	        
              	     
          def UpdatePatientList(self):
      	"Update the displayed list of patients from the backend"
      
            #request a backend connection
      
            db = gmPG.ConnectionPool().GetConnection('demographica')
      
            cursor = db.cursor()
      
            #query patients to be displayed
      
            cursor.execute(....)
      
            result = cursor.fetchall()
      
            #display the result
          	    	    	
           def OnPatientSelected(self, id):
      	 """When a patient has been selected by the user, call this function     
      	 id is the primary key identifying the selected patient"""     
      
          	 gmDispatcher.send(gmSignals.patient_selected(), id=id)
          	    	    	

  2. Another widget displays the current (active) patient's name. 

    • Thus, it has to register it's interest in the event the current patient changes. The registered callback could query the database directly. However, data that is likely to be shared among many widgets, should be cached to avoid unneccessary backend traffic and to improve client performance. Thus, it requests the data from the gmCachedPerson.CachedPerson object:
            def __init__(self):
              #code to display and place the widget
              # now register our callback function with the dispatcher
              gmDispatcher.connect(self.Update, gmSignals.patient_selected())
            
            def Update(self, id_patient):
              "show the currently selected patient"
              patient = gmCachedPerson.CachedPerson.dictresult()
              self.TxtctrlSurname.SetValue(patient['surname']
              ....