我需要一个启动和停止按钮,以使用while循环连续读取数据,因此我在这里https://wiki.wxpython.org/LongRunningTasks中使用了第一个示例。然后我也想连续地更改图形,但是我不能这样做,以模拟我试图只更改TextCtrl。因此,我使用wx.CallAfter在TextCtrl上进行编写,并且看到“内部”发生了变化,但没有更新框架。我也尝试过使用Update()和Refresh(),但这也不起作用。因此,我不知道该怎么办,并且已经搜索了所有我可能又不知道该做什么的地方,因此对您的帮助表示感谢!
import nidaqmx
import wx
import wxmplot
import time
from threading import Thread
from numpy import mean, std
from nidaqmx.constants import AcquisitionType, DataTransferActiveTransferMode, TerminalConfiguration
ID_START = wx.NewId()
ID_STOP = wx.NewId()
EVT_RESULT_ID = wx.NewId()
def EVT_RESULT(win, func):
"""Define Result Event."""
win.Connect(-1, -1, EVT_RESULT_ID, func)
class ResultEvent(wx.PyEvent):
"""Simple event to carry arbitrary result data."""
def __init__(self, data):
"""Init Result Event."""
wx.PyEvent.__init__(self)
self.SetEventType(EVT_RESULT_ID)
self.data = data
myEVT = wx.NewEventType()
EVT = wx.PyEventBinder(myEVT, 1)
class MyEvent(wx.PyCommandEvent):
def __init__(self, evtType, id):
wx.PyCommandEvent.__init__(self, evtType, id)
myVal = None
def SetMyVal(self, val):
self.myVal = val
def GetMyVal(self):
return self.myVal
# janela para ler canais
class NewTaskWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(1000,500))
self.parent = parent
self.title = title
self.task_panel = wx.Panel(self, wx.ID_ANY, size = (1000,500))
self.canais = ['Canal', 'Dev1/ai0','Dev1/ai1','Dev1/ai2','Dev1/ai3','Dev1/ai4','Dev1/ai5',
'Dev1/ai6','Dev1/ai7','Dev1/ai8','Dev1/ai9','Dev1/ai10','Dev1/ai11',
'Dev1/ai12','Dev1/ai13','Dev1/ai14','Dev1/ai15']
self.cfgs = [TerminalConfiguration.DEFAULT,
TerminalConfiguration.DEFAULT,
TerminalConfiguration.DIFFERENTIAL,
TerminalConfiguration.NRSE,
TerminalConfiguration.PSEUDODIFFERENTIAL,
TerminalConfiguration.RSE]
self.configs = ['Modo', 'DEFAULT', 'DIFFERENTIAL', 'NRSE', 'PSEUDODIFFERENTIAL', 'RSE']
self.config1 = TerminalConfiguration.DEFAULT
self.config2 = TerminalConfiguration.DEFAULT
self.config3 = TerminalConfiguration.DEFAULT
self.config4 = TerminalConfiguration.DEFAULT
self.chan1 = 'canal1'
self.chan2 = 'canal2'
self.chan3 = 'canal3'
self.chan4 = 'canal4'
wx.Button(self.task_panel, ID_START, 'Start', pos=(10,10))
wx.Button(self.task_panel, ID_STOP, 'Stop', pos=(10,90))
self.status = wx.StaticText(self.task_panel, -1, '', pos=(800,0))
self.lista_canais_1 = wx.ComboBox(self.task_panel, id=1, pos=(106,10),
size=(100,80), choices=self.canais, style=wx.CB_READONLY)
self.lista_canais_1.SetSelection(0)
self.lista_canais_2 = wx.ComboBox(self.task_panel, id=2, pos=(106,40),
size=(100,80), choices=self.canais, style=wx.CB_READONLY)
self.lista_canais_2.SetSelection(0)
self.lista_canais_3 = wx.ComboBox(self.task_panel, id=3, pos=(106,70),
size=(100,80), choices=self.canais, style=wx.CB_READONLY)
self.lista_canais_3.SetSelection(0)
self.lista_canais_4 = wx.ComboBox(self.task_panel, id=4, pos=(106,100),
size=(100,80), choices=self.canais, style=wx.CB_READONLY)
self.lista_canais_4.SetSelection(0)
self.lista_configs_1 = wx.ComboBox(self.task_panel, id=5, pos=(216,10),
size=(100,80), choices=self.configs, style= wx.CB_READONLY)
self.lista_configs_1.SetSelection(0)
self.lista_configs_2 = wx.ComboBox(self.task_panel, id=6, pos=(216,40),
size=(100,80), choices=self.configs, style= wx.CB_READONLY)
self.lista_configs_2.SetSelection(0)
self.lista_configs_3 = wx.ComboBox(self.task_panel, id=7, pos=(216,70),
size=(100,80), choices=self.configs, style= wx.CB_READONLY)
self.lista_configs_3.SetSelection(0)
self.lista_configs_4 = wx.ComboBox(self.task_panel, id=8, pos=(216,100),
size=(100,80), choices=self.configs, style= wx.CB_READONLY)
self.lista_configs_4.SetSelection(0)
self.check1 = wx.CheckBox(self.task_panel, wx.ID_ANY, "ON", pos=(330,10), size=(40,20))
self.check2 = wx.CheckBox(self.task_panel, wx.ID_ANY, "ON", pos=(330,40), size=(40,20))
self.check3 = wx.CheckBox(self.task_panel, wx.ID_ANY, "ON", pos=(330,70), size=(40,20))
self.check4 = wx.CheckBox(self.task_panel, wx.ID_ANY, "ON", pos=(330,100), size=(40,20))
self.input_pontos = wx.TextCtrl(self.task_panel , wx.ID_ANY, style = wx.TE_PROCESS_ENTER,
value = "0", size =(90,20), pos = (10,70))
self.media1_text = wx.TextCtrl(self.task_panel , wx.ID_ANY, style = wx.TE_READONLY,
size =(90,20), pos = (420,12)) #<<<<-----------------------
self.media2_text = wx.TextCtrl(self.task_panel , wx.ID_ANY, style = wx.TE_READONLY,
size =(90,20), pos = (420,42))
self.media3_text = wx.TextCtrl(self.task_panel , wx.ID_ANY, style = wx.TE_READONLY,
size =(90,20), pos = (420,72))
self.media4_text = wx.TextCtrl(self.task_panel , wx.ID_ANY, style = wx.TE_READONLY,
size =(90,20), pos = (420,102))
self.desvio1_text = wx.TextCtrl(self.task_panel , wx.ID_ANY, style = wx.TE_READONLY,
size =(90,20), pos = (560,12))
self.desvio2_text = wx.TextCtrl(self.task_panel , wx.ID_ANY, style = wx.TE_READONLY,
size =(90,20), pos = (560,42))
self.desvio3_text = wx.TextCtrl(self.task_panel , wx.ID_ANY, style = wx.TE_READONLY,
size =(90,20), pos = (560,72))
self.desvio4_text = wx.TextCtrl(self.task_panel , wx.ID_ANY, style = wx.TE_READONLY,
size =(90,20), pos = (560,102))
wx.StaticText(self.task_panel, wx.ID_ANY, "Nº Pontos:", (10,50))
wx.StaticText(self.task_panel, wx.ID_ANY, "Média:", (380,12))
wx.StaticText(self.task_panel, wx.ID_ANY, "Média:", (380,42))
wx.StaticText(self.task_panel, wx.ID_ANY, "Média:", (380,72))
wx.StaticText(self.task_panel, wx.ID_ANY, "Média:", (380,102))
wx.StaticText(self.task_panel, wx.ID_ANY, "Desvio: ", (520,12))
wx.StaticText(self.task_panel, wx.ID_ANY, "Desvio: ", (520,42))
wx.StaticText(self.task_panel, wx.ID_ANY, "Desvio: ", (520,72))
wx.StaticText(self.task_panel, wx.ID_ANY, "Desvio: ", (520,102))
self.Bind(wx.EVT_COMBOBOX, self.SelectChannel, self.lista_canais_1)
self.Bind(wx.EVT_COMBOBOX, self.SelectChannel, self.lista_canais_2)
self.Bind(wx.EVT_COMBOBOX, self.SelectChannel, self.lista_canais_3)
self.Bind(wx.EVT_COMBOBOX, self.SelectChannel, self.lista_canais_4)
self.Bind(wx.EVT_COMBOBOX, self.SelectConfig, self.lista_configs_1)
self.Bind(wx.EVT_COMBOBOX, self.SelectConfig, self.lista_configs_2)
self.Bind(wx.EVT_COMBOBOX, self.SelectConfig, self.lista_configs_3)
self.Bind(wx.EVT_COMBOBOX, self.SelectConfig, self.lista_configs_4)
self.Bind(wx.EVT_BUTTON, self.OnStart, id=ID_START)
self.Bind(wx.EVT_BUTTON, self.OnStop, id=ID_STOP)
EVT_RESULT(self,self.OnResult)
self.worker = None
self.Bind(EVT, self.UpdateMedia1)
def OnStart(self, event): #<<<<<<<<<<<--------------
"""Start Computation."""
# Trigger the worker thread unless it's already busy
global pontos, checks, chans, configz
pontos=int(self.input_pontos.GetValue())
checks = [self.check1.GetValue(), self.check2.GetValue(),
self.check3.GetValue(), self.check4.GetValue()]
chans = [self.chan1, self.chan2, self.chan3, self.chan4]
configz = [self.config1, self.config2, self.config3, self.config4]
#self.media1_text.write('adsdsad')
if len(chans) == len(set(chans)):
self.graph_panel = wxmplot.plotpanel.PlotPanel(self.task_panel, pos=(0,150),
size=(500,350))
self.graph_panel.plot([0],[0])
if not self.worker:
self.status.SetLabel('Starting computation')
self.worker = WorkerThread(self, self.parent, self.title, 1)
else:
self.ErroCanais()
def OnStop(self, event):
"""Stop Computation."""
# Flag the worker thread to stop if running
if self.worker:
self.status.SetLabel('Trying to abort computation')
self.worker.abort()
def OnResult(self, event):
"""Show Result status."""
if event.data is None:
# Thread aborted (using our convention of None return)
self.status.SetLabel('Computation aborted')
else:
# Process results here
self.status.SetLabel('Computation Result: %s' % event.data)
# In either event, the worker is done
self.worker = None
def UpdateMedia1(self, x): # <<<<<<<----------------------
self.media1_text.write(x)
print(self.media1_text.GetValue())
print(wx.IsMainThread())
def ErroCanais(self):
chan_erro_frame = wx.Frame(self, wx.ID_ANY, "ERRO", size=(200,100))
chan_erro_panel = wx.Panel(chan_erro_frame, wx.ID_ANY, size=(200,100))
wx.StaticText(chan_erro_panel, wx.ID_ANY, "CANAIS IGUAIS", (30,20))
chan_erro_frame.Show()
def SelectChannel(self, event):
if event.GetId() == 1:
if event.GetString() == 'Canal':
self.chan1 = 'canal1'
else:
self.chan1 = event.GetString()
elif event.GetId() == 2:
if event.GetString() == 'Canal':
self.chan2 = 'canal2'
else:
self.chan2 = event.GetString()
elif event.GetId() == 3:
if event.GetString() == 'Canal':
self.chan3 = 'canal3'
else:
self.chan3 = event.GetString()
elif event.GetId() == 4:
if event.GetString() == 'Canal':
self.chan4 = 'canal4'
else:
self.chan4 = event.GetString()
def SelectConfig(self, event):
if event.GetId() == 5:
self.config1 = self.cfgs[event.GetSelection()]
elif event.GetId() == 6:
self.config2 = self.cfgs[event.GetSelection()]
elif event.GetId() == 7:
self.config3 = self.cfgs[event.GetSelection()]
elif event.GetId() == 8:
self.config4 = self.cfgs[event.GetSelection()]
class WorkerThread(Thread,NewTaskWindow):
"""Worker Thread Class."""
def __init__(self, notify_window, parent, title, value):
"""Init Worker Thread Class."""
Thread.__init__(self)
NewTaskWindow.__init__(self, parent, title)
self._notify_window = notify_window
self._want_abort = 0
# This starts the thread running on creation, but you could
# also make the GUI thread responsible for calling this
self.start()
def run(self):
"""Run Worker Thread."""
# This is the code executing in the new thread. Simulation of
# a long process (well, 10s here) as a simple loop - you will
# need to structure your processing so that you periodically
# peek at the abort variable
global pontos, checks, chans, configz
#chann1, chann2, chann3, chann4 = "","","",""
#chanz = [chann1, chann2, chann3, chann4]
#task = nidaqmx.Task()
#for i in range(4):
#if checks[i]==True:
#pass
# task.ai_channels.add_ai_voltage_chan(chans[i],
# terminal_config=configz[i])
# task.timing.cfg_samp_clk_timing(rate=10123,
# sample_mode=AcquisitionType.CONTINUOUS,
# samps_per_chan=10000)
# chanz[i] = nidaqmx._task_modules.channels.ai_channel.AIChannel(task._handle,
# chans[i])
# chanz[i].ai_data_xfer_mech = DataTransferActiveTransferMode.INTERRUPT
#data = []
pontos = 10
for i in range(pontos):
#p = []
#r = task.read(1)
#p.append(r)
#data.append(mean(p))
#event = MyEvent(myEVT, self.GetId())
#event.SetMyVal(i)
#self.GetEventHandler().ProcessEvent(event)
wx.CallAfter(self.UpdateMedia1, str(i)) #<<<<<<------------------
time.sleep(1)
if self._want_abort:
# Use a result of None to acknowledge the abort (of
# course you can use whatever you'd like or even
# a separate event type)
wx.PostEvent(self._notify_window, ResultEvent(None))
return
# Here's where the result would be returned (this is an
# example fixed result of the number 10, but it could be
# any Python object)
#wx.PostEvent(self._notify_window, ResultEvent(10))
def abort(self):
"""abort worker thread."""
# Method for use by main thread to signal an abort
self._want_abort = 1
class MainWindow(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(500,500))
self.CreateStatusBar() # A StatusBar in the bottom of the window
self.panel = wx.Panel(self, wx.ID_ANY)
new_task_button = wx.Button(self.panel, wx.ID_ANY, 'New Task', (10, 10))
# Setting up the menu.
filemenu= wx.Menu()
# wx.ID_ABOUT and wx.ID_EXIT are standard ids provided by wxWidgets.
menuAbout = filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.
self.v1_check = wx.CheckBox(self.panel, id=20, label="Valvula 1", pos=(20,50), size=(70,20))
self.v2_check = wx.CheckBox(self.panel, id=21, label="Valvula 2", pos=(20,70), size=(70,20))
self.v3_check = wx.CheckBox(self.panel, id=22, label="Valvula 3", pos=(20,90), size=(70,20))
self.v4_check = wx.CheckBox(self.panel, id=23, label="Valvula 4", pos=(20,110), size=(70,20))
self.v5_check = wx.CheckBox(self.panel, id=24, label="Porta 5", pos=(20,130), size=(70,20))
self.v6_check = wx.CheckBox(self.panel, id=25, label="Porta 6", pos=(20,150), size=(70,20))
self.v7_check = wx.CheckBox(self.panel, id=26, label="Porta 7", pos=(20,170), size=(70,20))
self.v8_check = wx.CheckBox(self.panel, id=27, label="Porta 8", pos=(20,190), size=(70,20))
self.v9_check = wx.CheckBox(self.panel, id=28, label="Porta 9", pos=(20,210), size=(70,20))
self.v10_check = wx.CheckBox(self.panel, id=29, label="Porta 10", pos=(20,230), size=(70,20))
# Set events.
self.Bind(wx.EVT_BUTTON, self.OnNewTask, new_task_button)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v1_check)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v2_check)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v3_check)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v4_check)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v5_check)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v6_check)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v7_check)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v8_check)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v9_check)
self.Bind(wx.EVT_CHECKBOX, self.AbrirFecharValvula, self.v10_check)
self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
self.Show(True)
def AbrirFecharValvula(self, event):
vchecksid=[20,21,22,23,24,25,26,27,28,29]
vchecks = [self.v1_check,self.v2_check,self.v3_check,self.v4_check,self.v5_check,
self.v6_check,self.v7_check,self.v8_check,self.v9_check,self.v10_check]
#num = str(vchecksid.index(event.GetId()))
#porta = 'Dev1/port'+num+'/line1'
for check in vchecks:
if check.GetId()==event.GetId():
#with nidaqmx.Task() as task:
#task.do_channels.add_do_chan(porta)
#task.write(check.GetValue())
print(check.GetValue())
def OnNewTask(self, event):
newin = NewTaskWindow(self.panel, 'Task')
newin.Show()
def OnAbout(self,e):
# A message dialog box with an OK button. wx.OK is a standard ID in wxWidgets.
dlg = wx.MessageDialog( self, "A user interface with nidaqmx",
"About NIDAQMX GUI", wx.OK)
dlg.ShowModal() # Show it
dlg.Destroy() # finally destroy it when finished.
def OnExit(self,e):
self.Close(True) # Close the frame.
# self.graph_panel.plot_many([(range(5),range(5)),(range(5),[0,0,0,0,0])])#[(x1,y1),(x2,y2)]
if __name__=='__main__':
app = wx.App(False)
frame = MainWindow(None, "NIDAQMX GUI")
frame.Centre()
app.MainLoop()
del app
我用<<<<< -----注释了部分原因代码。您可以运行它来查看自己的内容-单击“新建任务”,然后单击“启动”。 因此,CallAfter正在调用UpdateMedia1方法,它表明它在主线程中,并且它正在更改media1 textctrl的值,但在窗口中未更改,因此我不明白为什么。我也尝试过创建自己的事件并使用PostEvent,但这也不起作用。 我知道这是一个很长的问题,非常感谢您的阅读!!
答案 0 :(得分:0)
您的WorkerThread
类是从NewTaskWindow
派生的,因此在创建WorkerThread
时,您还会创建一个新的不可见的NewTaskWindow
在
wx.CallAfter(self.UpdateMedia1, str(i))
self
指的是不可见的第二帧,因此,其(不可见)文本控件已更新。
解决方案
不要继承NewTaskWindow
中的WorkerThread
而是调用可见框架对象的UpdateMedia1
(创建WorkerThread
时已将其作为参数)。