Effect in the Windows system:
I first tried to set a form's background image, and I need to initialize wxWidgets' image functionality. Add a line of code during the application initialization.
class RandGameApp : public wxApp
{
public:
virtual bool OnInit()
{
//Image Processing Initialization Code
wxInitAllImageHandlers();
...
return true;
}
};
After that, I need to declare an image member variable in the custom form class.
Load images and bind event handlers in the custom form class constructor
//load image
m_background.LoadFile("resource/background_0.jpg", wxBITMAP_TYPE_JPEG);
//bind
Bind(wxEVT_ERASE_BACKGROUND, &RandomGeneratorPage::OnEraseBackground, this);
Bind(wxEVT_SIZE, &RandomGeneratorPage::OnSize, this);
I draw an image in the OnEraseBackground function
void RandomGeneratorPage::OnEraseBackground(wxEraseEvent& event) {
wxDC* dc = event.GetDC();
if (!dc) {
return;
}
// get size
wxSize size = GetSize();
// If the image size does not match the control, it can be scaled.
if (m_background.GetWidth() != size.x ||
m_background.GetHeight() != size.y) {
// Create a resized image
wxImage img = m_background.ConvertToImage();
img.Rescale(size.x, size.y);
wxBitmap scaled(img);
dc->DrawBitmap(scaled, 0, 0, true);
} else {
dc->DrawBitmap(m_background, 0, 0, true);
}
}In order for the background image to refresh when the window is resized, I need to force the window to refresh in the OnSize function. Otherwise, the background image will become blurry when the window size changes.
void RandomGeneratorPage::OnSize(wxSizeEvent& event) {
Refresh();
// RefreshRect(GetClientRect());
// Update();
event.Skip();
}
This achieves the function of a window background image.
Implement a custom-drawn control with a transparent background. The transparent background here means that the areas of the control that are not drawn are transparent, revealing the content of the parent window.
At first, I tried inheriting from a standard control to draw it, but it was useless. The control's background would either turn completely black or show the parent window's default background color, making transparency impossible.
Later, I added the following statement in the constructor of the class inheriting from the wxStaticText control.
HWND hwnd = GetHWND();
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_TRANSPARENT);
Bind(wxEVT_PAINT, &TransparentStaticText::OnPaint, this);
Bind(wxEVT_ERASE_BACKGROUND,&TransparentStaticText::OnEraseBackground, this);
Bind(wxEVT_SIZE, &TransparentStaticText::OnSize, this);Then implemented the bound member function
void OnEraseBackground(wxEraseEvent& event) {
}
void OnPaint(wxPaintEvent& event) {
wxPaintDC dc(this);
dc.SetFont(GetFont());
dc.SetTextForeground(GetForegroundColour());
dc.DrawText(GetLabel(), 0, 0);
}
void OnSize(wxSizeEvent& event) {
Refresh();
event.Skip();
}The text can achieve a transparent background.
Later, I saw the official statement that standard controls should not be redrawn. Even if it works, it is very unstable.
Please notice that in general it is impossible to change the drawing of a standard control (such as wxButton) and so you shouldn't attempt to handle paint events for them as even if it might work on some platforms, this is inherently not portable and won't work everywhere.
It's difficult to draw transparent controls in wxWidgets. The official library doesn't support it. Many people have discussed it online. Using various functions to set control properties is almost useless. The only effective way is to implement fake transparency. This means redrawing the background of the parent window in the corresponding area on the control.
Here, we are drawing a rounded corner button. In the rounded corners, the background image of the parent window will be displayed instead of an ugly blank area.
Add the following code in the constructor of the custom-drawn control to bind the event handler.
Bind(wxEVT_PAINT, &CustomButton::OnPaint, this);
Bind(wxEVT_ERASE_BACKGROUND,&CustomButton::OnEraseBackground, this); void OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
// Get parent window
wxWindow *parent = GetParent();
wxPoint pt = GetPosition();
wxSize sz = GetSize();
wxClientDC parentDC(parent);
// Draw parent window background
dc.Blit(0,0,sz.x,sz.y,&parentDC,pt.x,pt.y,wxCOPY,true);
// Draw control content
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxBrush(wxColor(255,111,111,123)));
dc.DrawRoundedRectangle(5,5,sz.x-10,sz.y-10,12);
dc.SetTextForeground(*wxWHITE);
dc.DrawText(GetLabel(),10,10);
}
void OnEraseBackground(wxEraseEvent& event)
{
// do nothing
}This achieves a transparent background. In areas where the control is not drawn, the contents of the parent window can be displayed, rather than showing white or black blocks.
I decided to give up using wxWidgets because I find its custom drawing inconvenient.
Even drawing a transparent control is this troublesome, I might run into other problems in the future.
If you use it, it's best suited for scenarios where using the operating system's native controls is sufficient and no beautification is needed.