Logging freezes the application GUI

Hi, ALL,
I just added logging to my application into the text control instead
of the console. And I'm facing with the following issue:

My application start a very long and time consuming task with couple
of threads. This threads are started in the script that I don't have
control over. It is someone else script and it is written to work
under the CLI environment. My program should be just a GUI wrapper.

Now before the logging addition I had an indefinite process dialog
which was working fine. Everything was processing and the other MT
script was running behind the scenes. All was good.

Now instead of the progress dialog I have an actual dialog with a test
control init and I'm calling Show() on this dialog. Whenever the outer
scripts needs logging I'm pushing that message to this dialog's text
control. This part works fine, except that after the message is pushed
the GUI freezes. Sometimes after couple of lines, sometimes after the
very first line.

I tried to call wx.Yield() after printing the message to the text
control, but got an exception from C++ "only main thread can work with
GUI".
The outer script does not yield after emitting the log message as it
is written with the CLI interface in mind.

Now my question is: what can I do to "un-freeze" my application?
Obviously Yield() and its siblings wouldn't work.
Asking to change the outer script is not currently an option (maybe in
the future).

My code is using basicLogging() capabilities and just overrides an
emit() function of the logger.

Thank you for any hints.

Two ideas off the top of my head:

1: Try emit()ting the log messages to a Queue,
and have your GUI pull from that Queue via wx.Timer.

2: From your emit(), wx.PostEvent a custom event with your log line as data.

in emit():

  import wx.lib.newevent as newevent
  appdata.NetworkStatusEvent, appdata.EVT_NETWORK_STATUS = newevent.NewEvent()

  wx.PostEvent(
    appdata.networktoolbar.GetEventHandler(),
    appdata.NetworkStatusEvent(status=status,peer=peer)
    )

in the GUI:

  self.Bind(appdata.EVT_NETWORK_STATUS, OnStatus)

  def OnStatus(self,event):

           self.ChangeStatus(event.status,event.peer)

  ( "appdata" is my shared-state between threads class )

Regards,

Michael

···

On Sat, 14 Jun 2014 09:53:53 +0200, Igor Korot <ikorot01@gmail.com> wrote:

Hi, ALL,
I just added logging to my application into the text control instead
of the console. And I'm facing with the following issue:

My application start a very long and time consuming task with couple
of threads. This threads are started in the script that I don't have
control over. It is someone else script and it is written to work
under the CLI environment. My program should be just a GUI wrapper.

Now before the logging addition I had an indefinite process dialog
which was working fine. Everything was processing and the other MT
script was running behind the scenes. All was good.

Now instead of the progress dialog I have an actual dialog with a test
control init and I'm calling Show() on this dialog. Whenever the outer
scripts needs logging I'm pushing that message to this dialog's text
control. This part works fine, except that after the message is pushed
the GUI freezes. Sometimes after couple of lines, sometimes after the
very first line.

I tried to call wx.Yield() after printing the message to the text
control, but got an exception from C++ "only main thread can work with
GUI".
The outer script does not yield after emitting the log message as it
is written with the CLI interface in mind.

Now my question is: what can I do to "un-freeze" my application?
Obviously Yield() and its siblings wouldn't work.
Asking to change the outer script is not currently an option (maybe in
the future).

My code is using basicLogging() capabilities and just overrides an
emit() function of the logger.

Thank you for any hints.

Hi, Michael,

Hi, ALL,
I just added logging to my application into the text control instead
of the console. And I'm facing with the following issue:

My application start a very long and time consuming task with couple
of threads. This threads are started in the script that I don't have
control over. It is someone else script and it is written to work
under the CLI environment. My program should be just a GUI wrapper.

Now before the logging addition I had an indefinite process dialog
which was working fine. Everything was processing and the other MT
script was running behind the scenes. All was good.

Now instead of the progress dialog I have an actual dialog with a test
control init and I'm calling Show() on this dialog. Whenever the outer
scripts needs logging I'm pushing that message to this dialog's text
control. This part works fine, except that after the message is pushed
the GUI freezes. Sometimes after couple of lines, sometimes after the
very first line.

I tried to call wx.Yield() after printing the message to the text
control, but got an exception from C++ "only main thread can work with
GUI".
The outer script does not yield after emitting the log message as it
is written with the CLI interface in mind.

