wxStaticText - transparent backgrounds in XP

BlitzMax Modules Forums/Brucey's Modules/wxStaticText - transparent backgrounds in XP

In OS X wxStaticText labels automatically use a transparent background on textured panels, but this is not the case in XP.

Searching the wxWidgets forum produced this answer

void wxMyDialog::OnPanelHeaderEraseBackground( wxEraseEvent& event )
{
    wxDC* dc = event.GetDC();
    wxRect rect = m_panel_header->GetClientRect();
    dc->GradientFillLinear(rect,wxColour(102,153,102), wxColour(204,255,204),wxEAST);

    wxFont font(12, wxSWISS, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_BOLD, FALSE, wxT("Verdana"));
    dc->SetFont(font);
    dc->SetBackgroundMode(wxTRANSPARENT);
    dc->SetTextForeground(*wxWHITE);
    wxString msg = wxT("Some text");
    dc->DrawText(msg, wxPoint(10, 10));

    m_panel_header->RefreshRect(rect, false);
} 


ie, you override the erase background event and do your own drawing.

Unfortunately, when I check wxEraseEvent, I find no GetDC() - just a commented out bit of code

	Rem
	bbdoc: Returns the device context associated with the erase event to draw on.
	End Rem
'	Method GetDC:_wxDC()
'	End Method


What does this mean Brucey? You haven't implemented it, or we are meant to use another method?

ta!

David

I've moved wxEraseEvent from wx to wxwindow, since it requires wxDC access.

You should be able to catch wxEVT_ERASE_BACKGROUND events now, all being well, etc :-)

Thanks Brucey :-) The event is being caught OK but I'm afraid I'm stuck for a solution.

If anyone's interested in having a tinker - here's a little test bed with pretty much every solution I found online in it - none of which seem to work. Which, interestingly, is what each solution said of the others!

Thanks,

David

SuperStrict

Framework wx.wxApp
Import wx.wxFrame
Import wx.wxStaticText
Import wx.wxPanel

'	You'll need to download this from <img src="http://www.gibbongames.com/temp/bitmap_panel.png">
Const s_BITMAP_PANEL_PATH:String = "media\bitmap_panel.png"

New MyApp.run()

' ----------------------------------------------------------------
Rem
	bbdoc:   
	about:    
End Rem	
Type MyApp Extends wxApp

	Field Window:wxFrame
	Field Panel:TBitmapPanel
	Field Label:TLabel[6]
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem		
	Method OnInit:Int()
		
		wxInitAllImageHandlers()

		'	Create the window
		Window = New wxFrame.Create(Null, , "Window", , , 600, 600)
		Window.Centre()	
	
		'	Create the p=textured panel
		Panel = TBitmapPanel(New TBitmapPanel.Create(Window,wxID_ANY, 1,1,598,598))
			
		'	Create 6 labels	
		Local y:Int = 25
		
		Local s_text:String[] = ["Label 1 (one)","Label 2 (two)","Label 3 (three)", "Label 4 (four)", "Label 5 (five)", "Label 6 (six)"]
							
		For Local label_id:Int = 0 Until s_text.length
							
			Label[label_id] 		= TLabel(New TLabel.Create(Panel, wxID_ANY,s_text[label_id], 50,y, 450,60))
			Label[label_id].Font 	= New wxFont.CreateWithAttribs(16 +2*label_id, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL ,wxFONTWEIGHT_NORMAL)
			Label[label_id].SetFont(Label[label_id].Font)
		'	Label[label_id].Refresh()
			y:+ 80
		
		Next
			
		Window.Show(True)
					
		Return True
	
	End Method

End Type

' ----------------------------------------------------------------
Rem
	bbdoc:   
	about:    
