Categories: ComponentswxWidgets

How to Create Nice About Box in wxWidgets

After taking a look at wxWidgets samples I noticed that all of them have simple message box instaed of normal about box. However in real applications About dialog is important enough part of GUI.

So, in this post I’m going to tell a bit about creating About boxes for your software.

wxWidgets has builf-in API for creating “standard” dialog boxes. wxAboutBox() function is used for displaying About box and wxAboutDialogInfo object, which contains all necessary information, should be passed to wxAboutBox() function.

wxAboutDialogInfo can contain such information as:

  • Application name
  • Application icon
  • Application description
  • Application version
  • List of developers
  • List of artists
  • List of documentation writers
  • List of translators
  • Copyright message
  • Web-site URL
  • Application license

Only wxGTK port supports native way of displaying application license. On other platforms generic implementation will be used and it is better to create a separate dialog for this purpose.

Well, here is a small example of using API described above:

#include
...
// This object will contain all information displayed in About box
wxAboutDialogInfo info;
// Call of AddDeveloper() method adds a record to list of developers
info.AddDeveloper(_("John Doe"));
// Call of AddDocWriter() method adds a record to list of documentation writers
info.AddDocWriter(_("Donald Duck"));
// Call of AddArtist() method adds a record to list of artists
info.AddArtist(_("Scrooge Mc.Duck"));
// Call of AddTranslator() method adds a record to list of translators
info.AddTranslator(_("Mickey Mouse"));
// This method adds application description.
info.SetDescription(_("Sample wxWidgets application for testing wxAboutBox() function."));
// This method sets application version string
info.SetVersion(wxT("1.0.0 beta 1"));
// SetName() method sets application name displayed in About box.
// It is better to pass wxApp::GetAppName() to this method
info.SetName(wxTheApp->GetAppName());
// Sets application Web-site URL
info.SetWebSite(wxT("https://wxwidgets.info"));
// Sets the icon which will be displayed in About box.
info.SetIcon(wxICON(wxICON_AAA));
// Sets application license string. Only wxGTK port has native way of
// displaying application license. All other ports will use generic way for this purpose.
info.SetLicence(_("Public Domain"));

// At last, we can display about box
wxAboutBox(info);


As you can see, there are several collapsible panels placed to dialog. The amount of these panels changes according theinformation specified in wxAboutDialogInfo object.
After expanding collapsible panels we’ll get something like this:

Looks nice but a bit boring. So I decided to create more fancy About box. In fact, I was inspired by this post at wxForum but used my own way and also made some changes.

wxMozillaLikeAboutBoxDialog.h

#ifndef _WXMOZILLALIKEABOUTBOXDIALOG_H_
#define _WXMOZILLALIKEABOUTBOXDIALOG_H_

#include "wx/gbsizer.h"
#include "wx/statline.h"

#define SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_STYLE wxCAPTION|wxSYSTEM_MENU|wxCLOSE_BOX|wxTAB_TRAVERSAL
#define SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_TITLE _("About ")
#define SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_IDNAME ID_WXMOZILLALIKEABOUTBOXDIALOG
#define SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_SIZE wxSize(400, 300)
#define SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_POSITION wxDefaultPosition

class wxMozillaLikeAboutBoxDialog: public wxDialog
{
    DECLARE_DYNAMIC_CLASS( wxMozillaLikeAboutBoxDialog )
    DECLARE_EVENT_TABLE()
public:
    wxMozillaLikeAboutBoxDialog();
    wxMozillaLikeAboutBoxDialog( wxWindow* parent,
  wxWindowID id = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_IDNAME,
  const wxString& caption = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_TITLE,
  const wxPoint& pos = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_POSITION,
  const wxSize& size = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_SIZE,
  long style = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_STYLE );

    bool Create( wxWindow* parent,
  wxWindowID id = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_IDNAME,
  const wxString& caption = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_TITLE,
  const wxPoint& pos = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_POSITION,
  const wxSize& size = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_SIZE,
  long style = SYMBOL_WXMOZILLALIKEABOUTBOXDIALOG_STYLE );

    ~wxMozillaLikeAboutBoxDialog();

    void Init();
    void CreateControls();

    wxString GetAppName() const { return m_AppName ; }
    void SetAppName(wxString value) { m_AppName = value ; }