Now my question is: what can I do to "un-freeze" my application?
Obviously Yield() and its siblings wouldn't work.
Asking to change the outer script is not currently an option (maybe in
the future).

My code is using basicLogging() capabilities and just overrides an
emit() function of the logger.

Thank you for any hints.

Two ideas off the top of my head:

1: Try emit()ting the log messages to a Queue,
and have your GUI pull from that Queue via wx.Timer.

2: From your emit(), wx.PostEvent a custom event with your log line as data.

in emit():

        import wx.lib.newevent as newevent
        appdata.NetworkStatusEvent, appdata.EVT_NETWORK_STATUS =
newevent.NewEvent()

        wx.PostEvent(
                appdata.networktoolbar.GetEventHandler(),
                appdata.NetworkStatusEvent(status=status,peer=peer)
                )

in the GUI:

        self.Bind(appdata.EVT_NETWORK_STATUS, OnStatus)

        def OnStatus(self,event):

                self.ChangeStatus(event.status,event.peer)

        ( "appdata" is my shared-state between threads class )

Which solution is better?

Thank you.

···

On Sat, Jun 14, 2014 at 3:15 AM, Michael Ross <gmx@ross.cx> wrote:

On Sat, 14 Jun 2014 09:53:53 +0200, Igor Korot <ikorot01@gmail.com> wrote:

Regards,

Michael

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Hi, Michael,

Hi, ALL,
I just added logging to my application into the text control instead
of the console. And I'm facing with the following issue:

My application start a very long and time consuming task with couple
of threads. This threads are started in the script that I don't have
control over. It is someone else script and it is written to work
under the CLI environment. My program should be just a GUI wrapper.

Now before the logging addition I had an indefinite process dialog
which was working fine. Everything was processing and the other MT
script was running behind the scenes. All was good.

Now instead of the progress dialog I have an actual dialog with a test
control init and I'm calling Show() on this dialog. Whenever the outer
scripts needs logging I'm pushing that message to this dialog's text
control. This part works fine, except that after the message is pushed
the GUI freezes. Sometimes after couple of lines, sometimes after the
very first line.

I tried to call wx.Yield() after printing the message to the text
control, but got an exception from C++ "only main thread can work with
GUI".
The outer script does not yield after emitting the log message as it
is written with the CLI interface in mind.

Now my question is: what can I do to "un-freeze" my application?
Obviously Yield() and its siblings wouldn't work.
Asking to change the outer script is not currently an option (maybe in
the future).

My code is using basicLogging() capabilities and just overrides an
emit() function of the logger.

Thank you for any hints.

Two ideas off the top of my head:

1: Try emit()ting the log messages to a Queue,
and have your GUI pull from that Queue via wx.Timer.

2: From your emit(), wx.PostEvent a custom event with your log line as data.

in emit():

        import wx.lib.newevent as newevent
        appdata.NetworkStatusEvent, appdata.EVT_NETWORK_STATUS =
newevent.NewEvent()

        wx.PostEvent(
                appdata.networktoolbar.GetEventHandler(),
                appdata.NetworkStatusEvent(status=status,peer=peer)
                )

in the GUI:

        self.Bind(appdata.EVT_NETWORK_STATUS, OnStatus)

        def OnStatus(self,event):

                self.ChangeStatus(event.status,event.peer)

        ( "appdata" is my shared-state between threads class )

Which solution is better?

I don't know.

In my application, I use both.

A wx.Timer to handle the data-from-network processing
because this has to be haltet sometimes,
and this is quite easy with a timer:

  if already_running or global_hold_processing:
    return
  already_running=True

  ... pull data from queue ...
  ... process data ...

  already_running=False

If I were to do this in an Eventhandler,
I'd have to store the data in another queue in case I don't want it processed right now,
*and* have to re-post an Event to ensure it is processed some time.

I use the PostEvent method for GUI status indicators,
as a fire-and-forget method.

In your application I would ask if the event handler you'd be emitting to does always exist,
if not, you'd have to handle this in the logger.

···

On Sat, 14 Jun 2014 12:24:23 +0200, Igor Korot <ikorot01@gmail.com> wrote:

On Sat, Jun 14, 2014 at 3:15 AM, Michael Ross <gmx@ross.cx> wrote:

On Sat, 14 Jun 2014 09:53:53 +0200, Igor Korot <ikorot01@gmail.com> >> wrote:

Thank you.

Regards,

Michael

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Michael,

Hi, ALL,
I just added logging to my application into the text control instead
of the console. And I'm facing with the following issue:

My application start a very long and time consuming task with couple
of threads. This threads are started in the script that I don't have
control over. It is someone else script and it is written to work
under the CLI environment. My program should be just a GUI wrapper.

Now before the logging addition I had an indefinite process dialog
which was working fine. Everything was processing and the other MT
script was running behind the scenes. All was good.

Now instead of the progress dialog I have an actual dialog with a test
control init and I'm calling Show() on this dialog. Whenever the outer
scripts needs logging I'm pushing that message to this dialog's text
control. This part works fine, except that after the message is pushed
the GUI freezes. Sometimes after couple of lines, sometimes after the
very first line.

I tried to call wx.Yield() after printing the message to the text
control, but got an exception from C++ "only main thread can work with
GUI".
The outer script does not yield after emitting the log message as it
is written with the CLI interface in mind.

Now my question is: what can I do to "un-freeze" my application?
Obviously Yield() and its siblings wouldn't work.
Asking to change the outer script is not currently an option (maybe in
the future).

My code is using basicLogging() capabilities and just overrides an
emit() function of the logger.

Thank you for any hints.

Two ideas off the top of my head:

1: Try emit()ting the log messages to a Queue,
and have your GUI pull from that Queue via wx.Timer.

2: From your emit(), wx.PostEvent a custom event with your log line as data.

in emit():

        import wx.lib.newevent as newevent
        appdata.NetworkStatusEvent, appdata.EVT_NETWORK_STATUS =
newevent.NewEvent()

        wx.PostEvent(
                appdata.networktoolbar.GetEventHandler(),
                appdata.NetworkStatusEvent(status=status,peer=peer)
                )

in the GUI:

        self.Bind(appdata.EVT_NETWORK_STATUS, OnStatus)

        def OnStatus(self,event):

                self.ChangeStatus(event.status,event.peer)

        ( "appdata" is my shared-state between threads class )

I am going with the second approach. So here is my code:

class LoggingRedirectHandler(logging.StreamHandler):
        def __init__(self,dialog):
                logging.StreamHandler.__init__( self )
                self.textctrl = dialog

        def emit(self, record):
                import wx.lib.newevent as newevent
                UpdateLogCommandEvent, EVT_UPDATE_LOG_COMMAND_EVENT =
newevent.NewCommandEvent()
                msg = self.format( record )
                stream = self.stream
                frame = wx.GetApp().GetMainFrame()
                evt = updateLog(status=msg,peer=self)
                wx.PostEvent(frame.GetEventHandler(), evt)

class Frame(wx.Frame):
     def __init__()
         wx.Bind(EVT_UPDATE_LOG_COMMAND_EVENT, self.OnUpdateLog)

     def OnUpdateLog(self, event):
         msg = event.status
         dialog = event.peer
         wx.CallAfter(peer.textctrl.Write, msg)
         peer.textctrl.flush()

I'm getting a compier error on wx.Bind() line:

EVT_UPDATE_LOG_COMMAND_EVENT is not defined

How do I fix it?

Thank you.

···

On Sat, Jun 14, 2014 at 3:15 AM, Michael Ross <gmx@ross.cx> wrote:

On Sat, 14 Jun 2014 09:53:53 +0200, Igor Korot <ikorot01@gmail.com> wrote:

Regards,

Michael

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Michael,

...

EVT_UPDATE_LOG_COMMAND_EVENT is not defined

I think it is due that you define it within your method emit, shouldn't it be defined at the beginning of your module.

see:
wxpython.org/Phoenix/docs/html/lib.newevent.html

Werner

···

On 6/15/2014 8:45, Igor Korot wrote:

On Sat, Jun 14, 2014 at 3:15 AM, Michael Ross <gmx@ross.cx> wrote:

Werner,
One more thing:

class LoggingRedirectHandler(logging.StreamHandler):
        def __init__(self,dialog):
                logging.StreamHandler.__init__( self )
                self.textctrl = dialog

        def emit(self, record):
                msg = self.format( record )
                stream = self.stream
                frame = wx.GetTopLevelParent()
                evt = updateLog(status=msg,peer=self)
                wx.PostEvent(frame.GetEventHandler(), evt)
                #wx.CallAfter(self.textctrl.WriteText, msg + "\n" )
                #self.flush
                #wx.Yield()

The code crashes on the wx.GetTopLevelParent().
What is the best way to get the main frame window? I don't use MDI and
the code crashes even on:

wx.GetApp().GetMainFrame()

Using wxPython3.0.0 classic.

Thank you.

···

On Sun, Jun 15, 2014 at 12:27 AM, Werner <wernerfbd@gmx.ch> wrote:

On 6/15/2014 8:45, Igor Korot wrote:

Michael,

On Sat, Jun 14, 2014 at 3:15 AM, Michael Ross <gmx@ross.cx> wrote:

...

EVT_UPDATE_LOG_COMMAND_EVENT is not defined

I think it is due that you define it within your method emit, shouldn't it
be defined at the beginning of your module.

see:
wxpython.org/Phoenix/docs/html/lib.newevent.html

Werner

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

wx.GetApp().GetTopWindow() , but you need to do SetTopWindow in your OnInit

Werner

···

On 6/15/2014 11:27, Igor Korot wrote:

Werner,
One more thing:

class LoggingRedirectHandler(logging.StreamHandler):
         def __init__(self,dialog):
                 logging.StreamHandler.__init__( self )
                 self.textctrl = dialog

         def emit(self, record):
                 msg = self.format( record )
                 stream = self.stream
                 frame = wx.GetTopLevelParent()
                 evt = updateLog(status=msg,peer=self)
                 wx.PostEvent(frame.GetEventHandler(), evt)
                 #wx.CallAfter(self.textctrl.WriteText, msg + "\n" )
                 #self.flush
                 #wx.Yield()

The code crashes on the wx.GetTopLevelParent().
What is the best way to get the main frame window? I don't use MDI and
the code crashes even on:

wx.GetApp().GetMainFrame()

Hi, guys,

So now I have following code:

class Redirect(object):
    def __init__(self, textctrl):
        self.out = textctrl

    def write(self, string):
        wx.CallAfter(self.out.WriteText, string )

class LoggingRedirectHandler(logging.StreamHandler):
    def __init__(self,dialog):
        logging.StreamHandler.__init__( self )
        self.textctrl = dialog

    def emit(self, record):
        msg = self.format( record )
        stream = self.stream
        evt = UpdateLogCommandEvent(status=msg, peer=self)
        wx.PostEvent(self.textctrl.GetEventHandler(), evt)
        #wx.CallAfter(self.textctrl.WriteText, msg + "\n" )
        #self.flush
        #wx.Yield()

class Executor(wx.Dialog):
    def __init__(self, parent, ID, title, options, path_spec):
        self.options = options
        self.path_spec = path_spec
        wx.Dialog.__init__( self, parent, ID, title, size=(600,600) )
        sizer1 = wx.BoxSizer( wx.VERTICAL )
        self.log = wx.TextCtrl( self, size=(800,800), style =
wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL )
        sizer1.Add( self.log, 1, wx.EXPAND, 0 )
        self.SetSizer( sizer1 )
        sizer1.Fit( self )
        self.Bind(EVT_UPDATE_LOG_COMMAND_EVENT, self.OnUpdateLog)

    def OnUpdateLog(self, event):
        message = event.status
        peer = event.peer
        #self.log.WriteText(event.status + "\n")
        wx.CallAfter(self.log.WriteText, message + "\n" )
        #peer.textctrl.flush()

    def OnShowExecutor(self, logLevel):
        format_str = "[%(levelname)s] %(message)s"
        logging.basicConfig( level=logLevel, format=format_str )
        self.logger = logging.getLogger()
        self.logger.setLevel(logLevel)
        redir = Redirect(self.log)
        sys.stdout = redir
        sys.stderr = redir
        logger_stream_handler = LoggingRedirectHandler(self)
        self.logger.addHandler( logger_stream_handler )

With this code if I start moving the dialog where the log messages are
going, the GUI freezes.