End Rem	
Type TLabel Extends wxStaticText

	Field Font:wxFont
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnEraseBackground(_event:wxEraseEvent)
	
		DebugLog "OnEraseIn"
	
		If Not _event Then Throw "TLabel.OnEraseBackground - null event!"
	
		Local dc:wxDC = _event.GetDC()
		
		If dc 
		
			Local x:Int
			Local y:Int
			Local w:Int
			Local h:Int
			
			getRect(x,y,w,h)
			
			dc.SetBrush(wxTRANSPARENT_BRUSH())
			dc.SetBackgroundMode(wxTRANSPARENT)
		
			dc.SetTextForeground(New wxColour.Create(255,255,255))
		
			dc.DrawText(GetLabel(),x, y)
			
		'	DebugLog "OnEraseBackground " +GetLabel() +" x " +x +" y " +y
			
			RefreshRect(x, y, w, h, False)
		
		EndIf	
		
	'	_event.Skip()
		
		DebugLog "OnEraseOut"
			
	End Method
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnInit()
		
		SetBackgroundStyle(wxBG_STYLE_CUSTOM)
		
		'Connect(GetId(), wxEVT_ERASE_BACKGROUND,_OnErase)
		Connect( GetId(),wxEVT_PAINT,_OnPaint)
		
		
	End Method
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem		
	Method OnPaint(_event:wxPaintEvent)
	
		Local dc:wxPaintDC = New wxPaintDC.Create(Self)
		
		Local x:Int
		Local y:Int
		Local w:Int
		Local h:Int
		
		getRect(x,y,w,h)
		
		dc.SetFont(GetFont())
		
		dc.SetBrush(wxTRANSPARENT_BRUSH())
		dc.SetPen(wxTRANSPARENT_PEN())
		dc.SetPen(wxBLACK_PEN())
		
		dc.SetBackgroundMode(wxTRANSPARENT)
		dc.SetBackground(wxTRANSPARENT_BRUSH())
		dc.SetTextForeground(wxBLACK())
		
		dc.DrawText(GetLabel(),x, y)
		
		DebugLog "OnPaint " +GetLabel() +" x " +x +" y " +y
		
		dc.Free()
		
	End Method
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Function _OnErase(_event:wxEvent)
		TLabel(_event.parent).OnEraseBackground(wxEraseEvent(_event))
	End Function
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Function _OnPaint(_event:wxEvent)
		TLabel(_event.parent).OnPaint(wxPaintEvent(_event))
	End Function

End Type

' ----------------------------------------------------------------
Rem
	bbdoc:   
	about:    
End Rem	
Type TBitmapPanel Extends wxPanel

	Field BackgroundImage:wxBitmap
	Field s_BackgroundImage:String = s_BITMAP_PANEL_PATH 
		
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnInit()
		ConnectAny(wxEVT_PAINT, _OnPaint)		
	End Method

	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnPaint(_event:wxPaintEvent)
		
		Local paint_dc:wxPaintDC
		
		'	If we desire an image background
		If BackgroundImage Or s_BackgroundImage 
			
			paint_dc = New wxPaintDC.Create(Self)
	
			' If we haven't loaded in our image yet
			If Not BackgroundImage
										
				'	Does image file exist?
				If Not FileType(s_BackgroundImage) Then Throw "TPanel.OnPaint Image does Not exist? Invalid path: " + s_BackgroundImage
				
				'	Load in the image. No need to free it manually GC will do this for us
				BackgroundImage = wxBitmap.CreateFromFile(s_BackgroundImage, wxBITMAP_TYPE_PNG)
				
				'	Safety check
				If Not BackgroundImage.IsOK() Then Throw "TPanel.OnPaint Invalid image (we require PNG format)  " + s_BackgroundImage
			EndIf
			
			'	Draw the background image
			If BackgroundImage Then paint_dc.DrawBitmap(BackgroundImage, 0, 0, True)
		
		EndIf	
			
		' Manual free as we can't afford to rely on timely auto garbage collection 
		If paint_dc 
			paint_dc.Free()
		EndIf
								
		_event.Skip()
		
	End Method
	
	Rem
		bbdoc:   
		about:    
	End Rem	
	Function _OnPaint(_event:wxEvent)
		TBitmapPanel(_event.parent).OnPaint(wxPaintEvent(_event))
	End Function

End Type


Works on Mac! ;-)

How's about this :

SuperStrict

Framework wx.wxApp
Import wx.wxFrame
Import wx.wxStaticText
Import wx.wxPanel

