Creating wxWidgets Programs with Visual Studio 2015 – Part 2

Part 1 of this post described how to set up your development environment for building wxWidgets-based Windows applications, and how to build a bare-bones application. This post continues the development of this application by modifying it to create a HelloWorld program.

The first step is to create a new main window class. In Solution Explorer, right click on the project name (MyProject if you are following along from part 1). Select Add->Class... from the dropdown menu to open the Add Class dialog. Double-click on C++ Class       Visual C++ to start the Generic C++ Class Wizard. Enter “HelloWindow” as the class name. Enter “wxFrame” as the base class, then select the Virtual destructor checkbox. Click the Finish button. Two new files, HelloWindow.h and HelloWindow.cpp are created and opened.

In HelloWindow.h, delete the #include directive. Add the
void OnClick(wxCommandEvent& event);
method, then add a wxStaticText* member called hello, and a wxButton* member called helloButton.


#pragma once
class HelloWindow :
    public wxFrame
{
public:
    HelloWindow();
    virtual ~HelloWindow();
    void OnClick(wxCommandEvent& event);

private:
    wxStaticText* hello;
    wxButton* helloButton;
};

In HelloWindow.cpp, add
#include "wx/wxprec.h"
as the first line in the file, and
#include "HelloWindow.h"
as the second line in the file.

Define a enumeration to contain two widget IDs, one for a wxStaticText widget, and another for a wxButton widget.

Add the following code to HelloWindow::HelloWindow(). This creates a wxStaticText widget and a wxButton widget and adds them to the window. The code also binds the OnClick method to the button click event.
hello = new wxStaticText(this, ID_STATIC, L"", { 100, 50 }, { 250, 20 });
helloButton = new wxButton(this, ID_HELLO, L"Hello", { 150, 100});
helloButton->Bind(wxEVT_BUTTON, &HelloWindow::OnClick, this);

and add the method HelloWindow::OnClick as follows:

void HelloWindow::OnClick(wxCommandEvent& event)
{
    hello->SetLabelText(L"Hello World, I want to get off.");
    helloButton->Enable(false);
}

This code sets “Hello World, I want to get off.” as the label of the wxStaticText widget and disables the button. Since this method performs the same action every time it executes and no other method sets the wxStaticText widget’s label to any other value, there is no reason to leave the button enabled.

HelloWindow.cpp should now look like this:

#include "wx/wxprec.h"
#include "HelloWindow.h"

enum {
    ID_STATIC = 2001,
    ID_HELLO
};

HelloWindow::HelloWindow() : wxFrame(nullptr, wxID_ANY, L"Hello World!")
{
    hello = new wxStaticText(this, ID_STATIC, L"", { 100, 50 }, { 250, 20 });
    helloButton = new wxButton(this, ID_HELLO, L"Hello", { 150, 100 });
    helloButton->Bind(wxEVT_BUTTON, &HelloWindow::OnClick, this);
}

HelloWindow::~HelloWindow()
{

}

void HelloWindow::OnClick(wxCommandEvent& event)
{
    hello->SetLabelText(L"Hello World, I want to get off.");
    helloButton->Enable(false);
}

Add

#include "HelloWindow.h"

below the two #include directives at the top of MyProjectApp.cpp. Change the

wxFrame* mainFrame = newwxFrame( nullptr, wxID_ANY, L"MyProject");

line in MyProjectApp::OnInit()

to

HelloWindow* mainFrame = new HelloWindow();
Build and run this program. You will get the following window:

HelloWorld1

Click the Hello button:

Hello World2

As noted above, text is displayed in the wxStaticText widget, and the wxButton is disabled.

But Aren’t There Memory Leaks?

A HelloWorld object is created on the heap in MyProjectApp::OnInit() and two widgets are created on the heap in the HelloWorld constructor, but these objects are not deleted anywhere in the code. Doesn’t that result in memory leaks?

Well, no. The wxWidgets library takes ownership of these objects and deletes them at the appropriate time. The widgets are deleted when HelloWindow is destroyed, and HelloWindow is deleted when the MyProjectApp terminates.

Now What?

The Tutorials section of the wxWidgets website contains more information about wxWidgets and how to use it.

Creating wxWidgets Programs with Visual Studio 2015 – Part 1

The information provided in this post is actually available elsewhere; I have included it here so that I can find it quickly without searching for it. (Hey, these posts are at least as much for me as they are for you!)

The previous post on this site discussed building the wxWidgets libraries using Visual Studio 2015. Now that we have the libraries available, how do we go about using wxWidgets in a program built using Visual Studio?

Prior to the First Program

Note: This section discusses setting up an environment variable that points to the wxWidgets directory. An alternative, and probably better, method to that given in this section is provided in the User-Wide Settings in Visual Studio 2015 post.

Prior to the first time that you create a wxWidgets-based project, you must set up two environment variables. For this, you need to have Administrator rights on your PC. The fastest way to create an environment variable in Windows 10 is to right-click the Start menu and select System. Now click on Advanced system settings. This opens the System Properties dialog in the Advanced tab. Click on the Environment Variables... button to open the Environment Variables dialog. Click the New... button in the User variables panel to set up an environment variable for the logged in user, or in the System variables panel for all users of the PC. This opens the New User Variable dialog or the New System Variable dialog. Enter WXWIN as the the variable name, and the directory of the top-level wxWidgets directory as the variable name. On my computer, this is C:\wxWidgets.

If you created wxWidgets DLLs, you must also add the directory containing the DLLs to the PATH variable.

Click the OK button on all three dialogs and close the System dialog.

IIRC, for Windows 8.1, you can click the Start button, select Control Panel, and follow a path similar to that stated above for Windows 10.

For Every New wxWidgets Program

Once the WXWIN environment variable has been defined, you can start Visual Studio, or restart Visual Studio if it was already running.

Now we can create a wxWidgets project. The documentation on the wxWidgets website suggests that you start by creating a Visual C++ Win32 project or by copying one of the Samples projects and modifying that. I prefer to start with an empty project: On the Start Page tab, click on New Project... or select the File->New->Project... menu item to open the New Project dialog. Select Empty Project       Visual C++ and change the project name near the bottom of the dialog. For the sake of this post, assume you have named the project MyProject. Select the Create directory for solution and Create new Git repository checkboxes as appropriate. Click the OK button to create the project. You now have a project with no source files.

The first step is to create a subclass of the wxApp class. Right-click on the project name in the Solution Explorer. Select the Add->Class... menu item to open the Add Class dialog. Double-click C++ Class Visual C++ to open the Generic C++ Class Wizard. Enter a name for the application class (e.g. MyProjectApp) in Class Name, and wxApp as the Base class name. Check the Virtual destructor checkbox and click the Finish button. At this point a message box is displayed containing the message: “Base class ‘wxApp’ not found in the project. Continue adding the class?” Click the Yes button.

Two files (e.g. MyProjectApp.h and MyProjectApp.cpp) are created and opened. Modify them to contain the following:

#pragma once

class MyProjectApp :
    public wxApp
{
public:
    MyProjectApp();
    virtual ~MyProjectApp();
    virtual bool OnInit() override;
};

 

#include <wx/wxprec.h>
#include "MyProjectApp.h"

#ifdef _UNICODE
#ifdef _DEBUG
#pragma comment(lib, "wxbase31ud.lib")
#else
#pragma comment(lib, "wxbase31u.lib")
#endif
#else
#ifdef _DEBUG
#pragma comment(lib, "wxbase31d.lib")
#else
#pragma comment(lib, "wxbase31.lib")
#endif
#endif

MyProjectApp::MyProjectApp()
{
}

MyProjectApp::~MyProjectApp()
{
}

bool MyProjectApp::OnInit()
{
	wxFrame* mainFrame = new wxFrame(nullptr, wxID_ANY, L"MyProject");
	mainFrame->Show(true);
	return true;
}

wxIMPLEMENT_APP(MyProjectApp);

Do not attempt to build this project yet. If you do, you will get the following error:
“c:\users\<username>\documents\visual studio 2015\myproject\myproject\myprojectapp.cpp(1): fatal error C1083: Cannot open file: ‘wxprec.h’: No such file or directory”.

The following instructions set up project specific include and library directories. If you will be creating a large number of wxWidgets projects, you may prefer to follow the instructions provided in the User-Wide Settings in Visual Studio 2015 post. Once you have followed those instructions, jump to the instructions for building the project given at the end of this post.

Right-click on the project name in the Solution Explorer and select the Properties menu item. This opens the MyProject Property Pages dialog. In this dialog, select the Configuration Properties->General menu item. Change the Character Set setting as appropriate. Note that the default wxWidgets builds have the Use Unicode Character Set setting, so unless you modified this in your wxWidgets build, you should set this value. Click the Apply button.

Now select the Configuration Properties->VC++ Directories->General->Include Directories item. This changes the text on the right to a dropdown list:

MyProjectPropertyPagesIncludeDirectoriesSelected

Click to open the dropdown list, and select <Edit...> to open the Include Directories dialog:

IncludeDirectoriesDialog1

Double-click in the empty scroll box at the top of the dialog (where the cursor is in the image) and enter $(WXWIN)\include. Double-click below this line and enter $(WXWIN)\include\msvc. Press Enter, and the dialog box will look like this:

IncludeDirectoriesDialog2

Click the OK button to close the Include Directories Dialog, and then the Apply button. Now select Library Directories and open the Library Directories dialog. Enter the path to the wxWidgets library files (e.g. $(WXWIN)/lib/vc_x64_dll if you created the wxWidgets x64 DLL configuration). Click the OK button to close the Library Directories dialog, and then the Apply button on the MyProject Property Pages dialog.

If you built wxWidgets as a set of DLLs, open Configuration Properties->C/C++->Preprocessor. Open the Preprocessor Definitions dialog and add the following preprocessor definition: WXUSINGDLL.

Click the OK button to close the Preprocessor Definitions dialog, and the OK button in the MyProject Property Pages dialog to apply the changes to the project and to close the dialog.

Try to build MyProject. If you performed the setup described above correctly, there will be no build errors. Now run the program; the following window will display:

MyProject

You have created your first wxWidgets program. Admittedly, it doesn’t do much, but it shows that you can create a wxWidgets program. Part 2 of this post will look at modifying this program to do something useful. For now, just close this window to terminate the program.

Visual Studio 2015 and wxWidgets 3.0.2

As I write this post, wxWidgets 3.0.2 is the latest version. The wxWidgets website provides a download for DLLs that can be used with Visual Studio 2008 – 2013.

Visual Studio 2015 is the first version of Visual Studio to support almost all features of C++11 and C++14. To use wxWidgets with VS 2015, you must build wxWidgets from source code. Downloading the source code for wxWidgets 3.0.2 and attempting to build it with VS 2015 results in a few compile errors as discussed in this forum post. You could apply the mentioned patches to the 3.0.2 source code and rebuild, but a better solution is to clone the master repository on GitHub because these changes as well as a number of new features and bug fixes are included.

Once you have cloned the wxWidgets master repository, go to the directory it was copied to, and open the file build/msw/wx_vc14.sln. Select the configuration you want to build and build it.  There will be a number of warnings generated, but these should not cause any problems.