Am I missing wx.Yield() call somewhere?
Also, I'd like to use Redirect class as well. Can I send the same
event from its write() method?

Thank you.

···

On Sun, Jun 15, 2014 at 3:00 AM, Werner <wernerfbd@gmx.ch> wrote:

On 6/15/2014 11:27, Igor Korot wrote:

Werner,
One more thing:

class LoggingRedirectHandler(logging.StreamHandler):
         def __init__(self,dialog):
                 logging.StreamHandler.__init__( self )
                 self.textctrl = dialog

         def emit(self, record):
                 msg = self.format( record )
                 stream = self.stream
                 frame = wx.GetTopLevelParent()
                 evt = updateLog(status=msg,peer=self)
                 wx.PostEvent(frame.GetEventHandler(), evt)
                 #wx.CallAfter(self.textctrl.WriteText, msg + "\n" )
                 #self.flush
                 #wx.Yield()

The code crashes on the wx.GetTopLevelParent().
What is the best way to get the main frame window? I don't use MDI and
the code crashes even on:

wx.GetApp().GetMainFrame()

wx.GetApp().GetTopWindow() , but you need to do SetTopWindow in your OnInit

Werner

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Anybody?
It still frezes and I have no clue where and what I'm doing wrong...

Thank you.

···

On Sun, Jun 15, 2014 at 4:23 AM, Igor Korot <ikorot01@gmail.com> wrote:

Hi, guys,

So now I have following code:

class Redirect(object):
    def __init__(self, textctrl):
        self.out = textctrl

    def write(self, string):
        wx.CallAfter(self.out.WriteText, string )

class LoggingRedirectHandler(logging.StreamHandler):
    def __init__(self,dialog):
        logging.StreamHandler.__init__( self )
        self.textctrl = dialog

    def emit(self, record):
        msg = self.format( record )
        stream = self.stream
        evt = UpdateLogCommandEvent(status=msg, peer=self)
        wx.PostEvent(self.textctrl.GetEventHandler(), evt)
        #wx.CallAfter(self.textctrl.WriteText, msg + "\n" )
        #self.flush
        #wx.Yield()

class Executor(wx.Dialog):
    def __init__(self, parent, ID, title, options, path_spec):
        self.options = options
        self.path_spec = path_spec
        wx.Dialog.__init__( self, parent, ID, title, size=(600,600) )
        sizer1 = wx.BoxSizer( wx.VERTICAL )
        self.log = wx.TextCtrl( self, size=(800,800), style =
wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL )
        sizer1.Add( self.log, 1, wx.EXPAND, 0 )
        self.SetSizer( sizer1 )
        sizer1.Fit( self )
        self.Bind(EVT_UPDATE_LOG_COMMAND_EVENT, self.OnUpdateLog)

    def OnUpdateLog(self, event):
        message = event.status
        peer = event.peer
        #self.log.WriteText(event.status + "\n")
        wx.CallAfter(self.log.WriteText, message + "\n" )
        #peer.textctrl.flush()

    def OnShowExecutor(self, logLevel):
        format_str = "[%(levelname)s] %(message)s"
        logging.basicConfig( level=logLevel, format=format_str )
        self.logger = logging.getLogger()
        self.logger.setLevel(logLevel)
        redir = Redirect(self.log)
        sys.stdout = redir
        sys.stderr = redir
        logger_stream_handler = LoggingRedirectHandler(self)
        self.logger.addHandler( logger_stream_handler )

With this code if I start moving the dialog where the log messages are
going, the GUI freezes.

Am I missing wx.Yield() call somewhere?
Also, I'd like to use Redirect class as well. Can I send the same
event from its write() method?

Thank you.

On Sun, Jun 15, 2014 at 3:00 AM, Werner <wernerfbd@gmx.ch> wrote:

On 6/15/2014 11:27, Igor Korot wrote:

Werner,
One more thing:

class LoggingRedirectHandler(logging.StreamHandler):
         def __init__(self,dialog):
                 logging.StreamHandler.__init__( self )
                 self.textctrl = dialog

         def emit(self, record):
                 msg = self.format( record )
                 stream = self.stream
                 frame = wx.GetTopLevelParent()
                 evt = updateLog(status=msg,peer=self)
                 wx.PostEvent(frame.GetEventHandler(), evt)
                 #wx.CallAfter(self.textctrl.WriteText, msg + "\n" )
                 #self.flush
                 #wx.Yield()

The code crashes on the wx.GetTopLevelParent().
What is the best way to get the main frame window? I don't use MDI and
the code crashes even on:

wx.GetApp().GetMainFrame()

wx.GetApp().GetTopWindow() , but you need to do SetTopWindow in your OnInit

Werner

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Hi Igor,

···

On 6/17/2014 7:32, Igor Korot wrote:

Anybody?
It still frezes and I have no clue where and what I'm doing wrong...

No idea, but have you looked at:
http://wiki.wxpython.org/LongRunningTasks

Werner

Hi, Werner,

Hi Igor,

Anybody?
It still frezes and I have no clue where and what I'm doing wrong...

No idea, but have you looked at:
LongRunningTasks - wxPyWiki

No, I didn't.
But today I looked more closely at the code in the section:
"Redirecting text from stdout to wx.TextCtrl".

What happen in my case is this:

I have wx.Wizard based dialog which after completion starts a
DOS-based script on which I don't have any control.
It's been developed by someone else and right now it is frozen for development.
This script spawns couple of python threads which produce some logging
messages and some debug messages/errors.

Now it used to be that when the wx.Wizard is finished my GUI starts
the wx.Progress dialog and starts running that external script in
background. AFAIU, progress dialog is itself run on the different
thread and it calls wx.Yield to let the GUI process messages.
Now, my GUI is getting rid of the progress dialog and instead we want
the logging be put in text control which is shown inside wx.Dialog.
The redirection of the messages works fine. The problem comes from the
fact that somewhere in the middle of the processing of that DOS-based
script' thread the GUI freezes. Text control is not updated and no GUI
events are processed.

The old code was like this:

def menu_create_file(self, event):
     wizard = MyWizard(self)
     if wizard.run():
         options = wizard.options
     else:
          return
     self.statusBar.SetStatusText("Creating File...",0)
     def after_completion(args):
          self.progressDialog.Destroy()
          if args:
               #we have an error. Report it to the user
         else:
               #display successful message
     def run_creation(args):
          #set the parameters and call the external script
     self.progressDialog = wx.ProgressDialog()
     self.progressDialog.Pulse()
     self.progressDialog.Show(true)
     self.worker = WorkerThread(self, run_creation, None, after_completion)

where WorkerThread is a simple wrapper around the python Thread class
(not the wx.Thread).

Now what I did is this:

class Executor(wx.Dialog):
    #this class is to display the dialog with the text control logger
and start the external process
    def __init__(self, parent, id, title):
         #create text control and bind the update log event
    def OnShowExecutor(self, logLevel):
         #redirect logging
         try:
              self.Show()
              #set the parameters and call external script
        except Exception as e:
               print e

def menu_create_file(self, event):
     wizard = MyWizard(self)
     if wizard.run():
         options = wizard.options
     else:
          return
     self.statusBar.SetStatusText("Creating File...",0)
     def after_completion(args):
          self.dlg.Destroy()
          if args:
               #we have an error. Report it to the user
         else:
               #display successful message
     def run_creation(args):
          self.dlg = Executor(self,-1, "my_title", options)
          self.dlg.OnShowExecutor()
     self.worker = WorkerThread(self, run_creation, None, after_completion)

And this new code, while successfully perform logging freezes the GUI part.
Now as I said before I don't have control over the base script - the
one that my GUI starts after the wizard.

As far as I can tell I'm missing a simple call to wx.Yield() to let
the system process GUI messages.
I just don't know where to put it.

The pseudo-code I put in here is from the wx.Frame based class (TLW).

Does anybody sees any issues with what I'm trying to do?

Thank you.

···

On Mon, Jun 16, 2014 at 11:15 PM, Werner <wernerfbd@gmx.ch> wrote:

On 6/17/2014 7:32, Igor Korot wrote:

Werner

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Hi, Werner,
Moreover trying to implement the code on the link you referenced gave
C++ exception: Timer running not on the main thread,
which is correct, seeing that I have wx.Frame, which bring the logging
dialog window.I can probably create a text control inside my main
frame, but my main application is AUI based and I have no big
experience with AUI.
Besides the setup I'm using should work.

