Is there some sort of printing buffer that overflows, when WriteText (AppendText, SetLabel, etc.) continuously in wxPython?

StackOverflow https://stackoverflow.com/questions/23449701

  •  14-07-2023
  •  | 
  •  

Question

I have some text that goes somewhat continuously on the output (somewhat = every two seconds approx in the real application).

When just print into the terminal, everything is ok, no matter how long I keep the running loop.

However, when directing the print to a wx frame, the print action itself goes well, no problem here, but if I keep the running loop more than 10-20 cycles, I am no longer able to close the window normally (mouse or Ctrl+F4 in this example, but the same if I construct an explicit Exit event menu). The action in thread stops, but the application hangs -- it can only be closed by the OS (Windows in my case) with a "force close / wait for the program to respond" dialog. Though, it can be closed immediately with Ctrl+C when the terminal window is on focus. It looks like something fills up with too much text and locks the closing process.

Happens with either WriteText or AppendText on a multiline wxTextCtrl window, or with the SetLabel as in the test code below.

In this test, if I close the wx window almost immediately after launch, it closes well. If I keep running the loop longer (or by comment out the two time.sleep() lines), then the hang will succeed whenever trying to close the window.

What am I missing here ? (Is there something I have to flush ?)

edit Hmm, the issue could be related to "threadsafe method", as described briefly here. Will do some tests in that direction, have to find out the proper usage of each of the wx.CallAfter, wx.CallLater or wx.PostEvent.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import wx
import time
import threading

class TestFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.sometext = wx.TextCtrl(self, wx.ID_ANY, "", style=wx.TE_READONLY)
        self.thread = None
        self.alive = threading.Event()
        self.__set_properties()
        self.__do_layout()
        self.__attach_events()
        self.StartThread()

    def __set_properties(self):
        self.SetTitle("test")

    def __do_layout(self):
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.sometext, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL, 0)
        self.SetSizer(sizer)
        sizer.Fit(self)
        self.Layout()

    def __attach_events(self):
        self.Bind(wx.EVT_CLOSE, self.OnClose)

    def OnClose(self, event):
        """ stop & close on system window close """
        self.StopThread()
        self.Destroy()

    def StartThread(self):
        """ start the thread """
        self.thread = threading.Thread(target=self.TestThread)
        self.thread.setDaemon(1)
        self.alive.set()
        self.thread.start()

    def StopThread(self):
        """ stop the thread, wait util it is finished """
        if self.thread is not None:
            self.alive.clear()
            self.thread.join()
            self.thread = None

    def TestThread(self):
        """ main thread """
        while self.alive.isSet():
            self.sometext.SetLabel("Hello")
            time.sleep(0.5)
            self.sometext.SetLabel("Python")
            time.sleep(0.5)

class MyApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
        frame = TestFrame(None, -1, "")
        self.SetTopWindow(frame)
        frame.Show(1)
        return 1

if __name__ == "__main__":

    app = MyApp(0)
    app.MainLoop()
Was it helpful?

Solution

I've changed every SetLabal with AppendtText. I'm don't know why, but SetLabel function don't work correctly for me.

After a few seconds the application will stop working. This is my error output:

(python:14099): Pango-CRITICAL **: pango_layout_get_iter: assertion 'PANGO_IS_LAYOUT (layout)' failed
Segmentation fault

After that I used CallAfter function http://wiki.wxpython.org/CallAfter the application started correctly working for me. My version of TestThread:

def TestThread(self):
        """ main thread """
        while self.alive.isSet():
            wx.CallAfter(self.sometext.AppendText, "Hello")
            time.sleep(0.5)
        wx.CallAfter(self.sometext.AppendText, "Python") 
        time.sleep(0.5)
        wx.CallAfter(self.sometext.Clear)

I hope this help you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top