经常更新GUI WxPYTHON

时间:2016-09-21 22:16:25

标签: multithreading wxpython publish-subscribe

我有一段代码必须每100毫秒执行一次并更新GUI。当我更新GUI时 - 我按下一个按钮,它调用一个线程,然后调用一个目标函数。目标函数使用pub sub将消息返回给GUI线程,如下所示。

wx.CallAfter(pub.sendMessage, "READ EVENT", arg1=data, arg2=status_read) # This command line is in my target function

        pub.subscribe(self.ReadEvent, "READ EVENT") # This is in my GUI file - whihc calls the following function

 def ReadEvent(self, arg1, arg2):
        if arg2 == 0:
            self.MessageBox('The program did not properly read data from MCU \n Contact the Program Developer')
            return

        else:
            self.data = arg1

            self.firmware_version_text_control.Clear()
            #fwversion = '0x' + ''.join('{:02X}'.format(j) for j in reversed(fwversion))
            self.firmware_version_text_control.AppendText(str(SortAndDecode(self.data, 'FwVersion')))
            # Pump Model
            self.pump_model_text_control.Clear()
            self.pump_model_text_control.AppendText(str(SortAndDecode(self.data, 'ModelName')))
            # Pump Serial Number
            self.pump_serial_number_text_control.Clear()
            self.pump_serial_number_text_control.AppendText(str(SortAndDecode(self.data, 'SerialNum'))[:10]) # Personal Hack to not to display the AA , AB and A0
            # Pressure GAIN
            self.gain_text_control.Clear()
            self.gain_text_control.AppendText(str(SortAndDecode(self.data, 'PresGain')))
            # Pressure OFFSET Offset
            self.offset_text_control.Clear()
            self.offset_text_control.AppendText(str(SortAndDecode(self.data, 'PresOffset')))
            #Wagner Message:
            #self.status_text.SetLabel(str(SortAndDecode(self.data, 'WelcomeMsg')))
            # PUMP RUNNING OR STOPPED

            if PumpState(SortAndDecode(self.data, 'PumpState')) == 1:
                self.led6.SetBackgroundColour('GREEN')
            elif PumpState(SortAndDecode(self.data, 'PumpState')) == 0:
                self.led6.SetBackgroundColour('RED')
            else:
                self.status_text.SetLabel(PumpState(SortAndDecode(self.data, 'PumpState')))
            # PUMP RPM
            self.pump_rpm_text_control.Clear()
            if not self.new_model_value.GetValue():
                self.pump_rpm_text_control.AppendText("000")
            else:
                self.pump_rpm_text_control.AppendText(str(self.sheet_num.cell_value(self.sel+1,10)*(SortAndDecode(self.data, 'FrqQ5'))/65536))
            # PUMP PRESSURE
            self.pressure_text_control.Clear()
            self.pressure_text_control.AppendText(str(SortAndDecode(self.data, 'PresPsi')))
            # ON TIME   -- HOURS AND MINUTES --- EDITING IF YOU WANT
            self.on_time_text_control.Clear()
            self.on_time_text_control.AppendText(str(SortAndDecode(self.data, 'OnTime')))
            # JOB ON TIME - HOURS AND MINUTES - EDITING IF YOU WANT
            self.job_on_time_text_control.Clear()
            self.job_on_time_text_control.AppendText(str(SortAndDecode(self.data, 'JobOnTime')))
            # LAST ERROR ----- RECHECK THIS AGAIN
            self.last_error_text_control.Clear()
            self.last_error_text_control.AppendText(str(SortAndDecode(self.data, 'LastErr')))
            # LAST ERROR COUNT --- RECHECK THIS AGAIN
            self.error_count_text_control.Clear()
            self.error_count_text_control.AppendText("CHECK THIS")

正如您所看到的,READEVENT非常庞大,GUI需要一段时间才能成功完成所有这些工作。我的问题是,当我的GUI更新TEXTCTRL的值时,它没有响应 - 我不能做任何其他事情。我无法按下按钮或输入数据或其他任何内容。我的问题是,如果有更好的方法让我这样做,那么我的GUI就不会反应迟钝。我不知道如何把它放在不同的线程中,因为所有小部件都在主GUI中。但这也需要每隔100毫秒继续创建线程 - 这太可怕了。任何建议都会有很大帮助。

1 个答案:

答案 0 :(得分:0)

一些建议:

  1. SortAndDecode需要多长时间?那个结果的str()怎么样?这些可能是将这些处理保留在工作线程而不是UI线程中,并将值传递给预先排序和解码的UI线程的良好候选者。

  2. 通过调用ChangeValue代替ClearAppendText,您可以在每次迭代中节省一点时间。为什么每个文本小部件有两个函数调用而不是一个?与其他Python代码相比,Python中的函数调用相对昂贵。

  3. 如果有可能在最后一次迭代时发送相同的值,则添加与旧值匹配的新值的检查并跳过窗口小部件的更新可能会节省大量时间。与单独留下相比,更新小部件值非常昂贵。

  4. 除非有100毫秒更新的硬性要求,否则您可能需要尝试150或200.对于大多数人来说,每秒更新的速度可能更快,特别是因为它主要是文本的。你能在100ms读取多少文本?

  5. 如果您仍然遇到比UI线程可以跟上的更新更多的麻烦,那么您可能希望使用与pubsub和wx.CallAfter不同的方法。例如,您可以让工作线程接收并处理数据,然后将对象添加到Queue.Queue,然后调用wx.WakeUpIdle()。在UI线程中,您可以使用EVT_IDLE事件处理程序来检查队列并将第一个项目拉出队列(如果有),然后使用该数据更新窗口小部件。这样可以避免使用来自过多wx.CallAfter次调用的事件来处理待处理事件列表,并且如果项目中的项目太多,您还可以执行从数据队列中删除项目等操作。