G
As I did you can't use blocking methods or functions within a GUI in general. Any function/method or structure that does not return "immediately" as time.sleep, input, cycle while, etc are blockers.Generally, a graphical interface is executed using a main cycle (mainloop) that is responsible for constantly reshaping the interface allowing it to respond adequately to the generated events. If in the same process you run anything that doesn't respond in a short time (without using concurrence) the mainloop crashes and the interface freezes to stop responding.To solve these problems you need to use some method that allows concurrence such as threads, processes, corrutins, etc. so that the blocking process does not interfere with the mainloop. You will also need to communicate both processes properly and safely (synchronization). The simplest thing is to use a thread and communicate with it using some safe method. One option is to use a queue ( https://docs.python.org/3.6/library/queue.html ) However, the vast majority of frameworks provide methods for communication with other threads or processes in a@mainthread in Kivy, QThread and sign in Qtetc.). In wxWidgets there are also methods to do this. You can use events or use https://wiki.wxpython.org/CallAfter next to https://wiki.wxpython.org/WxLibPubSub to send messages between objects. In addition to this you want to be able to "pause" the thread. To do this, you must establish appropriate methods to initiate, pause, resume and stop the execution of a thread. There are many ways to address these problems, depending on what you want to do. If you do not know anything about threads I advise you to first learn the concept of yarn, the importance of synchronization and the ways to get it (seeds, padlocks, etc.), you must not do when interacting with several threads, etc. I leave the link to the module documentation. threading from Python where you can find the information about the methods I will use in the example that I will leave below: https://docs.python.org/3/library/threading.html#condition-objects Explaining how to implement what you want from zero and in detail is quite extensive, as there are many ways to approach it. To focus on something I will leave you an example where we run a certain blocking code in a thread (in this case it will be a simple counter next to a sleep() to simulate a "long" processing time. The thread can be released and stopped using the main window of your GUI, we can also pause and resume the process carried out by the thread at any time. In order to pause and resume a thread we can also use several approaches. In this case a condition is used ( https://docs.python.org/3/library/threading.html#condition-objects ) associated with a lock to allow to pause and resume the thread, although there are other forms, such as the use of https://docs.python.org/3/library/threading.html#event-objects .I'll give you the code:# -*- coding: utf-8 -*-
import time
from threading import Thread
import wx
import wx.xrc
from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub
###########################################################################
class Worker
###########################################################################
class Worker(threading.Thread):
def init(self):
threading.Thread.init(self)
self.on = True
self.paused = False
self.condition = threading.Condition(threading.Lock())
def run(self):
n = 0
while self.on:
with self.condition:
while self.paused:
self.pause_cond.wait()
n += 1
wx.CallAfter(pub.sendMessage, 'actualizar', value=n)
time.sleep(2)
def pause(self):
# Al pausar cambiamos la varible de control y adquirimos el candado
if not self.paused:
self.paused = True
self.condition.acquire()
def resume(self):
# Al reanudar liberamos el candado
if self.paused:
self.paused = False
self.condition.notify()
self.condition.release()
def stop(self):
self.on = False
###########################################################################
Class MyFrame1
###########################################################################
class MyFrame1 ( wx.Frame
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.static = wx.StaticText( self, wx.ID_ANY, u"Inicie un hilo", wx.DefaultPosition, wx.DefaultSize, 0 )
self.static.Wrap( -1 )
self.static.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNTEXT ) )
self.static.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_HIGHLIGHTTEXT ) )
bSizer1.Add( self.static, 0, wx.ALL, 5 )
self.ini = wx.Button( self, wx.ID_ANY, u"iniciar", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer1.Add( self.ini, 0, wx.ALL, 5 )
self.det = wx.Button( self, wx.ID_ANY, u"detener", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer1.Add( self.det, 0, wx.ALL, 5 )
self.rea = wx.Button( self, wx.ID_ANY, u"reanudar", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer1.Add( self.rea, 0, wx.ALL, 5 )
self.pau = wx.Button( self, wx.ID_ANY, u"pausar", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer1.Add( self.pau, 0, wx.ALL, 5 )
self.SetSizer(bSizer1)
self.Layout()
self.Centre(wx.BOTH)
self.ini.Bind( wx.EVT_BUTTON, self._start_thread )
self.det.Bind( wx.EVT_BUTTON, self._stop_thread )
self.pau.Bind( wx.EVT_BUTTON, self._pause_thread )
self.rea.Bind( wx.EVT_BUTTON, self._resume_thread )
self.det.Disable()
self.pau.Disable()
self.rea.Disable()
pub.subscribe(self._update_label, "actualizar")
self.Bind(wx.EVT_CLOSE, self._when_closed)
self.hilo = None
def _update_label(self, value):
self.static.SetLabel("Numero {}".format(value))
def _start_thread(self, event):
self.ini.Disable()
self.det.Enable()
self.pau.Enable()
self.rea.Disable()
self.hilo = Worker()
self.hilo.start()
def _stop_thread(self, event):
if self.hilo:
self.hilo.stop()
self.det.Disable()
self.pau.Disable()
self.rea.Disable()
self.ini.Enable()
def _pause_thread(self, event):
if self.hilo:
self.hilo.pause()
self.pau.Disable()
self.rea.Enable()
def _resume_thread(self, event):
if self.hilo:
self.hilo.resume()
self.pau.Enable()
self.rea.Disable()
def _when_closed(self, event):
self._stop_thread(event)
event.Skip()
def __del__(self):
pass
app = wx.App()
fr = MyFrame1(None)
fr.Show()
app.MainLoop()
We can see it running: The theme of yarns and concurrence in general is very extensive and complex to explain in an answer. This is just an example of one of the many ways to address the problem. The code is tested under Python 3.6.1 with wxWidgets 4.0.0a3.