'	You'll need to download this from <img src="http://www.gibbongames.com/temp/bitmap_panel.png">
Const s_BITMAP_PANEL_PATH:String = "media/bitmap_panel.png"

New MyApp.run()

' ----------------------------------------------------------------
Rem
	bbdoc:   
	about:    
End Rem	
Type MyApp Extends wxApp

	Field Window:wxFrame
	Field Panel:TBitmapPanel
	Field Label:TLabel[6]
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem		
	Method OnInit:Int()
		
		wxInitAllImageHandlers()

		'	Create the window
		Window = New wxFrame.Create(Null, , "Window", , , 600, 600)
		Window.Centre()	
	
		'	Create the p=textured panel
		Panel = TBitmapPanel(New TBitmapPanel.Create(Window,wxID_ANY, 1,1,598,598))
			
		'	Create 6 labels	
		Local y:Int = 25
		
		Local s_text:String[] = ["Label 1 (one)","Label 2 (two)","Label 3 (three)", "Label 4 (four)", "Label 5 (five)", "Label 6 (six)"]
							
		For Local label_id:Int = 0 Until s_text.length
							
			Label[label_id] 		= TLabel(New TLabel.Create(Panel, wxID_ANY,s_text[label_id], 50,y, 450,60))
			Label[label_id].Font 	= New wxFont.CreateWithAttribs(16 +2*label_id, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL ,wxFONTWEIGHT_NORMAL)
			Label[label_id].SetFont(Label[label_id].Font)
		'	Label[label_id].Refresh()
			y:+ 80
		
		Next
			
		Window.Show(True)
					
		Return True
	
	End Method

End Type

' ----------------------------------------------------------------
Rem
	bbdoc:   
	about:    
End Rem	
Type TLabel Extends wxStaticText

	Field Font:wxFont

	Global BackgroundImage:wxBitmap
	Global s_BackgroundImage:String = s_BITMAP_PANEL_PATH 
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnEraseBackground(_event:wxEraseEvent)
	
		DebugLog "OnEraseIn"
	
		If Not _event Then Throw "TLabel.OnEraseBackground - null event!"
	
		Local dc:wxDC = _event.GetDC()
		
		If dc 
		
			Local x:Int
			Local y:Int
			Local w:Int
			Local h:Int
			
			getRect(x,y,w,h)
			
			'dc.SetBrush(wxTRANSPARENT_BRUSH())
			'dc.SetBackgroundMode(wxTRANSPARENT)
		
			dc.SetTextForeground(New wxColour.Create(255,255,255))
		
			If BackgroundImage Then
				Local bmp:wxBitmap = BackgroundImage.GetSubBitmap(x, y, w, h)
				dc.DrawBitmap(bmp, x, y, True)
			End If
'			dc.DrawText(GetLabel(),x, y)
			'dc.DrawText("asdasd",x, y)
			
			'DebugLog "OnEraseBackground " +GetLabel() +" x " +x +" y " +y
			
			'RefreshRect(x, y, w, h, False)
		
		EndIf	
		
		'_event.Skip()
		
		DebugLog "OnEraseOut"
			
	End Method
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnInit()

		If Not BackgroundImage
									
			'	Does image file exist?
			If Not FileType(s_BackgroundImage) Then Throw "TPanel.OnPaint Image does Not exist? Invalid path: " + s_BackgroundImage
			
			'	Load in the image. No need to free it manually GC will do this for us
			BackgroundImage = wxBitmap.CreateFromFile(s_BackgroundImage, wxBITMAP_TYPE_PNG)
			
			'	Safety check
			If Not BackgroundImage.IsOK() Then Throw "TPanel.OnPaint Invalid image (we require PNG format)  " + s_BackgroundImage
		EndIf


		
		'SetBackgroundStyle(wxBG_STYLE_CUSTOM)
		
		'Connect(GetId(), wxEVT_ERASE_BACKGROUND,_OnErase)
		Connect( GetId(),wxEVT_PAINT,_OnPaint)
		
		
	End Method
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem		
	Method OnPaint(_event:wxPaintEvent)
	
		Local dc:wxPaintDC = New wxPaintDC.Create(Self)

		Local x:Int
		Local y:Int
		Local w:Int
		Local h:Int
		
		getRect(x,y,w,h)

		If BackgroundImage Then
			Local bmp:wxBitmap = BackgroundImage.GetSubBitmap(x, y, w, h)
			dc.DrawBitmap(bmp, 0, 0, True)
		End If
		
		dc.SetFont(GetFont())
		
		dc.DrawText(GetLabel(),0, 0)
		
		DebugLog "OnPaint " +GetLabel() +" x " +x +" y " +y
		
		dc.Free()
		
	End Method
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Function _OnErase(_event:wxEvent)
		TLabel(_event.parent).OnEraseBackground(wxEraseEvent(_event))
	End Function
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Function _OnPaint(_event:wxEvent)
		TLabel(_event.parent).OnPaint(wxPaintEvent(_event))
	End Function