    wxString GetVersion() const { return m_Version ; }
    void SetVersion(wxString value) { m_Version = value ; }

    wxString GetCopyright() const { return m_Copyright ; }
    void SetCopyright(wxString value) { m_Copyright = value ; }

    wxString GetCustomBuildInfo() const { return m_CustomBuildInfo ; }
    void SetCustomBuildInfo(wxString value) { m_CustomBuildInfo = value ; }

    wxBitmap GetBitmapResource( const wxString& name );
    wxIcon GetIconResource( const wxString& name );

    enum wxBuildInfoFormat
    {
        wxBUILDINFO_SHORT,
        wxBUILDINFO_LONG
    };

    static wxString GetBuildInfo(wxBuildInfoFormat format);

    void SetHeaderBitmap(const wxBitmap & value);
    void ApplyInfo();

private:
    wxPanel* m_ContentPanel;
    wxStaticBitmap* m_HeaderStaticBitmap;
    wxStaticText* m_AppNameStaticText;
    wxStaticText* m_CopyrightStaticText;
    wxStaticText* m_VersionStaticText;
    wxStaticText* m_BuildInfoStaticText;
    wxString m_AppName;
    wxString m_Version;
    wxString m_Copyright;
    wxString m_CustomBuildInfo;
    /// Control identifiers
    enum {
        ID_WXMOZILLALIKEABOUTBOXDIALOG = 10000,
        ID_ContentPanel = 10001
    };
};

wxBitmap wxGetBitmapFromMemory(const void * data, size_t length);

#endif

wxMozillaLikeAboutBoxDialog.cpp

#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

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

#include "wxMozillaLikeAboutBoxDialog.h"
#include <wx/mstream.h>

IMPLEMENT_DYNAMIC_CLASS( wxMozillaLikeAboutBoxDialog, wxDialog )

BEGIN_EVENT_TABLE( wxMozillaLikeAboutBoxDialog, wxDialog )
END_EVENT_TABLE()

wxMozillaLikeAboutBoxDialog::wxMozillaLikeAboutBoxDialog()
{
    Init();
}

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

