wxPython 从线程自动更新 TextCtrl

问题描述 投票:0回答:1

我正在创建一个通信 GUI,它使用我无法发布的导入的 tx 和 rx python 脚本发送和接收消息。我已经独立测试了它们,它们按预期工作。我希望 GUI 的工作方式是打开一个 tx GUI 和一个 rx GUI。当选择 tx 单选按钮并且用户点击发送时,它会调用 tx 脚本并将消息发送到 rx 脚本接收到的位置,并显示在底部 TextCtrl 框中。

我相信我必须使用线程来运行 rx 脚本,因为 tx 脚本在主线程中运行。您会注意到,当选择 rx 单选按钮时,我会创建线程,因此它只会发生一次。但是,我希望每次收到新消息时都调用 receive_msg 函数,以便更新 TextCtrl 框。如何在不创建多个线程的情况下做到这一点?

我尝试将receed_msg函数绑定到发送按钮,但没有帮助。

import wx
import tx_UDP
import rx_UDP
import threading

class ExamplePanel(wx.Frame):

    def __init__(self, parent, title): 
        wx.Frame.__init__(self,parent, title=title, size=(600,600))
        
        self.InitUI()

    def InitUI(self):
        pn1 = wx.Panel(self)
        self.quote = wx.StaticText(pn1, label="Please select transmission direction:", pos=(20, 30))

        # A multiline TextCtrl
        self.rx_box = wx.TextCtrl(pn1, pos=(20, 370), size=(500,100), style=wx.TE_MULTILINE | wx.TE_READONLY)
        self.tx_box = wx.TextCtrl(pn1, pos=(20,110), size=(500,200), style=wx.TE_MULTILINE)
        #self.logger = wx.TextCtrl(self, pos=(300,20), size=(200,300), style=wx.TE_MULTILINE | wx.TE_READONLY)

        # Send button
        self.send_button = wx.Button(pn1, label="Send", pos=(450, 325))
        self.send_button.Bind(wx.EVT_BUTTON, self.OnSendClick)

        # TX & RX Radio Boxes
        tx_rx = ['TX','RX']
        self.rb = wx.RadioBox(pn1, label="", pos=(20, 50), choices=tx_rx, majorDimension=2, style=wx.RA_SPECIFY_COLS)
        self.rb.Bind(wx.EVT_RADIOBOX, self.EvtRadioBox)

        self.Show(True)


    def EvtRadioBox(self,event): 
        rb_index = self.rb.GetSelection()
        # TX
        if rb_index == 0:       
            self.send_button.Enable()
            self.tx_box.Enable()
        # RX
        else:
            self.send_button.Disable()
            self.tx_box.Disable()
            t=threading.Thread(target=self.Recieved_msg)
            t.start()
            

    def OnSendClick(self, event):
        message = self.tx_box.GetValue()
        tx_UDP.tx_UDP(message)

    def Recieved_msg(self, event=None):
        recieved_msg = rx_UDP.rx_UDP()
        self.rx_box.SetValue(recieved_msg)  
        
python multithreading wxpython python-multithreading
1个回答
0
投票

您还没有发布可行的代码,因此无需重新发明轮子,我怀疑您将能够使用

wx.lib.newevent
来发布您自己的
events
,以通常的方式在主循环中将其绑定到。

当您收到事件时,您可以使用您在事件中收到的任何消息更新相应的文本控件。

这里有一个例子供你选择。

from threading import Thread
import wx
import time
import wx.lib.newevent

progress_event, EVT_PROGRESS_EVENT = wx.lib.newevent.NewEvent()