Any idea? Or maybe you can spot a flaw in my code?

Thank you.

···

On Wed, Jun 18, 2014 at 3:12 AM, Igor Korot <ikorot01@gmail.com> wrote:

Hi, Werner,

On Mon, Jun 16, 2014 at 11:15 PM, Werner <wernerfbd@gmx.ch> wrote:

Hi Igor,

On 6/17/2014 7:32, Igor Korot wrote:

Anybody?
It still frezes and I have no clue where and what I'm doing wrong...

No idea, but have you looked at:
LongRunningTasks - wxPyWiki

No, I didn't.
But today I looked more closely at the code in the section:
"Redirecting text from stdout to wx.TextCtrl".

What happen in my case is this:

I have wx.Wizard based dialog which after completion starts a
DOS-based script on which I don't have any control.
It's been developed by someone else and right now it is frozen for development.
This script spawns couple of python threads which produce some logging
messages and some debug messages/errors.

Now it used to be that when the wx.Wizard is finished my GUI starts
the wx.Progress dialog and starts running that external script in
background. AFAIU, progress dialog is itself run on the different
thread and it calls wx.Yield to let the GUI process messages.
Now, my GUI is getting rid of the progress dialog and instead we want
the logging be put in text control which is shown inside wx.Dialog.
The redirection of the messages works fine. The problem comes from the
fact that somewhere in the middle of the processing of that DOS-based
script' thread the GUI freezes. Text control is not updated and no GUI
events are processed.

The old code was like this:

def menu_create_file(self, event):
     wizard = MyWizard(self)
     if wizard.run():
         options = wizard.options
     else:
          return
     self.statusBar.SetStatusText("Creating File...",0)
     def after_completion(args):
          self.progressDialog.Destroy()
          if args:
               #we have an error. Report it to the user
         else:
               #display successful message
     def run_creation(args):
          #set the parameters and call the external script
     self.progressDialog = wx.ProgressDialog()
     self.progressDialog.Pulse()
     self.progressDialog.Show(true)
     self.worker = WorkerThread(self, run_creation, None, after_completion)

where WorkerThread is a simple wrapper around the python Thread class
(not the wx.Thread).

Now what I did is this:

class Executor(wx.Dialog):
    #this class is to display the dialog with the text control logger
and start the external process
    def __init__(self, parent, id, title):
         #create text control and bind the update log event
    def OnShowExecutor(self, logLevel):
         #redirect logging
         try:
              self.Show()
              #set the parameters and call external script
        except Exception as e:
               print e

def menu_create_file(self, event):
     wizard = MyWizard(self)
     if wizard.run():
         options = wizard.options
     else:
          return
     self.statusBar.SetStatusText("Creating File...",0)
     def after_completion(args):
          self.dlg.Destroy()
          if args:
               #we have an error. Report it to the user
         else:
               #display successful message
     def run_creation(args):
          self.dlg = Executor(self,-1, "my_title", options)
          self.dlg.OnShowExecutor()
     self.worker = WorkerThread(self, run_creation, None, after_completion)

And this new code, while successfully perform logging freezes the GUI part.
Now as I said before I don't have control over the base script - the
one that my GUI starts after the wizard.

As far as I can tell I'm missing a simple call to wx.Yield() to let
the system process GUI messages.
I just don't know where to put it.

The pseudo-code I put in here is from the wx.Frame based class (TLW).

Does anybody sees any issues with what I'm trying to do?

Thank you.

Werner

--
You received this message because you are subscribed to the Google Groups
"wxPython-users" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to wxpython-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Hi Igor,

···

On 6/19/2014 11:21, Igor Korot wrote:

Hi, Werner,
Moreover trying to implement the code on the link you referenced gave
C++ exception: Timer running not on the main thread,
which is correct, seeing that I have wx.Frame, which bring the logging
dialog window.I can probably create a text control inside my main
frame, but my main application is AUI based and I have no big
experience with AUI.
Besides the setup I'm using should work.

Any idea? Or maybe you can spot a flaw in my code?

I had looked at the code you posted and I don't see a flaw, BUT I have no experience with threading.

Maybe it is time to do a stand alone app which is as close as possible to your real app and try to isolate what is really causing the problem. Is it maybe an issue with reading stdout or with logging or ......?

Werner