End Type

' ----------------------------------------------------------------
Rem
	bbdoc:   
	about:    
End Rem	
Type TBitmapPanel Extends wxPanel

	Field BackgroundImage:wxBitmap
	Field s_BackgroundImage:String = s_BITMAP_PANEL_PATH 
		
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnInit()
		ConnectAny(wxEVT_PAINT, _OnPaint)		
	End Method

	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnPaint(_event:wxPaintEvent)
		
		Local paint_dc:wxPaintDC
		
		'	If we desire an image background
		If BackgroundImage Or s_BackgroundImage 
			
			paint_dc = New wxPaintDC.Create(Self)
	
			' If we haven't loaded in our image yet
			If Not BackgroundImage
										
				'	Does image file exist?
				If Not FileType(s_BackgroundImage) Then Throw "TPanel.OnPaint Image does Not exist? Invalid path: " + s_BackgroundImage
				
				'	Load in the image. No need to free it manually GC will do this for us
				BackgroundImage = wxBitmap.CreateFromFile(s_BackgroundImage, wxBITMAP_TYPE_PNG)
				
				'	Safety check
				If Not BackgroundImage.IsOK() Then Throw "TPanel.OnPaint Invalid image (we require PNG format)  " + s_BackgroundImage
			EndIf
			
			'	Draw the background image
			If BackgroundImage Then paint_dc.DrawBitmap(BackgroundImage, 0, 0, True)
		
		EndIf	
			
		' Manual free as we can't afford to rely on timely auto garbage collection 
		If paint_dc 
			paint_dc.Free()
		EndIf
								
		_event.Skip()
		
	End Method
	
	Rem
		bbdoc:   
		about:    
	End Rem	
	Function _OnPaint(_event:wxEvent)
		TBitmapPanel(_event.parent).OnPaint(wxPaintEvent(_event))
	End Function

End Type



Kind of avoids the issue by painting the appropriate bitmap section before drawing text on top of it.

So EraseBackground wasn't needed in the end at all! I'm amazed at how many different solutions were out there - but I didn't see that one!

Thanks so much Brucey :-)

[Edit] I've cleaned up the above code and posted it below for the benefit of those also stuck on this issue.

SuperStrict

Framework wx.wxApp
Import wx.wxFrame
Import wx.wxStaticText
Import wx.wxPanel

'	You'll need to download this from <img src="http://www.gibbongames.com/temp/bitmap_panel.png">
Global s_BackgroundImage:String = "media/bitmap_panel.png"
'	You'd probably store these in a bitmap class rather than pure globals
Global BackgroundImage:wxBitmap

New MyApp.run()

' ----------------------------------------------------------------
Rem
	bbdoc:   This is an XP-only work around to enable transparent static text control backgrounds
	about:   OS X (and I presume Vista) don't need this 
