How to Draw Gradient Buttons (wxWidgets Way)

Several days ago I found How to draw gradient buttons post at Native Mobile blog. Looks nice but I think that using GradienFill() is not very convenient because you need to fill all these TRIVERTEX structures. wxWidgets provides more convenient way of drawing gradients by using wxDC::GradientFillLinear(). Here is how it can be done in wxWidgets:

wxBufferedPaintDC dc(this);

wxRect clientRect = GetClientRect();
wxRect gradientRect = clientRect;
gradientRect.SetHeight(gradientRect.GetHeight()/2);
dc.GradientFillLinear(gradientRect,
wxColour(132,125,132), wxColour(74,69,74), wxSOUTH);
gradientRect.Offset(0, gradientRect.GetHeight());
dc.GradientFillLinear(gradientRect,
wxColour(0,0,0), wxColour(57,56,57), wxSOUTH);

dc.SetPen(wxPen(GetBackgroundColour()));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, clientRect.GetWidth(), clientRect.GetHeight());
dc.SetFont(GetFont());
dc.SetTextForeground(GetForegroundColour());
dc.DrawLabel(m_Label, clientRect,
wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL);

After some experiments I created a simple owner-drawn button control which utilizes this way of drawing:
wxGradientButton.h

/////////////////////////////////////////////////////////////////////////////
// Name:        wxGradientButton.h
// Purpose:
// Author:      Volodymir (T-Rex) Tryapichko
// Modified by:
// Created:     01/08/2008 20:25:42
// RCS-ID:
// Copyright:   Volodymir (T-Rex) Tryapichko, 2008
// Licence:
/////////////////////////////////////////////////////////////////////////////

#ifndef _WXGRADIENTBUTTON_H_
#define _WXGRADIENTBUTTON_H_

/*!
* Includes
*/
////@begin includes
////@end includes

/*!
* Forward declarations
*/
////@begin forward declarations
class wxGradientButton;
////@end forward declarations

/*!
* Control identifiers
*/
////@begin control identifiers
#define ID_WXGRADIENTBUTTON 10003
#define SYMBOL_WXGRADIENTBUTTON_STYLE wxSIMPLE_BORDER|wxFULL_REPAINT_ON_RESIZE
#define SYMBOL_WXGRADIENTBUTTON_IDNAME ID_WXGRADIENTBUTTON
#define SYMBOL_WXGRADIENTBUTTON_SIZE wxSize(100, 100)
#define SYMBOL_WXGRADIENTBUTTON_POSITION wxDefaultPosition
////@end control identifiers

/*!
* wxGradientButton class declaration
*/
class wxGradientButton: public wxWindow
{
DECLARE_DYNAMIC_CLASS( wxGradientButton )
DECLARE_EVENT_TABLE()

wxSize DoGetBestSize() const;
public:
/// Constructors
wxGradientButton();
wxGradientButton(wxWindow* parent,
wxWindowID id = ID_WXGRADIENTBUTTON,
const wxString & label = wxEmptyString,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxSize(100, 100),
long style = wxSIMPLE_BORDER);

/// Creation
bool Create(wxWindow* parent,
wxWindowID id = ID_WXGRADIENTBUTTON,
const wxString & label = wxEmptyString,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxSize(100, 100),
long style = wxSIMPLE_BORDER);

/// Destructor
~wxGradientButton();

/// Initialises member variables
void Init();

/// Creates the controls and sizers
void CreateControls();

////@begin wxGradientButton event handler declarations

/// wxEVT_SIZE event handler for ID_WXGRADIENTBUTTON
void OnSize( wxSizeEvent& event );

/// wxEVT_PAINT event handler for ID_WXGRADIENTBUTTON
void OnPaint( wxPaintEvent& event );

/// wxEVT_ERASE_BACKGROUND event handler for ID_WXGRADIENTBUTTON
void OnEraseBackground( wxEraseEvent& event );

/// wxEVT_LEFT_DOWN event handler for ID_WXGRADIENTBUTTON
void OnLeftDown( wxMouseEvent& event );

/// wxEVT_LEFT_UP event handler for ID_WXGRADIENTBUTTON
void OnLeftUp( wxMouseEvent& event );

////@end wxGradientButton event handler declarations

////@begin wxGradientButton member function declarations

wxString GetLabel() const { return m_Label ; }
void SetLabel(wxString value) { m_Label = value ; }

wxColour GetGradientTopStartColour() const { return m_GradientTopStartColour ; }
void SetGradientTopStartColour(wxColour value) { m_GradientTopStartColour = value ; }

wxColour GetGradientTopEndColour() const { return m_GradientTopEndColour ; }
void SetGradientTopEndColour(wxColour value) { m_GradientTopEndColour = value ; }

wxColour GetGradientBottomStartColour() const { return m_GradientBottomStartColour ; }
void SetGradientBottomStartColour(wxColour value) { m_GradientBottomStartColour = value ; }

wxColour GetGradientBottomEndColour() const { return m_GradientBottomEndColour ; }
void SetGradientBottomEndColour(wxColour value) { m_GradientBottomEndColour = value ; }

wxColour GetPressedColourTop() const { return m_PressedColourTop ; }
void SetPressedColourTop(wxColour value) { m_PressedColourTop = value ; }

wxColour GetPressedColourBottom() const { return m_PressedColourBottom ; }
void SetPressedColourBottom(wxColour value) { m_PressedColourBottom = value ; }

/// Retrieves bitmap resources
wxBitmap GetBitmapResource( const wxString& name );

/// Retrieves icon resources
wxIcon GetIconResource( const wxString& name );
////@end wxGradientButton member function declarations

/// Should we show tooltips?
static bool ShowToolTips();

////@begin wxGradientButton member variables
wxString m_Label;
wxColour m_GradientTopStartColour;
wxColour m_GradientTopEndColour;
wxColour m_GradientBottomStartColour;
wxColour m_GradientBottomEndColour;
wxColour m_PressedColourTop;
wxColour m_PressedColourBottom;
////@end wxGradientButton member variables
};

