Reputation: 23535
I'm working on a wxPython GUI for esptool.py i.e. the app will invoke that script. For starters I'd like to redirect the content that esptool.py prints to console to a TextCtrl. I followed a frequently referenced article for that and it works well.
However, I'm currently stuck dealing with the progress monitor that esptool.py prints to console. It prints something like "25%" followed by a number of \b
which immediately erase what was printed, then "26%" which again is erased immediately and so on.
The plan was to parse the string, TextCtrl.AppendText()
everything but the backspace characters and then TextCtrl.Remove()
as many characters as there are backspace characters.
The below code works fine when I step through it with the debugger but it crashes hard when "let loose". There seems to be some timing/threading issue. Apparently I can't call TextCtrl.Remove()
right after TextCtrl.AppendText()
?
class RedirectText:
def __init__(self, textCtrl):
self.out = textCtrl
def write(self, string):
new_string = ""
number_of_backspaces = 0
# this could definitely be improved performance wise...
for c in string:
if c == "\b":
number_of_backspaces += 1
else:
new_string += c
self.out.AppendText(new_string)
if number_of_backspaces > 0:
last_position = self.out.GetLastPosition()
self.out.Remove(last_position - number_of_backspaces, last_position)
def flush(self):
None
The code that calls esptool.py runs in its own thread as to not hog the main UI thread.
This is my first real Python project (and thus the first w/ wxPython of course) and I haven't coded for the desktop in many years. So, it's entirely possible I'm missing something obvious.
Upvotes: 0
Views: 628
Reputation: 23535
For the sake of completeness here's (one of) the solution(s).
Turns out that manipulating the text control with wx.CallAfter
in quick succession isn't too reliable wrt GetLastPosition()
. So, it now just appends the text and remembers how many characters to remove the next time write()
is invoked. It then removes those characters before appending the new text.
class RedirectText:
def __init__(self, text_ctrl):
self.out = text_ctrl
self.pending_backspaces = 0
def write(self, string):
new_string = ""
number_of_backspaces = 0
for c in string:
if c == "\b":
number_of_backspaces += 1
else:
new_string += c
if self.pending_backspaces > 0:
# current value minus pending backspaces plus new string
new_value = self.out.GetValue()[:-1 * self.pending_backspaces] + new_string
wx.CallAfter(self.out.SetValue, new_value)
else:
wx.CallAfter(self.out.AppendText, new_string)
self.pending_backspaces = number_of_backspaces
def flush(self):
None
Upvotes: 2