Wxpython线程

时间:2018-02-11 09:27:06

标签: multithreading wxpython

我正在构建一个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()

1 个答案:

答案 0 :(得分:1)

您的代码似乎不包含 CountingThread 类。无论如何,在wxPython中使用线程时,您需要使用wxPython的线程安全方法之一:

  • wx.CallAfter
  • wx.CallLater
  • wx.PostEvent

我通常使用 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')

像上面这样的东西应该有效。另见以下内容: