Attempts to change wx.StatusBar.BackgroundColour

I am attempting to change the background colour of a statusbar without much success.

I thought I followed the examples I’ve seen all over the web on how to do this, to no avail.

I’m using:

  • Python 2.7
  • Microsoft Windows XP Pro SP3 32 bit
  • wxPython 2.8.11.0 (msw-unicode)
    Code like:

self.sb = self.CreateStatusBar()

self.sb.SetBackgroundColour(‘RED’)

mycolor = self.sb.GetBackgroundColour()

print(“mycolor: %s” % mycolor) # prints out wx.Color() version of “RED”

self.Refresh()

This will change the self.sb.BackGroundColour attribute to “RED” but doesn’t

seem to show red visually on the window frame.

A test app showing my code is attached. I appreciate any direction to a solution

anyone is willing to share.

fixsbc.py (3.11 KB)

In an attempt to find a working example for my statusbar color problem
I found something on the wxPyWiki.

However the certain section of example code on the wxPyWiki does not
clearly work without modification, nor for what I need to learn from
it. See
http://wiki.wxpython.org/AnotherTutorial

The section about 80% the way down the wiki page labelled:
" Error handling without dialogs "

There is no "self.Show()" at the end of Isabella.__init__() or after
app = wx.App(). There is no "class MyApp(wx.App):" used in this
example. There is no Show() called for that frame I can see. Therefore
the main frame portrade below the example doesn't show as running the
example code proves (on my machine).

Also the text after the source code incorrectly states "There is
awx.TextCtrl on the Statusbar." I believe it means to say "There is a
wx.TextCtrl on the toolbar."

In the following discussion it shows a code snippet "self.timer =
wx.Timer(self, 1)" which is not in the Isabella.py example code. I
think the author means to say "self.timer = wx.Timer(self, ID_TIMER)".
Although ID_TIMER = 1, a novice coping this code could spend some
unnecessary time debugging it if she changed the ID_TIMER to a
different value and think the "1" represents "1 second" instead.

I think The next code snippet "wx.EVT_TIMER(self, 1, self.OnTimer)"
in the discussion is meant to represent the line
"self.Bind(wx.EVT_TIMER, self.OnTimer, id=ID_TIMER)" in the
Isebella.py example code. A novice may not know they are near
equivelent. Not everyone will have read those notes that they are
equivalent.

Adding the self.Show() to the end of the Isabella.__init__() makes the
frame show and the demo app to -mostly- work. I'm using Python 2.7,
wxPython 2.8.11.0, MSW-XP Pro-32bit. The statusbar does not turn red
when I run the modificed Isabella.py example.

I don't feel versed enough to mess with wiki pages, nor do I wish to
login to the wiki with my real name (yet), and "TheRules" of the wiki
ruling want that.

If anyone knows a fix to getting the statusbar to change color for the
Isebella.py example please let me know.

[alm>]
I, too, asked this question recently and the answer is 'no'.
I also looked at the demo and that Isabelle thing. Isabelle seems to be old
and may have worked at one time but not now or not for me. A message will
appear but no color. I think what's happening there is the frame's built-in
minimal statusbar support.

The attached files are what I came up with. These are 2 of 18 files of the
app I've been working on so don't expect it to just work.

amain.py is the main app file. Copy stuff from there to your app; get
everything 'statusbar' related.
astat.py has a wx.StatusBar sub-class. Import this file/module into your app
main.

Once everything is in and working you can do something like this to put a
message on the status bar:

         wx.GetApp().status_msg( "Money fields may only have one '.'!", 1 )

It will vanish in about 3 seconds, see TIMER_EXPIRE.

I've attached an example screen shot for the status_msg call with
severity=1.

I may not be finished with astat.py and so I've left commented code there
for the other statusbar fields and some of the isabelle and demo code that
didn't work or I don't need yet.

Al

amain.py (7.33 KB)

astat.py (5.26 KB)

···

-----Original Message-----
From: wxpython-users@googlegroups.com [mailto:wxpython-
users@googlegroups.com] On Behalf Of DevPlayer
Sent: Monday, August 16, 2010 7:31 PM
To: wxPython-users
Subject: [wxPython-users] Re: Attempts to change
wx.StatusBar.BackgroundColour

In an attempt to find a working example for my statusbar color problem
I found something on the wxPyWiki.

However the certain section of example code on the wxPyWiki does not
clearly work without modification, nor for what I need to learn from
it. See
http://wiki.wxpython.org/AnotherTutorial

