问题现象描述:textctrl控件不能实时显示报文信息,只能在全部接收之后一次性显示到界面上,当报文信息量较大时,极易造成界面卡死。
原执行界面卡死:
解决办法参考文章:如何从子流程标准输出获得结果并在TextCtrl中实时显示它们? (Python 2.7 - wxPython)
http://cn.voidcc.com/question/p-faxdrneo-uv.html
将textctrl控件显示报文内容的功能移到线程进行执行。
代码片段如下:
class LinkThread(Thread):
def __init__(self, m_textCtrl1, can_device, baud_rate, device_id):
Thread.__init__(self)
self.m_textCtrl1 = m_textCtrl1
self.can_device = can_device
self.baud_rate = baud_rate
self.device_id = device_id
self.start()
def run(self):
Timing0 = can_interface.Timing0_dict[self.baud_rate]
Timing1 = can_interface.Timing1_dict[self.baud_rate]
vci_initconfig = can_interface.VCI_INIT_CONFIG(0x00000000, 0xFFFFFFFF, 0, 1, Timing0, Timing1, 0)
open_state = can_interface.open_device(self.can_device, self.device_id, 0)
if open_state == 0:
toastone = wx.MessageDialog(None, "打开设备操作失败!", "错误信息提示", wx.YES_DEFAULT | wx.ICON_QUESTION)
if toastone.ShowModal() == wx.ID_YES: # 如果点击了提示框的确定按钮
toastone.Destroy() # 则关闭提示框
elif open_state == -1:
toastone = wx.MessageDialog(None, "USB-CAN设备不存在或USB掉线!", "错误信息提示", wx.YES_DEFAULT | wx.ICON_QUESTION)
if toastone.ShowModal() == wx.ID_YES: # 如果点击了提示框的确定按钮
toastone.Destroy() # 则关闭提示框
else:
# 设置波特率
pData = can_interface.baud_rate_dict[self.baud_rate]
can_interface.set_reference(self.can_device, self.device_id, 0, 0, pData)
# 初始化can通道
can_interface.ini_can(self.can_device, self.device_id, 0, vci_initconfig)
# 启动can设备
start_state = can_interface.start_device(self.can_device, self.device_id, 0)
if start_state == 0:
toastone = wx.MessageDialog(None, "打开设备操作失败!", "错误信息提示", wx.YES_DEFAULT | wx.ICON_QUESTION)
if toastone.ShowModal() == wx.ID_YES: # 如果点击了提示框的确定按钮
toastone.Destroy() # 则关闭提示框
elif start_state == -1:
toastone = wx.MessageDialog(None, "USB-CAN设备不存在或USB掉线!", "错误信息提示", wx.YES_DEFAULT | wx.ICON_QUESTION)
if toastone.ShowModal() == wx.ID_YES: # 如果点击了提示框的确定按钮
toastone.Destroy() # 则关闭提示框
else:
# 开始接收can报文信息
count = 0
while 1:
# while count < 50:
# 清空缓冲区
can_interface.clear_buffer(self.can_device, self.device_id, 0)
rxdata = can_interface._RX_CAN_OBJ()
while can_interface.get_receive_num(self.can_device, self.device_id, 0) == 0:
continue
# 接收缓存数量
if can_interface.get_receive_num(self.can_device, self.device_id, 0) == 1:
if (can_interface.receive_msg(self.can_device, self.device_id, 0, rxdata, 50, 100)):
count += 1
msg_view_dict = analysis_msg.analyse_msg(rxdata)
msg_view_dict["序号"] = (8 - len(str(count))) * "0" + str(count)
text_str = " ".join(["序号:%s" % msg_view_dict["序号"],
"传输方向:%s" % msg_view_dict["传输方向"],
"帧ID:%s" % msg_view_dict["帧ID"],
"帧格式:%s" % msg_view_dict["帧格式"],
"帧类型:%s" % msg_view_dict["帧类型"],
"数据(HEX):%s" % msg_view_dict["数据(HEX)"]])
self.data = msg_view_dict["数据(HEX)"]
wx.CallAfter(self.m_textCtrl1.write, text_str + "\n")
else:
print("接收缓存区为空")
else:
print("接收缓存数量大于1")
在原来的Frame下设置按钮触发事件onLink,执行LinkThread线程。
# 设置按钮触发事件
if self.m_button1.GetLabel() == "连接":
self.m_button1.Bind(wx.EVT_LEFT_DOWN, self.onLink)
def onLink(self, event):
self.link_thread = LinkThread(self.m_textCtrl1, self.can_device, self.baud_rate, self.device_id)
if self.link_thread:
self.m_button1.SetLabel("断开")
self.m_button1.Bind(wx.EVT_LEFT_DOWN, self.onClose)
代码调整之后,textctrl实时显示报文信息并且不会出现界面卡住的运行截图: