Beech:Using custom dialogs

From WxWiki
Jump to: navigation, search

Introduction

It's plain that common dialogs are only going to meet common needs and there are many occasions when we need to build custom dialogs.

It isn't particularly difficult to build custom dialogs but it can be complex depending on the approach you take and most of the initial complexity comes from actually designing the look of the custom dialog box, for example where controls will be located and what the sizes of the controls will be. We first look at doing it the hard way by hard-coding the dialog box appearance.

There are much better ways which involve using resource tools like Julian Smart's Dialog Editor and/or Robert Roebling's wxDesigner. Dialog Editor is distributed with wxWindows, wxDesigner is a shareware product and is well worth the few dollars it costs. You can go a fair way with Dialog Editor but the differences between the two are quite significant and I very much recommend getting wxDesigner.

Using a Custom Dialog

First Custom Dialog

Here is a very simple dialog box, it contains three controls, a text control and two buttons. The dialog box itself has a location on screen relative to its parent window and a height and a width. Each of the controls has a location relative to the dialog which is the parent window of the controls, and each of the controls has a size.

First I'll show you how we use it then we can look at the beast in detail.

void BasicFrame::OnAbout(wxCommandEvent & event )
{  
	BasicDialog aboutDialog ( this, -1, _("Your very own dialog"),
	                          wxPoint(100, 100), wxSize(200, 200) );
	if ( aboutDialog.ShowModal() != wxID_OK )
		dialogText->AppendText(_("The about box was cancelled.\n"));
	else
		dialogText->AppendText(aboutDialog.GetText());
}

Here you can see how we call the dialog. The dialog is instantiated in the BasicFrame's About method.

To use it we:

  • Construct the dialog, setting the arguments to the constructor as appropriate: aboutdialog is of type BasicDialog.
  • We call the dialog's ShowModal method which displays the dialog. We could call Show() in which case the dialog wouldn't hijack the focus but most dialogs are meant to be used modally, i.e. when a modal dialog is displayed we can't shift the input focus to anything else in the application.
  • We get a return status which we test. If the ShowModal method returns a value which is the same as wxID_OK we do one thing, if it isn't we do something else.
  • We then use the values held by the dialog text control.

As you can see the usage of the dialog is no different from any other dialog.

Building a Custom Dialog

class BasicDialog: public wxDialog
{
public:

	BasicDialog ( wxWindow * parent, wxWindowID id, const wxString & title,
	              const wxPoint & pos = wxDefaultPosition,
	              const wxSize & size = wxDefaultSize,
	              long style = wxDEFAULT_DIALOG_STYLE );

	wxTextCtrl * dialogText;
	wxString GetText();

private:

	void OnOk( wxCommandEvent & event );

	DECLARE_EVENT_TABLE()
};

BasicDialog is descended from wxDialog and a dialog needs the following for its construction:

  • A parent window: The dialog must belong to something.
  • An ID: This can be something determined by the programmer or it can be -1 in which case a default value will be chosen.
  • A title: Simply a wxString.
  • A position relative to the parent.
  • A size.
  • A style.

The custom dialog can also have one other construction parameter inherited from wxDialog and that is a name. This property has limited, if any, use in Windows.

The implementation of the custom dialog is in basic.cpp.

BasicDialog declares two public members apart from its constructor. There is a text control and a member function which returns a string. BasicDialog also declares a private member OnOk() and an event table.

BasicDialog::BasicDialog ( wxWindow * parent, wxWindowID id, const wxString & title,
                           const wxPoint & position, const wxSize & size, long style )
: wxDialog( parent, id, title, position, size, style)
{
	wxString dimensions = "", s;
	wxPoint p;
	wxSize  sz;

	sz.SetWidth(size.GetWidth() - 20);
	sz.SetHeight(size.GetHeight() - 70);

	p.x = 6; p.y = 2;
	s.Printf(_(" x = %d y = %d\n"), p.x, p.y);
	dimensions.append(s);
	s.Printf(_(" width = %d height = %d\n"), sz.GetWidth(), sz.GetHeight());
	dimensions.append(s);
	dimensions.append(AUTHOR);

	dialogText = new wxTextCtrl ( this, -1, dimensions, p, sz, wxTE_MULTILINE );

	p.y += sz.GetHeight() + 10;
	wxButton * b = new wxButton( this, wxID_OK, _("OK"), p, wxDefaultSize );
	p.x += 110;
	wxButton * c = new wxButton( this, wxID_CANCEL, _("Cancel"), p, wxDefaultSize );
}

To break this down into more managable parts...

First, we have the constructor which inherits from wxDialog.

BasicDialog::BasicDialog ( wxWindow * parent, wxWindowID id, const wxString & title,
                           const wxPoint & position, const wxSize & size, long style )
: wxDialog( parent, id, title, position, size, style)

We then declare some local variables. p and sz will used to help layout the positions and sizes of controls in the dialog. You should read about the WxPoint and wxSize classes in the wxWindows help.

wxString dimensions = "", s;
wxPoint p;
wxSize  sz;

sz.SetWidth(size.GetWidth() - 20);
sz.SetHeight(size.GetHeight() - 70);

We set some initial position values in p and also use the Printf method of wxString to format a message.

p.x = 6; p.y = 2;
s.Printf(_(" x = %d y = %d\n"), p.x, p.y);
dimensions.append(s);
s.Printf(_(" width = %d height = %d\n"), sz.GetWidth(), sz.GetHeight());
dimensions.append(s);
dimensions.append(AUTHOR);

A text control is added to the dialog, it contains whatever the string dimensions contains and is postioned and size according to p and sz.

dialogText = new wxTextCtrl ( this, -1, dimensions, p, sz, wxTE_MULTILINE );

Now we adjust p, create a button b, adjust p again and create a button c. Note that wxID_OK and wxID_CANCEL are used. These are default ID's.

p.y += sz.GetHeight() + 10;
wxButton * b = new wxButton( this, wxID_OK, _("OK"), p, wxDefaultSize );
p.x += 110;
wxButton * c = new wxButton( this, wxID_CANCEL, _("Cancel"), p, wxDefaultSize );