0

I am outputting the stderr to a wx.TextCtrl, after 10 lines I want to delete the first line so there is only ever a maximum of 10 lines in my wx.TextCtrl window. I have a python script which is using multiple threads and classes. I just can't for the life of me get the below bit of code to work, can someone give me a few hints please?

a = 1
while True:
    line = self.process1.stderr.readline().decode('utf-8')
    wx.CallAfter(self.frame.running_log1.AppendText, line)
    if a >= 10:
        s = wx.CallAfter(self.frame.running_log1.GetLineLength, 0) +1
        wx.CallAfter(self.frame.running_log1.Remove, 0, s)
        print s
    a +=1

When run s = None, so fails. I am using wx.CallAfter as I am using threads.

speedyrazor
  • 3,127
  • 7
  • 33
  • 51
  • Did you try to use other function - for example function with `print` to see result in console. – furas Jun 29 '14 at 02:09
  • s = None, so fails. No idea why though? – speedyrazor Jun 29 '14 at 14:33
  • Did you check in doc whether `wx.CallAfter()` returns something. I think `wx.CallAfter()` can't return anything. – furas Jun 29 '14 at 15:01
  • Maybe you could run in `wx.CallAfter()` own function with `GetLineLength` and `Remove`. Or maybe you coud use `lambda` to create that function in-place. `wx.CallAfter( lambda: self.frame.running_log1.Remove(0, self.frame.running_log1.GetLineLength(0)+1) )` – furas Jun 29 '14 at 15:17

1 Answers1

1

The reason wx.CallAfter returns None is because there isn't anything to return at that point. It can't return the length, because all it has done is made a note that at some point soon it needs to call the function. It hasn't actually called the function, and won't wait until the function has been called.

In this situation I would write a method that would append a line and remove the first line as necessary. This might look something like:

    def appendAndTrim(self, line):
        self.frame.running_log1.AppendText(line)
        self.line_count += 1
        if self.line_count > 10:
            first_line_length = self.frame.running_log1.GetLineLength(0) + 1
            self.frame.running_log1.Remove(0, first_line_length)

I would then pass this single method to wx.CallAfter, rather than making three separate calls to wx.CallAfter:

self.line_count = 0
while True:
    line = self.process1.stderr.readline().decode('utf-8')
    wx.CallAfter(self.appendAndTrim, line)
Luke Woodward
  • 63,336
  • 16
  • 89
  • 104
  • Excellent answer and description, I slightly modified it for my situation. Cheers. – speedyrazor Jun 29 '14 at 16:42
  • The only issue with this approach is that in Windows when the .Remove command runs and deletes the top line the wx.TextCtrl window jumps to the top, so if it is writing to the bottom and then deleting from the top, the window is constantly jumping from top to bottom to top, etc, not very pleasing visually. Any way to prevent this? – speedyrazor Jun 30 '14 at 12:37
  • @speedyrazor: does it make a difference if you remove an old line before adding a new one? – Luke Woodward Jun 30 '14 at 21:32