#endif
// _WXGRADIENTBUTTON_H_

wxGradientButton.cpp

/////////////////////////////////////////////////////////////////////////////
// Name:        wxGradientButton.cpp
// Purpose:
// Author:      Volodymir (T-Rex) Tryapichko
// Modified by:
// Created:     01/08/2008 20:25:42
// RCS-ID:
// Copyright:   Volodymir (T-Rex) Tryapichko, 2008
// Licence:
/////////////////////////////////////////////////////////////////////////////

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

////@begin includes
////@end includes

#include "wxGradientButton.h"
#include <wx/dcbuffer.h>

////@begin XPM images
////@end XPM images

/*!
* wxGradientButton type definition
*/
IMPLEMENT_DYNAMIC_CLASS( wxGradientButton, wxWindow )

/*!
* wxGradientButton event table definition
*/
BEGIN_EVENT_TABLE( wxGradientButton, wxWindow )

////@begin wxGradientButton event table entries
EVT_SIZE( wxGradientButton::OnSize )
EVT_PAINT( wxGradientButton::OnPaint )
EVT_ERASE_BACKGROUND( wxGradientButton::OnEraseBackground )
EVT_LEFT_DOWN( wxGradientButton::OnLeftDown )
EVT_LEFT_UP( wxGradientButton::OnLeftUp )

////@end wxGradientButton event table entries

END_EVENT_TABLE()

/*!
* wxGradientButton constructors
*/
wxGradientButton::wxGradientButton()
{
Init();
}

wxGradientButton::wxGradientButton(wxWindow* parent,
wxWindowID id, const wxString & label, const wxPoint& pos,
const wxSize& size, long style)
{
Init();
Create(parent, id, label, pos, size, style);
}

/*!
* wxGradientButton creator
*/
bool wxGradientButton::Create(wxWindow* parent,
wxWindowID id, const wxString & label, const wxPoint& pos,
const wxSize& size, long style)
{
////@begin wxGradientButton creation
wxWindow::Create(parent, id, pos, size, style);
CreateControls();
////@end wxGradientButton creation
m_Label = label;
return true;
}

/*!
* wxGradientButton destructor
*/
wxGradientButton::~wxGradientButton()
{
////@begin wxGradientButton destruction
////@end wxGradientButton destruction
}

/*!
* Member initialisation
*/
void wxGradientButton::Init()
{
////@begin wxGradientButton member initialisation
m_GradientTopStartColour = wxColour(132,125,132);
m_GradientTopEndColour = wxColour(74,69,74);
m_GradientBottomStartColour = wxColour(0,0,0);
m_GradientBottomEndColour = wxColour(57,56,57);
m_PressedColourTop = wxColour(57,56,57);
m_PressedColourBottom = wxColour(0,0,0);
////@end wxGradientButton member initialisation
}

/*!
* Control creation for wxGradientButton
*/
void wxGradientButton::CreateControls()
{
////@begin wxGradientButton content construction
this->SetForegroundColour(wxColour(255, 255, 255));
this->SetBackgroundColour(wxColour(0, 0, 0));
this->SetFont(wxFont(8, wxSWISS, wxNORMAL, wxBOLD, false, wxT("Tahoma")));
////@end wxGradientButton content construction
}

/*!
* Should we show tooltips?
*/
bool wxGradientButton::ShowToolTips()
{
return true;
}