End Rem	
Type MyApp Extends wxApp

	Field Window:wxFrame
	Field Panel:TBitmapPanel
	Field Label:TLabel[6]
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem		
	Method OnInit:Int()
		
		wxInitAllImageHandlers()

		'	Create the window
		Window = New wxFrame.Create(Null, , "How to draw transparent static text controls in XP", , , 600, 600)
		Window.Centre()	
		
		'	Both label and panel need access to this
		If Not BackgroundImage
									
			'	Does image file exist?
			If Not FileType(s_BackgroundImage) Then Throw "MyApp.OnInit Image does Not exist? Invalid path: " + s_BackgroundImage
			
			'	Load in the image. No need to free it manually GC will do this for us
			BackgroundImage = wxBitmap.CreateFromFile(s_BackgroundImage, wxBITMAP_TYPE_PNG)
			
			'	Safety check
			If Not BackgroundImage.IsOK() Then Throw "MyApp.OnInit Invalid image (we require PNG format)  " + s_BackgroundImage
		
		EndIf
	
		'	Create the textured panel
		Panel = TBitmapPanel(New TBitmapPanel.Create(Window,wxID_ANY, 1,1,598,598))
			
		'	Create 6 labels	
		Local y:Int = 25
		
		Local s_text:String[] = ["Label 1 (one)","Label 2 (two)","Label 3 (three)", "Label 4 (four)", "Label 5 (five)", "Label 6 (six)"]
							
		For Local label_id:Int = 0 Until s_text.length
							
			Label[label_id] 		= TLabel(New TLabel.Create(Panel, wxID_ANY,s_text[label_id], 50,y, 450,60))
			Label[label_id].Font 	= New wxFont.CreateWithAttribs(16 +2*label_id, wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL ,wxFONTWEIGHT_NORMAL)
			Label[label_id].SetFont(Label[label_id].Font)
			y:+ 80
		
		Next
			
		Window.Show(True)
					
		Return True
	
	End Method

End Type

' ----------------------------------------------------------------
Rem
	bbdoc:   
	about:    
End Rem	
Type TLabel Extends wxStaticText

	Field Font:wxFont
	Field SubBitmap:wxBitmap
		
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnInit()

		Connect( GetId(),wxEVT_PAINT,_OnPaint)
		
	End Method
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem		
	Method OnPaint(_event:wxPaintEvent)
	
		Local dc:wxPaintDC = New wxPaintDC.Create(Self)

		If BackgroundImage 

			'	Grab the texture immediately beneath this static text label
			If Not SubBitmap 

				Local x:Int
				Local y:Int
				Local w:Int
				Local h:Int
				
				getRect(x,y,w,h)
			
				SubBitmap = BackgroundImage.GetSubBitmap(x, y, w, h)
			EndIf
			
			' Plaster the label background with the same texture as the panel beneath us
			dc.DrawBitmap(SubBitmap, 0, 0, True)
		End If
		
		dc.SetFont(GetFont())
		
		dc.DrawText(GetLabel(),0, 0)
		
		DebugLog "OnPaint " +GetLabel() 
		
		dc.Free()
		
	End Method

	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Function _OnPaint(_event:wxEvent)
		TLabel(_event.parent).OnPaint(wxPaintEvent(_event))
	End Function

End Type

' ----------------------------------------------------------------
Rem
	bbdoc:   
	about:    
End Rem	
Type TBitmapPanel Extends wxPanel
	
	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnInit()
		ConnectAny(wxEVT_PAINT, _OnPaint)		
	End Method

	' ----------------------------------------------------------------
	Rem
		bbdoc:   
		about:    
	End Rem	
	Method OnPaint(_event:wxPaintEvent)
		
		Local paint_dc:wxPaintDC
		
		'	If we desire an image background
		If BackgroundImage 
			
			paint_dc = New wxPaintDC.Create(Self)
	
			'	Draw the background image
			paint_dc.DrawBitmap(BackgroundImage, 0, 0, True)
		
		EndIf	
			
		' Manual free as we can't afford to rely on timely auto garbage collection 
		If paint_dc 
			paint_dc.Free()
		EndIf
								
		_event.Skip()
		
	End Method
	
	Rem
		bbdoc:   
		about:    
	End Rem	
	Function _OnPaint(_event:wxEvent)
		TBitmapPanel(_event.parent).OnPaint(wxPaintEvent(_event))
	End Function

End Type