class WorkThread(Thread):

    def __init__(self,parent_target):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self.target = parent_target
        self.stop_work_thread = 0
        self.start()  # start the thread

    def run(self):
        curr_loop = 0
        while True:
            if self.stop_work_thread == 1: # Exit
                break
            time.sleep(1)
            if self.stop_work_thread == 2: # Paused
                continue
            curr_loop += 1
            evt = progress_event(count=curr_loop,name=self.name)
            #Send back current count for the progress bar
            try:
                wx.PostEvent(self.target, evt)
            except: # The parent frame has probably been destroyed
                self.stop()
        return

    def stop(self):
        self.stop_work_thread = 1

    def pause(self):
        if self.stop_work_thread == 2:
            self.stop_work_thread = 0
            self.target.pause_btn.SetLabel('Pause')
        else:
            self.stop_work_thread = 2
            self.target.pause_btn.SetLabel('Paused')

class Progress(wx.Frame):
    def __init__(self, parent, title):
        super(Progress, self).__init__(parent, title = title,size = (500,300))
        left_sizer = wx.BoxSizer(wx.VERTICAL)
        middle_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.panel = wx.Panel(self)

        self.start_btn = wx.Button(self.panel, label="Start")
        self.stop_btn =wx.Button(self.panel, label="Stop")
        self.count_btn =wx.Button(self.panel, label="Count")
        self.pause_btn =wx.Button(self.panel, label="Pause")
        self.quit_btn =wx.Button(self.panel, label="Quit")
        self.logger = wx.TextCtrl(self.panel, size=(200,200), style=wx.TE_MULTILINE | wx.TE_READONLY)

        self.stop_btn.Disable()
        self.count_btn.Disable()
        self.pause_btn.Disable()
        left_sizer.Add(self.start_btn,0,wx.EXPAND)
        left_sizer.Add(self.stop_btn,0,wx.EXPAND)
        left_sizer.Add(self.count_btn,0,wx.EXPAND)
        left_sizer.Add(self.pause_btn,0,wx.EXPAND)
        left_sizer.Add(self.quit_btn,0,wx.EXPAND)
        middle_sizer.Add(self.logger,0,wx.EXPAND)
        self.mainsizer = wx.BoxSizer(wx.HORIZONTAL)
        self.mainsizer.Add(left_sizer)
        self.mainsizer.Add(middle_sizer)
        self.panel.SetSizer(self.mainsizer)
        self.Layout()

        self.start_btn.Bind(wx.EVT_BUTTON, self.onStart)
        self.stop_btn.Bind(wx.EVT_BUTTON, self.onCancel)
        self.pause_btn.Bind(wx.EVT_BUTTON, self.onPause)
        self.quit_btn.Bind(wx.EVT_BUTTON, self.onExit)
        #Bind to the progress event issued by the thread
        self.Bind(EVT_PROGRESS_EVENT, self.OnProgress)
        self.Bind(wx.EVT_CLOSE, self.onExit)

    def OnProgress(self, event):
        if not self.work.is_alive():
            return 
        step = event.count
        ident = event.name
        s_step = ident+" count "+str(step)+'\n'
        self.logger.AppendText(s_step)
        self.count_btn.SetLabel("Count "+str(step))

    def onStart(self, event):
        self.start_btn.Disable()
        self.work = WorkThread(parent_target=self)
        self.pause_btn.Enable()
        self.stop_btn.Enable()

    def onPause(self, event):
        if self.work.is_alive():
            self.work.pause() # Pause the thread

    def onCancel(self, event):
        """Cancel thread process"""
        try:
            self.work.stop()
            self.work.join()
        except:
            pass
        self.onFinish()

    def onFinish(self):
        """thread process finished - clean up"""
        self.start_btn.Enable()
        self.stop_btn.Disable()
        self.pause_btn.Disable()
        self.pause_btn.SetLabel("Pause")
        self.count_btn.SetLabel("Count") 
        self.logger.Clear()

    def onExit(self, event):
        self.onCancel(None)
        self.onFinish()
        self.Destroy()

app = wx.App()
frame = Progress(None,'Thread Incrementer')
frame.Show()
app.MainLoop()
© www.soinside.com 2019 - 2024. All rights reserved.