I'm developing a GUI using wxPython (Boa Constructor IDE). My GUI has the following:
My requirement is that when I press the START button, numbers (1, 2, 3, etc.) should start printing in the text control; it should stop when I press the STOP button. Code and GUI are as shown. What changes do I need to make to meet my requirements?
Appearance:
Code:
import wx
import wx.richtext
def create(parent):
return Frame3(parent)
[wxID_FRAME3, wxID_FRAME3BUTTON1, wxID_FRAME3BUTTON2, wxID_FRAME3PANEL1,
wxID_FRAME3RICHTEXTCTRL1,
] = [wx.NewId() for _init_ctrls in range(5)]
class Frame3(wx.Frame):
def _init_ctrls(self, prnt):
# generated method, don't edit
wx.Frame.__init__(self, id=wxID_FRAME3, name='', parent=prnt,
pos=wx.Point(579, 234), size=wx.Size(414, 492),
style=wx.DEFAULT_FRAME_STYLE, title='Frame3')
self.SetClientSize(wx.Size(406, 458))
self.panel1 = wx.Panel(id=wxID_FRAME3PANEL1, name='panel1', parent=self,
pos=wx.Point(0, 0), size=wx.Size(406, 458),
style=wx.TAB_TRAVERSAL)
self.richTextCtrl1 = wx.richtext.RichTextCtrl(id=wxID_FRAME3RICHTEXTCTRL1,
parent=self.panel1, pos=wx.Point(96, 96), size=wx.Size(200, 100),
style=wx.richtext.RE_MULTILINE, value=u'')
self.richTextCtrl1.SetLabel(u'richText')
self.button2 = wx.Button(id=wxID_FRAME3BUTTON2, label=u'STOP',
name='button2', parent=self.panel1, pos=wx.Point(256, 280),
size=wx.Size(75, 23), style=0)
self.button2.Bind(wx.EVT_BUTTON, self.OnButton2Button,
id=wxID_FRAME3BUTTON2)
self.button1 = wx.Button(id=wxID_FRAME3BUTTON1, label=u'START',
name='button1', parent=self.panel1, pos=wx.Point(88, 280),
size=wx.Size(75, 23), style=0)
self.button1.Bind(wx.EVT_BUTTON, self.OnButton1Button,
id=wxID_FRAME3BUTTON1)
def __init__(self, parent):
self._init_ctrls(parent)
def OnButton1Button(self, event): #START BUTTON
event.Skip()
def OnButton2Button(self, event): #STOP BUTTON
event.Skip()
if __name__ == '__main__':
app = wx.PySimpleApp()
frame = create(None)
frame.Show()
app.MainLoop()
In general, this is an accepted way of doing it in wxPython, and comes straight from the docs
Create a new "data" event.
Make your controller listen for the "data" events
Let pressing the "Start" button start a thread that increments a counter and sends a "data" event to your window with the counter value attached.
Upon reception of the event, add the value to your RichTextCtrl
Here's an example. Note in particular the use of Connect()
to listen for incoming value events.
import wx
import wx.richtext
import threading
import time
EVT_ID_VALUE = wx.NewId()
class DataEvent(wx.PyEvent):
def __init__(self, data):
wx.PyEvent.__init__(self)
self.SetEventType(EVT_ID_VALUE)
self.data=data
class Frame3(wx.Frame):
def __init__(self, parent, title):
self.counter = 0
self.worker = None
wx.Frame.__init__(
self, name='',
parent=parent,
pos=wx.Point(579, 234),
size=wx.Size(414, 492),
style=wx.DEFAULT_FRAME_STYLE, title='Frame3'
)
self.panel1 = wx.Panel(
name='panel1',
parent=self,
pos=wx.Point(0, 0),
size=wx.Size(406, 458),
style=wx.TAB_TRAVERSAL
)
self.richTextCtrl1 = wx.richtext.RichTextCtrl(
parent=self.panel1,
pos=wx.Point(96, 96),
size=wx.Size(200, 100),
style=wx.richtext.RE_MULTILINE,
value=u''
)
self.richTextCtrl1.SetLabel(u'richText')
self.richTextCtrl1.SetScrollbars(20,20,50,50)
self.button2 = wx.Button(
label=u'STOP',
name='button2',
parent=self.panel1,
pos=wx.Point(256, 280),
size=wx.Size(75, 23),
style=0
)
self.button2.Bind(
wx.EVT_BUTTON,
self.OnStop
)
self.button1 = wx.Button(
label=u'START',
name='button1',
parent=self.panel1,
pos=wx.Point(88, 280),
size=wx.Size(75, 23),
style=0
)
self.button1.Bind(
wx.EVT_BUTTON,
self.OnStart
)
self.Connect(-1, -1, EVT_ID_VALUE, self.OnValue )
def OnValue(self, event):
self.richTextCtrl1.AppendText("%d\n"%event.data)
def OnStart(self, event): #START BUTTON
self.richTextCtrl1.AppendText("START\n")
if not self.worker:
self.worker = WorkerThread(self)
self.worker.start()
def OnStop(self, event): #STOP BUTTON
self.richTextCtrl1.AppendText("STOP\n")
if self.worker:
self.worker.stop()
class WorkerThread(threading.Thread):
def __init__(self, notify_window):
threading.Thread.__init__(self)
self.counter = 0
self._notify_window = notify_window
self.abort = False
def run(self):
while not self.abort:
self.counter += 1
wx.PostEvent(self._notify_window, DataEvent(self.counter))
time.sleep(1)
def stop(self):
self.abort = True
if __name__ == '__main__':
app = wx.App()
frame = Frame3(None, "My Hello App")
frame.Show(True)
app.MainLoop()