/*!
* Get bitmap resources
*/
wxBitmap wxGradientButton::GetBitmapResource( const wxString& name )
{
// Bitmap retrieval
////@begin wxGradientButton bitmap retrieval
wxUnusedVar(name);
return wxNullBitmap;
////@end wxGradientButton bitmap retrieval
}

/*!
* Get icon resources
*/
wxIcon wxGradientButton::GetIconResource( const wxString& name )
{
// Icon retrieval
////@begin wxGradientButton icon retrieval
wxUnusedVar(name);
return wxNullIcon;
////@end wxGradientButton icon retrieval
}

wxSize wxGradientButton::DoGetBestSize() const
{
wxSize labelSize = wxDefaultSize;
GetTextExtent(m_Label, &labelSize.x, &labelSize.y);
return wxSize(wxMax(40, labelSize.x + 20), wxMax(20, labelSize.y + 10));
}

/*!
* wxEVT_PAINT event handler for ID_WXGRADIENTBUTTON
*/
void wxGradientButton::OnPaint( wxPaintEvent& event )
{
// Before editing this code, remove the block markers.
wxBufferedPaintDC dc(this);

wxRect clientRect = GetClientRect();
wxRect gradientRect = clientRect;
gradientRect.SetHeight(gradientRect.GetHeight()/2 +
((GetCapture() == this) ? 1 : 0));
if(GetCapture() != this)
{
dc.GradientFillLinear(gradientRect,
m_GradientTopStartColour, m_GradientTopEndColour, wxSOUTH);
}
else
{
dc.SetPen(wxPen(m_PressedColourTop));
dc.SetBrush(wxBrush(m_PressedColourTop));
dc.DrawRectangle(gradientRect);
}

gradientRect.Offset(0, gradientRect.GetHeight());

if(GetCapture() != this)
{
dc.GradientFillLinear(gradientRect,
m_GradientBottomStartColour, m_GradientBottomEndColour, wxSOUTH);
}
else
{
dc.SetPen(wxPen(m_PressedColourBottom));
dc.SetBrush(wxBrush(m_PressedColourBottom));
dc.DrawRectangle(gradientRect);
}
dc.SetPen(wxPen(GetBackgroundColour()));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, clientRect.GetWidth(), clientRect.GetHeight());
dc.SetFont(GetFont());
dc.SetTextForeground(GetForegroundColour());
if(GetCapture() == this)
{
clientRect.Offset(1, 1);
}
dc.DrawLabel(m_Label, clientRect, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL);
}

/*!
* wxEVT_LEFT_DOWN event handler for ID_WXGRADIENTBUTTON
*/
void wxGradientButton::OnLeftDown( wxMouseEvent& event )
{
if(GetCapture() != this)
{
CaptureMouse();
Refresh();
}
}

/*!
* wxEVT_LEFT_UP event handler for ID_WXGRADIENTBUTTON
*/
void wxGradientButton::OnLeftUp( wxMouseEvent& event )
{
if(GetCapture() == this)
{
ReleaseMouse();
Refresh();
if(GetClientRect().Contains(event.GetPosition()))
{
wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
GetEventHandler()->AddPendingEvent(evt);
}
}
}

/*!
* wxEVT_ERASE_BACKGROUND event handler for ID_WXGRADIENTBUTTON
*/
void wxGradientButton::OnEraseBackground( wxEraseEvent& event )
{
}

/*!
* wxEVT_SIZE event handler for ID_WXGRADIENTBUTTON
*/
void wxGradientButton::OnSize( wxSizeEvent& event )
{
Refresh();
}

After you compile the code, you’ll get someting like this:

wxGradientButton under Windows Mobile

You can download the source code of sample application which uses wxGradientButton control here. Sample application compiles for Win32 and Windows Mobile 6 platforms.

Read discussion of wxGradientButton at wxForum.

T-Rex

Share
Published by
T-Rex

Recent Posts

Разработка кроссплатформенных модульных приложений на C++ с библиотекой wxWidgets

Введение Уже долгое время не пишу статьи о разработке, хотя сам процесс написания мне очень…

11 years ago

wxWidgets App With Plugins (Windows/Linux/Mac) – Sample Source Code

I can see that there is still a lot of topics at wxWidgets forums related…

11 years ago

wxToolBox is Now Open-Source!

I've just published the source code of wxToolBox component and a couple of sample apps at…

11 years ago

Microsoft Kinect Helper Library and Sample for wxWidgets

Microsoft released their Kinect SDK several days ago. So, for those wxWidgets developers who are…

13 years ago

wxJSON 1.1.0 Released

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to…

15 years ago

wxRuby. Оно даже работает!

Вдохновленнный читаемой нынче книгой My Job Went to India: 52 Ways to Save Your Job…

15 years ago