The section about 80% the way down the wiki page labelled:
" Error handling without dialogs "

There is no "self.Show()" at the end of Isabella.__init__() or after
app = wx.App(). There is no "class MyApp(wx.App):" used in this
example. There is no Show() called for that frame I can see. Therefore
the main frame portrade below the example doesn't show as running the
example code proves (on my machine).

Also the text after the source code incorrectly states "There is
awx.TextCtrl on the Statusbar." I believe it means to say "There is a
wx.TextCtrl on the toolbar."

In the following discussion it shows a code snippet "self.timer =
wx.Timer(self, 1)" which is not in the Isabella.py example code. I
think the author means to say "self.timer = wx.Timer(self, ID_TIMER)".
Although ID_TIMER = 1, a novice coping this code could spend some
unnecessary time debugging it if she changed the ID_TIMER to a
different value and think the "1" represents "1 second" instead.

I think The next code snippet "wx.EVT_TIMER(self, 1, self.OnTimer)"
in the discussion is meant to represent the line
"self.Bind(wx.EVT_TIMER, self.OnTimer, id=ID_TIMER)" in the
Isebella.py example code. A novice may not know they are near
equivelent. Not everyone will have read those notes that they are
equivalent.

Adding the self.Show() to the end of the Isabella.__init__() makes the
frame show and the demo app to -mostly- work. I'm using Python 2.7,
wxPython 2.8.11.0, MSW-XP Pro-32bit. The statusbar does not turn red
when I run the modificed Isabella.py example.

I don't feel versed enough to mess with wiki pages, nor do I wish to
login to the wiki with my real name (yet), and "TheRules" of the wiki
ruling want that.

If anyone knows a fix to getting the statusbar to change color for the
Isebella.py example please let me know.

--
To unsubscribe, send email to wxPython-
users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

You might give the EnhancedStatusBar a try:

http://xoomer.virgilio.it/infinity77/main/EnhancedStatusBar.html

I'm not sure if this is included with the latest wxPython now or
not...but you can always download it from that link if not.

···

On Aug 16, 10:21 pm, "Al Mansur" <alman...@rusnam.org> wrote:

> -----Original Message-----
> From: wxpython-users@googlegroups.com [mailto:wxpython-
> users@googlegroups.com] On Behalf Of DevPlayer
> Sent: Monday, August 16, 2010 7:31 PM
> To: wxPython-users
> Subject: [wxPython-users] Re: Attempts to change
> wx.StatusBar.BackgroundColour

> In an attempt to find a working example for my statusbar color problem
> I found something on the wxPyWiki.

> However the certain section of example code on the wxPyWiki does not
> clearly work without modification, nor for what I need to learn from
> it. See
>http://wiki.wxpython.org/AnotherTutorial

> The section about 80% the way down the wiki page labelled:
> " Error handling without dialogs "

> There is no "self.Show()" at the end of Isabella.__init__() or after
> app = wx.App(). There is no "class MyApp(wx.App):" used in this
> example. There is no Show() called for that frame I can see. Therefore
> the main frame portrade below the example doesn't show as running the
> example code proves (on my machine).

> Also the text after the source code incorrectly states "There is
> awx.TextCtrl on the Statusbar." I believe it means to say "There is a
> wx.TextCtrl on the toolbar."

> In the following discussion it shows a code snippet "self.timer =
> wx.Timer(self, 1)" which is not in the Isabella.py example code. I
> think the author means to say "self.timer = wx.Timer(self, ID_TIMER)".
> Although ID_TIMER = 1, a novice coping this code could spend some
> unnecessary time debugging it if she changed the ID_TIMER to a
> different value and think the "1" represents "1 second" instead.

> I think The next code snippet "wx.EVT_TIMER(self, 1, self.OnTimer)"
> in the discussion is meant to represent the line
> "self.Bind(wx.EVT_TIMER, self.OnTimer, id=ID_TIMER)" in the
> Isebella.py example code. A novice may not know they are near
> equivelent. Not everyone will have read those notes that they are
> equivalent.

> Adding the self.Show() to the end of the Isabella.__init__() makes the
> frame show and the demo app to -mostly- work. I'm using Python 2.7,
> wxPython 2.8.11.0, MSW-XP Pro-32bit. The statusbar does not turn red
> when I run the modificed Isabella.py example.

> I don't feel versed enough to mess with wiki pages, nor do I wish to
> login to the wiki with my real name (yet), and "TheRules" of the wiki
> ruling want that.

> If anyone knows a fix to getting the statusbar to change color for the
> Isebella.py example please let me know.

> --
> To unsubscribe, send email to wxPython-
> users+unsubscribe@googlegroups.com
> or visithttp://groups.google.com/group/wxPython-users?hl=en

[alm>]
I, too, asked this question recently and the answer is 'no'.
I also looked at the demo and that Isabelle thing. Isabelle seems to be old
and may have worked at one time but not now or not for me. A message will
appear but no color. I think what's happening there is the frame's built-in
minimal statusbar support.

The attached files are what I came up with. These are 2 of 18 files of the
app I've been working on so don't expect it to just work.

amain.py is the main app file. Copy stuff from there to your app; get
everything 'statusbar' related.
astat.py has a wx.StatusBar sub-class. Import this file/module into your app
main.

Once everything is in and working you can do something like this to put a
message on the status bar:

     wx\.GetApp\(\)\.status\_msg\( &quot;Money fields may only have one &#39;\.&#39;\!&quot;, 1 \)

It will vanish in about 3 seconds, see TIMER_EXPIRE.

I've attached an example screen shot for the status_msg call with
severity=1.

I may not be finished with astat.py and so I've left commented code there
for the other statusbar fields and some of the isabelle and demo code that
didn't work or I don't need yet.

Al

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

Since Windows XP (if I remember correctly) the native status bar widget on windows has ignored the color change messages. That is the cost we pay for having native widgets, sometimes they want to do their own thing in unexpected ways.

···

On 8/16/10 4:11 PM, Dev Player wrote:

I am attempting to change the background colour of a statusbar without
much success.
I thought I followed the examples I've seen all over the web on how to
do this, to no avail.
I'm using:

    * Python 2.7
    * Microsoft Windows XP Pro SP3 32 bit
    * wxPython 2.8.11.0 (msw-unicode)

Code like:

    self.sb = self.CreateStatusBar()
    self.sb.SetBackgroundColour('RED')
    mycolor = self.sb.GetBackgroundColour()
    print("mycolor: %s" % mycolor) # prints out wx.Color() version
    of "RED"
    self.Refresh()

This will change the self.sb.BackGroundColour attribute to "RED" but doesn't
seem to show red visually on the window frame.
A test app showing my code is attached. I appreciate any direction to a
solution
anyone is willing to share.

--
Robin Dunn
Software Craftsman

Thanks Al for showing your code. I will make a custom status bar like
yours or the wxPython Custom Statusbar which I think does allow the
second field that changes with the SetBackgroundColour() call.

I like the stuff from the inifinity77 website Mike. Thanks for the
link. I'll take a look at it.

I agree Robin, native widgets can cost in flexability. I got confused
thinking the SetBackgroundColour() was a member method of the
wx.StatusBar object when I imported wx in PythonWin. When I type
"wx.StatusBar." in the interactive window there is shows that method
as a member. So I thought it was there on purpose (and thought it
therefore would work) and forgot about unintended inheritence from
it's parent.

···

---
I am hoping someone will make the wxPyWiki "Error handling without
dialogs" demo show a different control for color other then the
statusbar. I would if I was versed in wiki editing and if I wanted to
log into the wiki with my real name, which I don't at this time.
---

Ray, Thanks for the tip with wx.PaintDC. I saw some examples from
Robin in other forums for other controls with (seemingly) same issue I
encounted. One offered method was to overright the OnPaint - I think,
of the control. How to do that without subclassing I don't know.

Steven thanks for bringing up the point on how to keep usergroup/
newsgroup threads clean.

The code I attached in my first post of this topic was my cleaned
version. In my "dirty" debug version I was trying all sorts of things
to try to force the statusbar to change color.

In my dirty version of that fixsbc.py I did notice a few things.

1. In wxPyWiki's AnotherTutorial Isebella.py, the code used
sb=self.CreateStatusBar().
Looking at the wiki docs I thought I read CreateStatusBar() uses the
DEFAULT_STATUSBAR_STYLE or some such flag.
Remembering back to my WinSDK days back when Windows ME was big, a
select few window styles would set the extended windows styles flags
too. What they're called I don't know. But these extended windows
flags where only modifyable at creation of the window.

2. I notice that my instance of the wx.StatusBar has a
wx.StatusBar.InheritsBackgroundColour() which returned True.

3. When I put a sb.ClearBackground() in one of my fixsbc.py
OnHitPanelBlue() methods and clicked really really fasted on the
button associated with that specific OnHitPanelBlue() for a faction of
a second the statusbar was painted red, and then repained with the
default system color of status bars of gray again.

4. I read somewhere that I could intercept or respond to a
EVT_SYSTEM_CHANGE_COLOR (of something with similar name) event and
make it work with the PaintDC method mentioned before by Ray.

5. After I do self.CreateStatusBar() I did x = sb.GetFieldsCount()
which equals zero, not one. Yet I can do sb.SetStatusText("Run Away!")
as if a field count of zero means really one "main" field. I presume
this "main" field to be a textctrl. And that this textctrl is an added
level of tricky in working around this statusbar color issue.

6. And finally that wx.controls inherits things differently then wx.
(non)controls, or native widgets as Robin says.

Therefore it looks like trying to code changing the native statusbar
color is more work then just making a new frame or panel that sits at
the bottom of the window frame and behaves/pretends to be like a
statusbar. I think the intention of the native statusbar is to reserve
system resources.

Well, that's a lot of chatter for a small visual effect huh.

Thanks all.

"Therefore it looks like trying to code changing the native statusbar
color is more work then just making a new frame or panel that sits
at the bottom of the window frame and behaves/pretends to be like
a statusbar."

But, This *IS* the way the wx.StatusBar is created in the underlying
C++ WxWidgets ! Nearly every control is a subclassed wx.Window
with added features, including the wx.StatusBar. They main point of
subclassing is to take a control and add features to it, or at least
set defaults for the existing features. What I'm calling "features"
are predefined methods and class variables.

Many controls have been developed using pure wxPython+Python
because they don't happen to be available in the wxWidgets C++
code. It doesn't matter whether a control has been subclassed in
the C++ wxWidget's code or using wxPython code - the new
control. "If it looks like a duck, walks like a duck and sounds like
a duck, then it MUST be a duck" !

The point of all this is that if a control doesn't have the features
you want then subclassing a similar control to add or change it
to exactly what you want it to be is the normal-usual-expected
way to do this. Just about any control can be hand-crafted with
just wxPython using just the wx.Window and the wx.StaticText
primitives.

So, merely colorizing the wx.StatusBar is about the simplest
subclassing example there is. Why "re-invent the wheel" to
create your own statusbar the "behaves/pretends" to be a
wx.StatusBar (an example of a "duck") ? That has already
been done for you. All you really need to do is subclass the
wx.StatusBar and change the .BackgroundColour !

Recreating the wx.StatusBar with all its "bells and whistles"
from scratch is a big task, but it certainly can be done in
wxPython. But, that would be totally pointless.

Ray

"Therefore it looks like trying to code changing the native statusbar
color is more work then just making a new frame or panel that sits
at the bottom of the window frame and behaves/pretends to be like
a statusbar."

But, This *IS* the way the wx.StatusBar is created in the underlying
C++ WxWidgets ! Nearly every control is a subclassed wx.Window
with added features, including the wx.StatusBar. They main point of
subclassing is to take a control and add features to it, or at least
set defaults for the existing features. What I'm calling "features"
are predefined methods and class variables.

When dealing with native controls there is another aspect to the picture other than just class inheritance. These classes also have a handle to a native window, and what is being inherited for something like SetBackgroundColour() is simply code that will send a standard message to that window handle. It is entirely up to the entity behind that handle what it will do with the message. It can accept it, reject it, or ignore it. In this case the native statusbar control is either ignoring the message or (more likely) it is simply not using the set background colour when it paints itself.

Many controls have been developed using pure wxPython+Python
because they don't happen to be available in the wxWidgets C++
code. It doesn't matter whether a control has been subclassed in
the C++ wxWidget's code or using wxPython code - the new
control. "If it looks like a duck, walks like a duck and sounds like
a duck, then it MUST be a duck" !

Except when it's a deaf duck and doesn't hear the messages being shouted at it. :wink: Actually your analogy still fits, but in this case it is not the "set the background color" feature that is being inherited, but rather it is simply the ability to ask the widget "Please sir, if you don't mind, will you please use color C when you draw yourself?"

Custom widgets written in Python code could easily have the same problem if their EVT_PAINT handler does not use GetBackgroundColour when painting. The users of that class could call SetBackgroundColour all they want and the widget will never paint itself with that color because it is ignoring the color set by the user of the class.

···

On 8/18/10 10:53 AM, WinCrazy wrote:

--
Robin Dunn
Software Craftsman

Although some have already given solutions: exploring the points being
made.

> "Therefore it looks like trying to code changing the native statusbar
> color is more work then just making a new frame or panel that sits
> at the bottom of the window frame and behaves/pretends to be like
> a statusbar."

> But, This *IS* the way the wx.StatusBar is created in the underlying
> C++ WxWidgets ! Nearly every control is a subclassed wx.Window
> with added features, including the wx.StatusBar. They main point of
> subclassing is to take a control and add features to it, or at least
> set defaults for the existing features. What I'm calling "features"
> are predefined methods and class variables.

When dealing with native controls there is another aspect to the picture
other than just class inheritance. These classes also have a handle to
a native window, and what is being inherited for something like
SetBackgroundColour() is simply code that will send a standard message
to that window handle. It is entirely up to the entity behind that
handle what it will do with the message. It can accept it, reject it,
or ignore it.

In this case the native statusbar control is either
ignoring the message or (more likely) it is simply not using the set
background colour when it paints itself.

Working out a proper solution to this, would there be any difference
if the wx.statusbar widget explicidly rejects the event or usage of
the color attribute verse ignores the event or usage of the color
attribute?

I assume if the wx.Statusbar just ignores it or there is some event it
doesn't capture or that there is an omitted method from its MS native
class then the best solution would be to add that method to a
subclass.

If the native Statusbar widget explicidly rejects the event or color
attributes or prevents replacing the native-widget-method-that-handles-
color changes with a subclass method (I don't know if this is even
possible for a native widget to override any subclass's method) then
what?

I know, my lack of programming/windows fundamentals shows here.

> Many controls have been developed using pure wxPython+Python
> because they don't happen to be available in the wxWidgets C++
> code. It doesn't matter whether a control has been subclassed in
> the C++ wxWidget's code or using wxPython code - the new
> control. "If it looks like a duck, walks like a duck and sounds like
> a duck, then it MUST be a duck" !

Except when it's a deaf duck and doesn't hear the messages being shouted
at it. :wink: Actually your analogy still fits, but in this case it is
not the "set the background color" feature that is being inherited, but
rather it is simply the ability to ask the widget "Please sir, if you
don't mind, will you please use color C when you draw yourself?"

Custom widgets written in Python code could easily have the same problem
if their EVT_PAINT handler does not use GetBackgroundColour when
painting. The users of that class could call SetBackgroundColour all
they want and the widget will never paint itself with that color because
it is ignoring the color set by the user of the class.

So partially understanding the problem but not fully understanding the
implied solution, will subclassing the wx.StatusBar solve the problem?
And the real question is which part in the subclass is the missing
part from the native widget?

What method is missing or can be overloaded or which event is not
getting processed in the native statusbar widget that other native
widgets do have to allow them to change colors?

something like this work?

class my.StatusBar(wx.StatusBar):
    def __init__(self):
         bla bla
         self.Bind(wx.EVT_PAINT, self.OnSetBackground)
   def OnSetBackgroundColor(self, evt): << --??
         self.InvalidateRect(self.ClientRect()) # or
something
         self.DoPaint(evt.color) # or something??

I assume if the wx.Statusbar just ignores it or there is some event it
doesn't capture or that there is an omitted method from its MS native
class then the best solution would be to add that method to a
subclass.

Like I said before, my assumption is that the native statusbar's WM_PAINT handler simply does not do the equivalent of self.GetBackgroundColour() when it paints itself.

So partially understanding the problem but not fully understanding the
implied solution, will subclassing the wx.StatusBar solve the problem?

Depends on what you mean by "solve" :wink: You can't force the native widget's paint handler to use the background color, I expect that if it could use the background color that it would be already.

Officially wx does not support overriding the native paint (and some others) handler for the native controls, but on Windows it should work most of the time. So if you derive a class from wx.Statusbar and bind the wx.EVT_PAINT event, then you can then *totally reimplement* the drawing of the statusbar however you want.

And the real question is which part in the subclass is the missing
part from the native widget?

Strictly speaking, nothing is missing. The wrapping of the native widget is what it is: a wrapper of some native functionality. If that functionality does not use a set background color then making it do it or work around it somehow means that it is no longer the native look and feel.

···

On 8/31/10 11:07 AM, DevPlayer wrote:

--
Robin Dunn
Software Craftsman