我正在构建一个GUI来控制for循环。所有代码都在工作,但在执行for循环时,它会锁定GUI,我无法访问GUI,直到循环结束。
我开始知道纠正这个问题的方法是使用线程。我试图将其实现到我的代码中,但未能做到这一点。我去过我的论坛,但我觉得我错过了什么。
我把我的代码放在这里:
import wx
import wx.grid
import wx.lib.agw.knobctrl as KC
import pylab
import os
import time
import threading
wildcard = "All files (*.txt)|*.txt"
halflifes={0 : (0.1*24.*3600.) , 1 : (0.05*24.*3600.) , 2 : (0.1*24.*3600.) , 3 : (0.1*24.*3600.) , 4 : (1.*24.*3600.)}
nuclides={0 : 500000 , 1 : 1000000 , 2 : 5000000}
def poissonsim(t, l , n , pathname):
r=pylab.random(n)
a= (r>=pylab.exp(-t*(pylab.log(2.)/l))) * 1
a = a.sum()
os.system("echo " + str(a) + ">>" + pathname+".txt")
return a
class PageOne(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.paused = True
self.create_main_panel()
##############################
def create_main_panel(self):
self.panel = wx.Panel(self,size=(450,450),pos=(25,25))
#self.toolbar = NavigationToolbar(self.canvas)
self.currentDirectory = os.getcwd()
self.nuclide1=0
self.halflife1=0
####################This is the pause Button##########################################
self.run_button = wx.Button(self.panel, -1, "RUN",(0,1)) # this is for the Pause Button
self.Bind(wx.EVT_BUTTON, self.on_run_button, self.run_button)
self.Bind(wx.EVT_UPDATE_UI, self.on_update_run_button, self.run_button)
self.knob1 = KC.KnobCtrl(self.panel, -1, size=(100, 100),pos=(0,150))
#self.knob1.SetFirstGradientColour(wx.BLUE)
#self.knob1.SetSecondGradientColour(wx.BLUE)
self.knob1.SetKnobRadius(8)
self.knob1.SetTags(range(0, 700, 100))
self.knob1.SetAngularRange(0, 180)
self.knob1.SetValue(0)
self.Bind(KC.EVT_KC_ANGLE_CHANGED, self.OnAngleChanged1, self.knob1)
self.knob2 = KC.KnobCtrl(self.panel, -2, size=(100, 100),pos=(200,150))
#self.knob2.SetFirstGradientColour(wx.BLUE)
#self.knob2.SetSecondGradientColour(wx.BLUE)
self.knob2.SetKnobRadius(8)
self.knob2.SetTags(range(0, 5500, 500))
self.knob2.SetAngularRange(0, 330)
self.knob2.SetValue(0)
self.Bind(KC.EVT_KC_ANGLE_CHANGED, self.OnAngleChanged2, self.knob2)
self.nuclide = wx.ComboBox(self.panel, 1, value="Small", pos=(200, 40), size=(100, -1), choices=["Small" , "Medium" , "Large" ], style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnSelectnuclide, self.nuclide)
self.halflife = wx.ComboBox(self.panel, 2, value="Sample A" ,pos=(0, 40), size=(100, -1), choices=["Sample A", "Sample B", "Sample C", "Sample D", "Sample E"] , style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnSelecthalflife, self.halflife)
self.textarea1 = wx.TextCtrl(self.panel, 1,style=wx.BORDER_SUNKEN|wx.TE_READONLY|wx.TE_RICH2 | wx.TE_CENTRE, pos=(0,100), size=(60,28))
self.textarea1.write("%d" % 0)
self.textarea2 = wx.TextCtrl(self.panel, 2,style=wx.BORDER_SUNKEN|wx.TE_READONLY|wx.TE_RICH2 | wx.TE_CENTRE, pos=(180,100), size=(60,28))
self.textarea2.write("%d" % 0)
self.textarea3 = wx.TextCtrl(self.panel, 3,style=wx.BORDER_SUNKEN|wx.TE_READONLY|wx.TE_RICH2 | wx.TE_CENTRE, pos=(250,100), size=(60,28))
self.textarea3.write("%d" % 0)
self.hbox = wx.BoxSizer(wx.HORIZONTAL)
self.hbox.Add(self.run_button, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
self.hbox.Add(self.nuclide, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
self.hbox.Add(self.halflife, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
self.hbox.Add(self.textarea1, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
self.hbox.Add(self.textarea2, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
self.hbox.Add(self.textarea3, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
self.hbox.Add(self.knob1, 0, wx.EXPAND | wx.ALL, 20)
self.hbox.Add(self.knob2, 0, wx.EXPAND | wx.ALL, 20)
#########################################
def OnAngleChanged1(self, event):
self.seconds = event.GetValue()/10
self.textarea1.Clear()
self.textarea1.write("%d" % self.seconds)
def OnAngleChanged2(self, event):
self.itterations = event.GetValue()
self.textarea2.Clear()
self.textarea2.write("%d" % self.itterations)
def onSaveFile(self):
"""
Create and show the Save FileDialog
"""
global path
dlg = wx.FileDialog(
self, message="Save file as ...",
defaultDir=self.currentDirectory, defaultFile="trial", wildcard=wildcard, style=wx.FD_SAVE)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
return path
dlg.Destroy()
def on_run_button(self, event):
self.paused = not self.paused
pathname = self.onSaveFile()
if not self.paused:
i=0
for i in range(self.itterations):
poissonsim(self.seconds, halflifes[self.halflife1], nuclides[self.nuclide1] , pathname)
#worker = CountingThread(self, 1)
#worker.start()
self.textarea3.Clear()
self.textarea3.write(str(i))
if i==self.itterations-1:
self.paused = True
label="Stop"
pcolor=(255,0,0)
self.run_button.SetLabel(label)
self.run_button.SetBackgroundColour(pcolor)
def on_update_run_button(self, event):
if self.paused:
label = "RUN"
pcolor= (0,255,255 )
else:
label="Stop"
pcolor=(255,0,0)
self.run_button.SetLabel(label)
self.run_button.SetBackgroundColour(pcolor)
def OnSelectnuclide(self, event):
self.nuclide1 = event.GetSelection()
def OnSelecthalflife(self, event):
self.halflife1 = event.GetSelection()
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="Simple Notebook Example",size=(400,400))
#self.create_menu()
# Here we create a panel and a notebook on the panel
p = wx.Panel(self)
nb = wx.Notebook(p)
# create the page windows as children of the notebook
page1 = PageOne(nb)
# add the pages to the notebook with the label to show on the tab
nb.AddPage(page1, "Measurment")
# finally, put the notebook in a sizer for the panel to manage
# the layout
sizer = wx.BoxSizer()
sizer.Add(nb, 1, wx.EXPAND)
p.SetSizer(sizer)
#def create_menu(self):
# self.menubar = wx.MenuBar()
# menu_file = wx.Menu()
# m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit")
# self.Bind(wx.EVT_MENU, self.on_exit, m_exit)
# self.menubar.Append(menu_file, "&File")
# self.SetMenuBar(self.menubar)
def on_exit(self, event):
self.Destroy()
if __name__ == "__main__":
app = wx.App(clearSigInt=True)
MainFrame().Show()
app.MainLoop()
答案 0 :(得分:1)
您的代码似乎不包含 CountingThread 类。无论如何,在wxPython中使用线程时,您需要使用wxPython的线程安全方法之一:
我通常使用 wx.CallAfter 。使用它时,您可以将对文本控件的引用传递给线程类:
class CountingThread(Thread):
def __init__(self, txt_ctrl):
Thread.__init__(self)
self.txt_ctrl = txt_ctrl
self.start()
def run(self):
# do your long running stuff here
print('running something long')
# update the display
wx.CallAfter(self.txt_ctrl.SetValue, 'I have changed')
像上面这样的东西应该有效。另见以下内容: