wx.textCtrl and SetDefaultStyle

I have ran into an issue when trying to color code my text box.

The text box is created with this value

item12 = wx.TextCtrl( parent, ID_logTEXTCTRL, "", wx.DefaultPosition,
[450,300], wx.TE_MULTILINE|wx.TE_READONLY|wx.VSCROLL|wx.HSCROLL|
wx.SIMPLE_BORDER|wx.TE_RICH2)

And then it is changed using this function

wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).SetDefaultStyle(wx.TextAttr("red")))
wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).AppendText,msg)
wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).ScrollLines,
1)

The program properly posts the message to the list box, in the correct
color. pops up with an error, but keeps running.

The error is the following.

File "C:\Python\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py",
line 14618,
in <lambda>
    lambda event: event.callable(*event.args, **event.kw) )
TypeError: 'bool' object is not callable

You can make your code much more readable by using a reference to the
window, either item12 if it is still in scope or by using
self.LogTextCtrl = item12 after creating it, your call after lines then
become:

wx.CallAfter(self.LogTextCtrl.SetDefaultStyle(wx.TextAttr("red")))
wx.CallAfter(self.LogTextCtrl.AppendText, msg)
wx.CallAfter(self.LogTextCtrl.ScrollLines, 1)

and I would think that the problem is that you are using call after in
the first line with an executed statement as the first parameter and the
other lines specify an executable function as the first parameter and
the parameters for that function as the remaining values so try changing
the first line to read:

wx.CallAfter(self.LogTextCtrl.SetDefaultStyle, wx.TextAttr("red"))
or in your style:
wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).SetDefaultStyle,
wx.TextAttr("red"))

Or better get keep a reference to the window and use shorter lines of
code :wink:

Gadget/Steve

···

On 02/09/2011 6:56 AM, adam wrote:

I have ran into an issue when trying to color code my text box.

The text box is created with this value

item12 = wx.TextCtrl( parent, ID_logTEXTCTRL, "", wx.DefaultPosition,
[450,300], wx.TE_MULTILINE|wx.TE_READONLY|wx.VSCROLL|wx.HSCROLL|
wx.SIMPLE_BORDER|wx.TE_RICH2)

And then it is changed using this function

wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).SetDefaultStyle(wx.TextAttr("red")))
wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).AppendText,msg)
wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).ScrollLines,
1)

The program properly posts the message to the list box, in the correct
color. pops up with an error, but keeps running.

The error is the following.

File "C:\Python\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py",
line 14618,
in <lambda>
    lambda event: event.callable(*event.args, **event.kw) )
TypeError: 'bool' object is not callable

That seems to have resolved it. Thank you :slight_smile:

···

On Sep 2, 2:58 am, Gadget/Steve <GadgetSt...@live.co.uk> wrote:

On 02/09/2011 6:56 AM, adam wrote:

> I have ran into an issue when trying to color code my text box.

> The text box is created with this value

> item12 = wx.TextCtrl( parent, ID_logTEXTCTRL, "", wx.DefaultPosition,
> [450,300], wx.TE_MULTILINE|wx.TE_READONLY|wx.VSCROLL|wx.HSCROLL|
> wx.SIMPLE_BORDER|wx.TE_RICH2)

> And then it is changed using this function

> wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).SetDefaul tStyle(wx.TextAttr("red")))
> wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).AppendTex t,msg)
> wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).ScrollLin es,
> 1)

> The program properly posts the message to the list box, in the correct
> color. pops up with an error, but keeps running.

> The error is the following.

> File "C:\Python\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py",
> line 14618,
> in <lambda>
> lambda event: event.callable(*event.args, **event.kw) )
> TypeError: 'bool' object is not callable

You can make your code much more readable by using a reference to the
window, either item12 if it is still in scope or by using
self.LogTextCtrl = item12 after creating it, your call after lines then
become:

wx.CallAfter(self.LogTextCtrl.SetDefaultStyle(wx.TextAttr("red")))
wx.CallAfter(self.LogTextCtrl.AppendText, msg)
wx.CallAfter(self.LogTextCtrl.ScrollLines, 1)

and I would think that the problem is that you are using call after in
the first line with an executed statement as the first parameter and the
other lines specify an executable function as the first parameter and
the parameters for that function as the remaining values so try changing
the first line to read:

wx.CallAfter(self.LogTextCtrl.SetDefaultStyle, wx.TextAttr("red"))
or in your style:
wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).SetDefaul tStyle,
wx.TextAttr("red"))

Or better get keep a reference to the window and use shorter lines of
code :wink:

Gadget/Steve

In other words, you were calling SetDefaultStyle, and then passing its return value (a bool value) to CallAfter, and the error is happening because CallAfter is trying to call the bool as if it was a callable function. By changing it to not do that call to SetDefaultStyle and to pass SetDefaultStyle itself to CallAfter then you are allowing CallAfter to work how it is supposed to.

This seems to be a semi-common mistake that people make. I'll add an assertion to CallAfter to hopefully help people to figure out what they are doing wrong.

BTW, you will be better off if you combine those three statements into a single function, and then just use CallAfter to call that one function. This will not only be more efficient, but also will ensure that the statements are always executed in the same order and that one will not be called before another is finished. Since CallAfter functions are called via events then the next event can be processed before the first one is finished if the first one does something that would allow events to be processed, like triggering another event whose handler does a yield. So to avoid this possibility I would change it to be something like this:

     def doShowErrorMsg(txtCtrl, msg):
         txtCtrl.SetDefaultStyle(wx.TextAttr("red"))
         txtCtrl.AppendText(msg)
         txtCtrl.ScrollLines(1)

...

     wx.CallAfter(doShowErrorMsg,
                  ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL),
                  msg)

···

On 9/1/11 11:58 PM, Gadget/Steve wrote:

On 02/09/2011 6:56 AM, adam wrote:

wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).SetDefaultStyle(wx.TextAttr("red")))
wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).AppendText,msg)
wx.CallAfter(ProgramVars.parentWin.FindWindowById(ID_logTEXTCTRL).ScrollLines,
1)

The program properly posts the message to the list box, in the correct
color. pops up with an error, but keeps running.

The error is the following.

  File "C:\Python\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py",
line 14618,
  in<lambda>
     lambda event: event.callable(*event.args, **event.kw) )
TypeError: 'bool' object is not callable

and I would think that the problem is that you are using call after in
the first line with an executed statement as the first parameter and the
other lines specify an executable function as the first parameter and
the parameters for that function as the remaining values

--
Robin Dunn
Software Craftsman