Search code examples
pythonmultithreadingwxpython

Python - wxPython Sequence of Command Execution


I have a properly working code, I understand I am not pasting enough code - but I will explain each command with proper comments. My question here is why is the code behaving rather than what I expected it to behave.

My code:

  def OnReset(self, event): # A function event which works after a button is pressed

        self.reset_pump.Disable() # Disables the button so it is clicked
        self.WriteToController([0x30],'GuiMsgIn') # Sends the reset command
        self.flag_read.set() # Set Event of the thread
        time.sleep(0.25)
        self.tr.join() # Joining a Thread

        self.MessageBox('Pump RESET going on Click OK \n')
        # Having the above step is useful
        # The question I have is based on the commands from here:    
        self.offset_text_control.Clear()
        self.gain_text_control.Clear()
        self.firmware_version_text_control.Clear()
        self.pump_rpm_text_control.Clear()
        self.pressure_text_control.Clear()
        self.last_error_text_control.Clear()
        self.error_count_text_control.Clear()
        self.pump_model_text_control.Clear()
        self.pump_serial_number_text_control.Clear()
        self.on_time_text_control.Clear()
        self.job_on_time_text_control.Clear()
        # The above commands clear various widgets on my GUI. 

        self.ser.close() # Closes my serial connection to MCU
        time.sleep(5)

        self.OnCorrectComPort(event) # An external function which gets executed. This function has a Message BOX - which says - PORT IS OPENED.

        return

I expect, once the thread is joined - my commands will clear the GUI. Then close the serial connection using (ser.close()). Then the self.OnCorrectComPort(event) gets executed.

This is what I am seeing: Thread joins with tr.join() then self.OnCorrecComPort(event) gets executed as I can see the Message box with "PORT OPENED" appears, I click OK, then my GUI gets CLEARED. To my understanding this is wrong, anyone please correct me.


Solution

  • The problem is that you're calling time.sleep(5) and self.OnCorrectComPort() in the callback, before returning to the mainloop where the events will be processed.

    The widgets will not reflect the effects of your Clear calls until you exit of the callback into the wx mainloop.

    What happens is, the routines you call are executed (takes several seconds because of the time.sleep call, then wx gets to process the graphical commands, and the widgets are cleared at this very moment (which is too late and the GUI seems stuck with the previous state)

    If you want it the other way round, you can use wx.CallAfter() to leave wx a chance to process its events before you call your routines.

    In your case, since you want to wait 5 seconds, the risk is to freeze your interface again. It's even better to call wx.CallLater() with a 5 second delay in that case, leaving the time to wx to refresh all the widgets.

    Modified code:

      def OnReset(self, event): # A function event which works after a button is pressed
    
            self.reset_pump.Disable() # Disables the button so it is clicked
            self.WriteToController([0x30],'GuiMsgIn') # Sends the reset command
            self.flag_read.set() # Set Event of the thread
            time.sleep(0.25)
            self.tr.join() # Joining a Thread
    
            self.MessageBox('Pump RESET going on Click OK \n')
            # Having the above step is useful
            # The question I have is based on the commands from here:    
            self.offset_text_control.Clear()
            self.gain_text_control.Clear()
            self.firmware_version_text_control.Clear()
            self.pump_rpm_text_control.Clear()
            self.pressure_text_control.Clear()
            self.last_error_text_control.Clear()
            self.error_count_text_control.Clear()
            self.pump_model_text_control.Clear()
            self.pump_serial_number_text_control.Clear()
            self.on_time_text_control.Clear()
            self.job_on_time_text_control.Clear()
            # The above commands clear various widgets on my GUI. 
            self.ser.close() # Closes my serial connection to MCU
            # will call calledAfter after 5 seconds
            wx.CallLater(5000,self.calledAfter,[ser,event])
    
      def calledAfter(self,ser,event):
            self.OnCorrectComPort(event) # An external function which gets executed. This function has a Message BOX - which says - PORT IS OPENED.