Programming with wxWidgets

in utopian-io •  7 years ago  (edited)

Let's roll up our sleeves and get started with wxWidgets. You can find the library at the official wxWidgets Web site here. Today, I'll be focusing on development under Windows, but next time around I'll move over to Mac OS X and take a look at things from that perspective. When getting to grips with a new class library, it's a good idea to at least confine your learning experience to a familiar platform, rather than changing too many variables at once.

image.png

Installing wxWidgets Go to the download page on the aforementioned website and acquire the latest stable version rather than a beta. At the time of writing, this is version 3.1.0. You'd also be wise to download the setup.exe version of the file rather than the ZIP archive. The file I downloaded was called wxMSW-3.1.0-Setup.exe, which was around 17MB in size.

Once you run the setup program, you'll end up with a library install into c:\wxWidgets-3.1.0. Be warned that wxWidgets is sensitive to spaces in the pathname, so just accept all the default option settings if you can; amongst other things, this will ensure that the library gets installed into a suitable path. You also need to decide which development system and compiler you're going to use. If you were paying attention last month, you'll know that Visual C++ is not a great choice, despite what the wxWidgets documentation tells you. This tool is now so long in the tooth that it will happily trample on a VS.NET installation from a great height. If I'd read the documentation more carefully before installing VC++, I would have realised that you can actually build wxWidgets projects quite happily with VS.NET, and that's exactly what I've done here. But there are other possibilities.

Building the library

With VS.NET running, choose 'Open Project' and navigate to the C:\wxWidgets-3.1.0\build\msw directory (I'm assuming the default pathname from now on), where you'll find a file called wx.dsw. Open this file in VS.NET and the IDE will complain that it needs to update the project to a more recent format. Just click the 'Yes to all' button and let it get on with it. When the IDE is finished, build the solution. This process takes a couple of minutes as the entire library has to be rebuilt. Stick with a debug build for now.

And that's it. Now that the library is built, we can go ahead and try out one of the many sample projects included with wxWidgets. I randomly selected the rotate sample which you can find here: c: \ wxWidgets-2.6.0 \ samples \ rotate \ rotate.dsw. As before, navigate to this project file from within VS.NET, open the project and you'll get asked to convert it to the new format. Once you've built the program, you should be able to run it and be rewarded with something like the screenshot shown on the left. Be sure to copy the kclub.bmp file from the solution directory into the actual vc_mswd directory before running the executable. If you don't, you'll get a rude error message. Note that naming conventions for these build directories are relatively straightforward. The 'vc_' prefix obviously represents Visual C++, the 'msw' tag stands for Microsoft Windows and the 'd' indicates a debug build.

DLL vs static builds?

As it stands, the rotate.exe file weighs in at around 2MB, but this can be substantially reduced by doing a release build. A more important issue is whether to create DLL or static builds of the library. With a DLL build, you've got the advantage of very small executable size, but the EXE file obviously won't work unless the wxWidgets DLL is accessible via the PATH environment variable. Also, the DLL contains every possible function within wxWidgets and will therefore be quite large. On the other hand, statically linking the library results in a larger executable, but only those parts of the library which are really needed get linked in. Most importantly, deployment issues are minimised because the program is completely stand-alone. In these days of fast broadband connections and large hard disks, there's little reason not to link statically, and that's what we're doing here.

Let's take some time to look at the structure of a typical wxWidgets program. The first thing you'll need to do is create an instance of the wxApp class which, as the name suggests, is an OOP encapsulation of the entire program. Inside this declaration, you'll almost always want to override the OnInit method like this:

class MyApp: public wxApp
{
public: virtual bool OnInit(); 
};

wxWidgets applications don't have a traditional main entry point (well, actually, they do, but it's hidden from the casual wxWidgets developer), but use OnInit instead. This is where you'll typically do all your once-only program initialisation. In the case of the rotate sample, it kicks off by creating a new wxImage object to hold the king of clubs bitmap. More importantly, it's inside the OnInit method that we create an instance of the application's main window. This is done by deriving a new class from wxFrame and instantiating it inside OnInit. A minimalist implementation of OnInit might look something like the following code:

bool MyApp::OnInit() 
{
MyFrame *frame = new MyFrame(_T ("My First App"), wxPoint (25,25), wxSize (100, 100));
frame->Show (TRUE);
SetTopWindow (frame);
return TRUE; 
}

This code assumes that we've derived a new class from wxFrame called MyFrame. It creates an instance of this frame, passing a caption string which is used as the window title. You'll notice from the presence of the _T macro that wxWidgets is Unicode compatible. The second constructor parameter specifies the initial location of the window and the third provides its initial window size.

Once the frame has been created, it's made visible using the Show method, set as the topmost window in the application and then the OnInit method exits with 'true' as the function result. This is important because if any of the program's one-time initialisation fails, it should return 'false' as the function result. In these circumstances, the program quits immediately without showing a main window.

Event handling in wxWidgets

In a wxWidgets application, event handling uses a similar technique to that traditionally used by programmers using Microsoft's MFC frameworks. This is based around a so-called event map. It's a specialised type of macro which is used to map specific event handlers to their corresponding events. Although it's not as simple to use as the RAD-based mapping in Delphi (for example), it doesn't require any support within the IDE itself, and this makes it inherently more portable. An event table for a frame (window) might look like this:

BEGIN_EVENT_TABLE (MyFrame, wxFrame)
EVT_MENU(ID_QUIT, MyFrame::OnQuit)
EVT_MENU(ID_ABOUT, MyFrame::OnAbout)
EVT_MOVE (MyFrame::OnMove)
END_EVENT_TABLE()

This might look a bit messy from a Delphi programmer's perspective, but having dabbled with Objective-C on the Mac, I appreciate it a lot more than I did in the past. Each entry in the maps an event to an event handler. Thus, an ID_QUIT notification calls the MyFrame::OnQuit method to be invoked. ID_QUIT, incidentally, is just a unique numerical identifier assigned by you, the developer. The actual OnQuit method might be as simple as this – it just closes the form in response to the command event:

void MyFrame::OnQuit (wxCommandEvent& WXUNUSED(event) )
{
Close(true);
}

In order to build any half-way decent application, you obviously need an application menu. The basic idea is illustrated by the code snippet below.

wxMenu * menu = new wxMenu;
menu->Append (ID_QUIT, _T("E&xit\tAlt-X") );
wxMenuBar * menuBar = new wxMenuBar;
menuBar->Append (menu, "&File");
SetMenuBar (menuBar);

This type of code is typically placed in the constructor of your frame object. Basically, you create a new wxMenu object, one for each top level menu such as File, Edit, and Window. You populate these menus by using the Append method, passing the control identifiers to the method as well as the wanted menu text. A nice touch here is that you can provide an optional third parameter which is automatically displayed in the window's status bar if one is present. This saves a lot of messing around with status bar updates such as you'd often need in other frameworks.

Finally, you create a wxMenuBar object, add all your top-level menus to the menu bar and then call the frame's SetMenuBar method to add the menu structure to the frame. Again, it's not as simple as the RAD experience you'd get from Delphi, or VS.NET with WinForms, but it is very straightforward and the code is easy to modify.

wxWidgets is a surprisingly flexible framework once you get to grips with it. In addition to the event table approach described above, you can also explicitly link an event handler to a specific event using the Connect method of the wxFrame class. This is illustrated by the code snippet below:

MyFrame *frame = new MyFrame("Hello World", wxPoint(50,50), wxSize(450,350));
frame->Connect (ID_QUIT, wxEVT_COMMAND_MENU_ SELECTED, (wxObjectEventFunction) &MyFrame:: OnQuit );

As before, ID_QUIT is the quit event, which is tied to the MyFrame::OnQuit connect method via the Connect call.

In order to reduce download size, many of the wxWidgets distributions don't include extensive online help. This can be downloaded separately from the website in a variety of formats including straight HTML, compiled HTML (CHM files) and Adobe Acrobat format. The various ZIP files should expand into files which are installed under the C: \ wxWidgets-3.1.0 \ docs folder, which is another reason for sticking with the default setup directory: it's assumed by these supplemental ZIP files. The reference documentation is extremely extensive. In the case of the PDF documentation set, the core wx.pdf file runs to over 2,000 pages.

There's quite a lively wxWidgets community and many interesting links can be found via the Community page on the wxWidgets site. Particularly useful is wxWiki, a specialised Wiki devoted to anything relating to wxWidgets. You can find the site here. A cool feature of this site is the wxWidgets Documentation Browser. As I've said, reference documentation is available in PDF format, but I found my machine struggling to quickly search through 200 pages of documentation. The online browser, on the other hand, is much snappier at instantly finding what you want; for example, type 'wxMenu' into the class search box, hit the search button and you get a synopsis of the class followed by a hyperlinked list for each member of the class. You'd be well advised to keep this web page open in your browser during day-to-day wxWidgets development.



Posted on Utopian.io - Rewarding Open Source Contributors

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

I love wxWidgets. Excelent read thank you :) How ever i'd like to see some screenshots of the results as well. Would help a lot

Hey @folke I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

folke!! Thank you, your Post.

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Thanks.