bool wxMozillaLikeAboutBoxDialog::Create( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
{
    SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
    wxDialog::Create( parent, id, caption, pos, size, style );
    CreateControls();
    if (GetSizer())
    {
        GetSizer()->SetSizeHints(this);
    }
    Centre();
    return true;
}

wxMozillaLikeAboutBoxDialog::~wxMozillaLikeAboutBoxDialog()
{
}

void wxMozillaLikeAboutBoxDialog::Init()
{
    m_ContentPanel = NULL;
    m_HeaderStaticBitmap = NULL;
    m_AppNameStaticText = NULL;
    m_CopyrightStaticText = NULL;
    m_VersionStaticText = NULL;
    m_BuildInfoStaticText = NULL;
}

void wxMozillaLikeAboutBoxDialog::CreateControls()
{
    wxMozillaLikeAboutBoxDialog* itemDialog1 = this;
    wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
    itemDialog1->SetSizer(itemBoxSizer2);
    m_ContentPanel = new wxPanel( itemDialog1, ID_ContentPanel, wxDefaultPosition, wxSize(200, 300), wxNO_BORDER|wxTAB_TRAVERSAL );
    m_ContentPanel->SetBackgroundColour(wxColour(255, 255, 255));
    itemBoxSizer2->Add(m_ContentPanel, 0, wxGROW, 0);
    wxBoxSizer* itemBoxSizer4 = new wxBoxSizer(wxVERTICAL);
    m_ContentPanel->SetSizer(itemBoxSizer4);
    m_HeaderStaticBitmap = new wxStaticBitmap( m_ContentPanel, wxID_STATIC, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer4->Add(m_HeaderStaticBitmap, 0, wxGROW, 0);
    wxGridBagSizer* itemGridBagSizer6 = new wxGridBagSizer(0, 0);
    itemGridBagSizer6->AddGrowableRow(2);
    itemGridBagSizer6->AddGrowableRow(3);
    itemGridBagSizer6->SetEmptyCellSize(wxSize(10, 20));
    itemBoxSizer4->Add(itemGridBagSizer6, 0, wxGROW|wxLEFT|wxRIGHT|wxBOTTOM, 10);
    m_AppNameStaticText = new wxStaticText( m_ContentPanel, wxID_STATIC, _T(""), wxDefaultPosition, wxDefaultSize, 0 );
    m_AppNameStaticText->SetForegroundColour(wxColour(255, 0, 0));
    m_AppNameStaticText->SetFont(wxFont(28, wxSWISS, wxNORMAL, wxNORMAL, false, wxT("Arial Narrow")));
    itemGridBagSizer6->Add(m_AppNameStaticText, wxGBPosition(0, 0), wxGBSpan(1, 2), wxALIGN_LEFT|wxALIGN_BOTTOM|wxLEFT|wxRIGHT|wxTOP, 5);
    wxStaticText* itemStaticText8 = new wxStaticText( m_ContentPanel, wxID_STATIC, _("version"), wxDefaultPosition, wxDefaultSize, 0 );
    itemStaticText8->SetForegroundColour(wxColour(192, 192, 192));
    itemStaticText8->SetFont(wxFont(8, wxSWISS, wxNORMAL, wxBOLD, false, wxT("Arial")));
    itemGridBagSizer6->Add(itemStaticText8, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_RIGHT|wxALIGN_TOP|wxLEFT|wxBOTTOM, 5);
    m_CopyrightStaticText = new wxStaticText( m_ContentPanel, wxID_STATIC, _T(""), wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE );
    itemGridBagSizer6->Add(m_CopyrightStaticText, wxGBPosition(2, 0), wxGBSpan(1, 2), wxGROW|wxGROW|wxALL, 5);
    m_VersionStaticText = new wxStaticText( m_ContentPanel, wxID_STATIC, _T(""), wxDefaultPosition, wxDefaultSize, 0 );
    m_VersionStaticText->SetForegroundColour(wxColour(192, 192, 192));
    m_VersionStaticText->SetFont(wxFont(8, wxSWISS, wxNORMAL, wxBOLD, false, wxT("Arial")));
    itemGridBagSizer6->Add(m_VersionStaticText, wxGBPosition(1, 1), wxGBSpan(1, 1), wxALIGN_LEFT|wxALIGN_TOP|wxLEFT|wxRIGHT|wxBOTTOM, 5);
    m_BuildInfoStaticText = new wxStaticText( m_ContentPanel, wxID_STATIC, _T(""), wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE );
    itemGridBagSizer6->Add(m_BuildInfoStaticText, wxGBPosition(3, 0), wxGBSpan(1, 2), wxGROW|wxGROW|wxALL, 5);
    itemBoxSizer4->Add(5, 5, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
    wxStaticLine* itemStaticLine13 = new wxStaticLine( itemDialog1, wxID_STATIC, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
    itemBoxSizer2->Add(itemStaticLine13, 0, wxGROW, 0);
    wxStdDialogButtonSizer* itemStdDialogButtonSizer14 = new wxStdDialogButtonSizer;
    itemBoxSizer2->Add(itemStdDialogButtonSizer14, 0, wxALIGN_RIGHT|wxALL, 5);
    wxButton* itemButton15 = new wxButton( itemDialog1, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 );
    itemStdDialogButtonSizer14->AddButton(itemButton15);
    itemStdDialogButtonSizer14->Realize();
    m_BuildInfoStaticText->SetLabel(wxMozillaLikeAboutBoxDialog::GetBuildInfo(wxBUILDINFO_LONG));
}

And here is a method which returns a string with build information

wxString wxMozillaLikeAboutBoxDialog::GetBuildInfo(wxBuildInfoFormat format)
{
    wxString wxbuild(wxVERSION_STRING);

    if (format == wxBUILDINFO_LONG)
    {
#if defined(__WXMSW__)
        wxbuild << _T("-Windows");
#elif defined(__WXMAC__)
        wxbuild << _T("-Mac");
#elif defined(__UNIX__)
        wxbuild << _T("-Linux");
#endif

#if wxUSE_UNICODE
        wxbuild << _T("-Unicode");
#else
        wxbuild << _T("-ANSI");
#endif // wxUSE_UNICODE
    }
 wxbuild << _(" build");
    return wxbuild;
}
&#91;/sourcecode&#93;
This method utilizes <code>wxVERSION_STRING</code> macro which returns a string with wxWidgets version.
[sourcecode language="cpp"]
wxBitmap wxGetBitmapFromMemory(const void * data, size_t length)
{
 wxMemoryInputStream stream(data, length);
 return wxBitmap(stream, wxBITMAP_TYPE_ANY);
}

void wxMozillaLikeAboutBoxDialog::SetHeaderBitmap(const wxBitmap & value)
{
    m_HeaderStaticBitmap->SetBitmap(value);
}

wxGetBitmapFromMemory() method creates wxBitmap from memory buffer using wxMemoryInputStream.

void wxMozillaLikeAboutBoxDialog::ApplyInfo()
{
 wxASSERT_MSG(m_HeaderStaticBitmap->GetBitmap().IsOk(), _("Header bitmap for About box is empty"));
 SetTitle(wxString::Format(wxT("%s %s"), _("About"), m_AppName.GetData()));
    m_AppNameStaticText->SetLabel(m_AppName);
    m_VersionStaticText->SetLabel(m_Version);
    m_CopyrightStaticText->SetLabel(m_Copyright);
 wxString buildInfo;
 if(m_CustomBuildInfo.IsEmpty())
 {
  buildInfo = wxMozillaLikeAboutBoxDialog::GetBuildInfo(wxBUILDINFO_LONG);
 }
 else
 {
  buildInfo = m_CustomBuildInfo;
 }
 m_BuildInfoStaticText->SetLabel(buildInfo);
 int labelWidth = m_HeaderStaticBitmap->GetSize().GetWidth() - 20;
 m_VersionStaticText->Wrap(labelWidth);
 m_CopyrightStaticText->Wrap(labelWidth);
 m_BuildInfoStaticText->Wrap(labelWidth);
 m_ContentPanel->Layout();
 m_ContentPanel->GetSizer()->Fit(m_ContentPanel);
    GetSizer()->Fit(this);
 Centre();
}

ApplyInfo method sets labels of all wxStaticText controls, applies header image and then fixes the layout according to changes.

Here is an example of usage of our Mozilla-like About box:

wxAboutBoxTestMainFrame.cpp

void wxAboutBoxTestMainFrame::OnMOZILLALIKEABOUTBOXClick( wxCommandEvent& event )
{
 // Create About box
 wxMozillaLikeAboutBoxDialog * dlg = new wxMozillaLikeAboutBoxDialog(this);
 // Set application name
 dlg->SetAppName(wxTheApp->GetAppName());
 // Set application version
 dlg->SetVersion(wxT("1.0.0 b1"));
 // Set copyright message
 dlg->SetCopyright(wxString::Format(wxT("%c %i %s"),
  (wxChar) 0x00A9, wxDateTime::Now().GetYear(),
  _("Volodymir (T-Rex) Tryapichko. All rights reserved. Please contact author if you have any copyright-related questions.")));
 // Set build info message. This is optional step. If you don't specify build info message then
 // default one will be used
 dlg->SetCustomBuildInfo(wxString::Format(wxT("%s. %s"),
  wxMozillaLikeAboutBoxDialog::GetBuildInfo(wxMozillaLikeAboutBoxDialog::wxBUILDINFO_LONG).GetData(),
  _("Compiled by T-Rex personally :)")));
 // Set header bitmap
 dlg->SetHeaderBitmap(wxGetBitmapFromMemory(header_png, sizeof(header_png)));
 // Apply changes
 dlg->ApplyInfo();
 // Show dialog
 dlg->ShowModal();
 // Destroy dialog
 dlg->Destroy();
}

header_png is a char array created from PNG image using Bin2C utility:

unsigned char header_png[] ={
 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,0x0D,0x49,0x48,
 ...
};

And here is a screenshot of what we get after compiling the source code listed above:

Download the source code for this tutorial.

T-Rex

View Comments

  • If you get this link error
    wxAboutBoxTestApp.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: void __thiscall wxStringData::Free(void)" (__imp_?Free@wxStringData@@QAEXXZ)""

    just go to Project Setting\C++\Code Generation\ and change Runtime Library to Multi-threaded Debug DLL (/MDd)

    • C/C++ -> Runtime Library property depends only on way how you compiled wxWidgets. I'm using static build which uses CRT statically.
      Anyway the simplest way is double check that your project settings correspond settings of wxWidgets projects

Share
Published by
T-Rex

Recent Posts

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

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

10 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…

14 years ago

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

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

15 years ago