C++ GUI Programming for MS Windows

The previous post, Win32 or UWP? looked at some of the advantages and disadvantages of developing C++ applications for either of those two frameworks. This post provides a high-level look at a number of toolkits for GUI programming in C++ for those frameworks. I have no intention of covering all toolkits, only the ones I have used, or contemplated using for more than a few minutes. See Wikipedia for a larger list of GUI toolkits.

MS Windows-Only APIs and Toolkits

Microsoft has provided a number of toolkits and APIs for developing C++ applications on Win32 and UWP. The oldest ones are for Win32 development and the newest ones are for UWP. Because Win32 has been around a much longer time, there are more toolkits for developing Win32 applications than for developing UWP applications. Let’s look at a few.

Win32

Any mentions of Win32 in this post also refer to Win64, the 64-bit equivalent of Win32.

Windows API

The Windows API (sometimes referred to as Win32 API) is a C-based library that has been around since the days of Windows 1.0 (originally Win16). This was the first toolkit used to build Windows applications and still remains somewhat popular today, especially for C applications. However, being a C interface, it tends to be long-winded; for example, the first Hello World application built using Win16 required only 150 lines of code.

I would recommend looking at one of the C++ toolkits instead.

MFC

MFC, the Microsoft Foundation Classes, was released in 1992 as a very thin wrapper around the Windows API. MFC is still available in various versions of Visual Studio, though it was previously not included in Visual Studio Express versions.

While some people still develop applications using MFC, and of course there is a large number of legacy MFC applications, there are now better choices available for developing new applications.

WTL

WTL, the Windows Template Library, was developed originally for use internally by Microsoft, and was later released as an unsupported add-on to Visual Studio. WTL provides a light-weight alternative to MFC.

I have not used WTL so I can’t comment on it, other than it is now available as a download from Sourceforge.

Others

A number of other Win32-specific toolkits have come and gone. As an alternative to any of the toolkits mentioned above, you may wish to consider one of the cross-platform toolkits which are listed in a section below.

UWP

Universal Windows Platform is Microsoft’s new framework for building Windows programs. Unlike Win32, which is limited to running on x64/x64 processors, UWP applications can also be built to run on ARM processors. This opens UWP applications up to running on desktops, laptops, tablets, XBox systems, HoloLens systems, Windows phones, and any other hardware that runs Windows 10.

UWP uses the Windows RunTime architecture (WinRT). WinRT provides a set of APIs that expose all of the functionality of Windows 10 to developers. See the Wikipedia entry for more information. .Net and the Common Language Runtime (CLR) are a subplatform of the Windows Runtime.

C++/CX

C++/CX is a set of extensions to Visual C++ for building UWP applications. This greatly reduces the amount of plumbing code required to interface to WinRT, but at the expense of unfamiliar code syntax. All functionality exposed by WinRT can be programmed using C++/CX. C++/CX supports using XAML to define a program’s user interface.

WRL

The Windows Runtime C++ Library (WRL) provides a low-level interface to the Windows Runtime. There is more boiler-plate code than in C++/CX, but at least it is standard, though not modern C++. For example, there are no modern types and no move semantics.

C++/WinRT

C++/WinRT is a standard C++ language projection implemented entirely as a set of header files. It does not use language extensions like C++/CX does, and avoids the complexity, verbosity, and tediousness of WRL.

One disadvantage is that XAML is not currently supported; XAML will be provided in a later version.

Cross Platform Toolkits

All of the toolkits mentioned below have been under active development for 20 or more years. They were started before C++98; to support backwards compatibility, they all suffer from a number of limitations. For example:

  • No namespaces;
  • Use raw pointers rather than smart pointers; and
  • Pass parameters as raw pointers rather than references.

There are many other limitations, but you get the idea.

wxWidgets

wxWidgets is the only toolkit that uses native libraries to create and display windows and widgets. On Windows, wxWidgets uses Win32, on OSX it uses Cocoa, and on Linux and other Unix-like systems it uses gtk+. Attempts were made to produce ports for both Android and iOS, but they never got past the pre-alpha stage.

gtkmm

gtkmm is a C++ wrapper around gtk+. gtk+ is the C API that is used on the Gnome desktop for Linux and Unix-like operating systems. It has been ported to Windows and OSX, and generally works well but with a few limitations on the fringes. For example, see my comments about printing and printer properties in Adventures in Cross-Platform GUI Programming and Printing.

Qt

Qt is available for the largest number of operating systems: Win32 and WinRT, OSX, Linux and many Unix-like OSes, Android, iOS, and embedded operating systems. Qt is the API used for the KDE desktop which runs on Linux and many Unix-like OSes. It is the oldest and best supported of the cross-platform toolkits. It is under constant development.

fltk

The Fast Light Toolkit is the lightest of the toolkits mentioned here. It provides only GUI functionality and does not provide helper classes like the toolkits mentioned above. The look and feel of its widgets is somewhat reminiscent of Motif from the 1990’s.

fltk is available for Win32, OSX, and Linux.

Others

Other toolkits are either lesser known or created for specific purposes, such as toolkits for gaming and toolkits that use and are designed for use with OpenGL, and in some cases, Vulkan.

What Have I Used?

All of my programming in the last 3 years or so has been on MS Windows systems, with most programs using wxWidgets for the GUI. In the past, I programmed using gtkmm and the Win32 API. More than 20 years ago I used MFC. I have also programmed GUIs in other languages, but they are not the topic of this post.

Summary

This post has provided a list and overview of a number of toolkits that can be used to program GUIs on computers running MS Windows. Hopefully I have provided sufficient information for you to limit the amount of investigation you need to do to select a GUI toolkit that is appropriate for your new applications.

Additional Information

Additional information on each of the platforms and toolkits may be obtained from the following links:

 

 

 

Vulkan with wxWidgets

Alexander Overvoorde wrote a good tutorial for programming Vulkan; this is available at vulkan-tutorial.com. In the tutorial, he used GLFW as the windowing system. This is fine if your application uses one main window with no adornments such as menus and status bars, and no additional windows.

I have modified the Hello Triangle example to use wxWidgets. This corresponds to the code up to the end of the Drawing a triangle section of the tutorial. The source code of my wxWidgets version is available on GitHub.

Here is a description of the changes:

  1. HelloTriangleApplication code is split among VulkanTutorialApp, VulkanWindow, and VulkanCanvas. The vast majority of the code is placed in VulkanCanvas. Specifically, the code in HelloTriangleApplication::run is split into two parts:
    • The line:
      mainloop()

      is handled automatically by VulkanTutorialApp, and to some extent by VulkanWindow.

    • The functionality in initWindow and initVulkan are performed in the VulkanCanvas constructor.
  2. The HelloTriangleApplication::drawFrame code is placed in VulkanCanvas::OnPaint.
  3. The HelloTriangleApplication::onWindowResized code is placed in VulkanCanvas::OnResize. wxWindow::RefreshRect must be called to ensure that the canvas is redrawn every time the window is resized. Calling wxWindow::Refresh or wxWindow::Updateonly causes a redraw to occur when the window grows in size, not when shrinking is size.
  4. Two changes were made regarding exceptions:
    • In the tutorial code, runtime_error exceptions are thrown whenever Vulkan errors are encountered. These are replaced with a new exception type called VulkanException which provides information about the actual Vulkan error that was encountered.
    • The tutorial code simply outputs text messages to std::cout. Because the wxVulkanTutorial code is Windows-based, there is no console to output the messages to, so they are output to a wxMessageBox. This was discussed previously in the post C++ Exceptions and wxWidgets.
  5. The tutorial code contains a templated class called VDeleter. This class automatically handles the destruction of various Vulkan handles. I have not included this class in wxVulkanTutorial. Instead, I destroy the handles in the VulkanCanvas destructor.

Have fun with it.

C++ Exceptions and wxWidgets

I have been working on a project to port a set of Vulkan tutorials from using GLFW as the windowing system to using wxWidgets. The code in the original tutorials throws std::runtime exceptions whenever there are unrecoverable Vulkan errors. These exceptions are caught in the program’s main function where the exception’s message is sent to cerr and the program is immediately terminated by returning a value from main. wxWidgets doesn’t work that way!

Here is the code from the first tutorial (original with GLFW, not wxWidgets):

int main() {
    HelloTriangleApplication app;

    try {
        app.run();
    } catch (const std::runtime_error& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

There are two problems with this approach when using wxWidgets:

  1. wxWidgets uses the platform’s native API so on Windows systems, that means that wxWidgets applications are Win32 GUI applications. Win32 GUI applications do not by default have a console, so, again by default, outputting to cerr does nothing.
  2. wxWidgets hides the main function and much of the program and GUI initialization. Instead, wxWidgets provides wxApp::OnInit, a method that should be overridden to perform initialization including creating a top-level main window. wxApp::OnExit may be overridden to delete any wxWidgets objects that are not tied to top-level windows. Following the return from OnInit, wxWidgets the calls wxApp::OnRun to enter the main loop. OnRun is not normally overridden.

So, what do we do? It is possible to create a console from a Win32 application and to tie cerr to output to the console. This is not typical of Win32 applications, so it will not be discussed further. A better approach for unrecoverable Vulkan and other exceptions is to display a message box containing exception information and then to terminate the application. Additionally, information could be output to a logging file if desired.

wxWidgets provides an overview document for using exceptions with wxWidgets. The document recommends handling exceptions in the following locations in order of preference:

  1. In a try/catch block inside an event handler.
  2. In wxApp::OnExceptionInMainLoop().
  3. In wxApp::OnUnhandledException().

In my port of the tutorials, a large amount of Vulkan initialization occurs in OnInit, so it will be necessary to handle exceptions there, inside a try/catch block. The rest of the Vulkan code is called from the wxEVT_PAINT handler (OnPaint in my case).

Here is my code from OnInit:

bool VulkanTutorialApp::OnInit()
{
    VulkanWindow* mainFrame;
    try {
        mainFrame = new VulkanWindow(nullptr, wxID_ANY, L"VulkanApp");
    } 
    catch (const std::runtime_error& err) {
        // process runtime_error exception
        // terminate application
        ...
    }
    mainFrame->Show(true);
    return true;
}

Even though wxWidgets has not yet called wxApp::OnRun, a message box can still be displayed and processed before the application terminates.

And here is a bit of code from the Vulkan canvas’s OnPaint method:

void VulkanCanvas::OnPaint(wxPaintEvent& event)
{
    try {
        // paint the image on the canvas using Vulkan
        ...
    } catch(const std::runtime_error& err) {
        // process runtime_error exception
        /// then terminate program
        ...
    }

How do we display a message box and possibly log information to a file? wxWidgets provides a set of wxLog* functions. See the logging overview for information on these functions. The default action for wxLogError is to display a message box with the error information. wxLogFatalError calls wxLogError then calls abort. Since we want to terminate the application after displaying the error information, wxLogFatalError would at first glance appear to be a good choice. Alternatively, we could call wxMessageBox to display the error information and then terminate the application ourselves.

Using wxLogFatalError in OnInit is overkill because simply returning false will result in wxWidgets cleaning up and terminating the application. Specifically, the destructors for all created objects are called and the memory associated with the objects is released.

Here is my code for OnInit:

bool wxVulkanTutorialApp::OnInit()
{
    VulkanWindow* mainFrame;
    try {
        mainFrame = new VulkanWindow(nullptr, wxID_ANY, L"VulkanApp");
    } 
    catch (std::runtime_error& err) {
        wxMessageBox(err.what(), "Vulkan Error");
        return false;
    }
    mainFrame->Show(true);
    return true;
}

wxLogFatalError may still be useful in the OnPaint method, but keep in mind that it calls abort. abort immediately terminates the program without necessarily calling all object destructors and freeing any associated memory. On program termination, Microsoft Windows will free any memory associated with the application, and also release any OS resources (file handles, window handles, etc.) associated with the program. But the operating system does not know about any Vulkan resources and handles that the application may have obtained and therefore, these are not released; they will stay around until the computer is restarted.

So wxLogFatalError does not appear to be a good choice in OnPaint either. This leaves us with wxLogError or wxMessageBox calls and some method to terminate the application. As mentioned above, messages sent to wxLogError display the messages in a message box by default; however, the messages may be redirected elsewhere, such as to a log file. Because I want to always display the messages on screen, I have chosen to use wxMessageBox. wxApp::ExitMainLoop() tells wxWidgets to exit the main loop, which eventually terminates the application cleanly. Let’s try that; the catch block in OnPaint will look like this:

    catch(const std::runtime_error& err) {
        wxMessageBox(err.what(), "Vulkan Error");
        wxTheApp->ExitMainLoop()
    }

To test this, I modified OnPaint to throw a runtime_error. Hmm, no message box is displayed, the program does not terminate, and the program becomes unresponsive. A bit of time using the debugger shows that as soon as the wxMessageBox call is reached, wxWidgets returns control to the message loop which again calls OnPaint, which calls wxMessageBox, which returns control to the message loop which again calls OnPaint… Well, you get the idea.

We must move the calls to wxMessageBox and wxApp::ExitMainLoop outside of the OnPaint method. Prior to wxWidgets 2.9.x, this could be done by creating a new event type, and defining a handler to process that event. In OnPaint, we would queue the event to be processed. wxWidgets 3.x provides the CallAfter method to simplify this. Let’s create a new method called OnPaintException to display the error information and terminate the program:

void VulkanCanvas::OnPaintException(const std::string& msg)
{
    wxMessageBox(msg, "Vulkan Error");
    wxTheApp->ExitMainLoop();
}

Now the catch block in OnPaint would look like this:

    catch (const std::exception& err) {
        CallAfter(&VulkanCanvas::OnPaintException, err.what());
    }

CallAfter adds an event to be processed once OnPaint returns. Only then is OnPaintException called. The call to ExitMainLoop causes the application to terminate normally.

Rerunning our test with OnPaint generating a runtime_error exception, the message box is displayed and the program then terminates normally.

HelloTriangle

The first program that you typically write in any programming language is HelloWorld, where you simply print out the words: “Hello World!” to the console. When you graduate to using a windowing toolkit, the Hello World program displays a window with “Hello World!” in it. The post Creating wxWidgets Programs with Visual Studio 2015 – Part 2 gives an example using wxWidgets. In OpenGL, about the simplest program you can write is HelloTriangle which displays a white triangle on a black background; there is no text. I will develop HelloTriangle in this post.

HelloTriangle will be developed using Visual Studio 2015, wxWidgets, and OpenGL. Actually, Visual Studio is simply the development environment used by me. You could in fact use any environment you want provided it supports wxWidgets and GLEW (for OpenGL).

To begin, we need to create a bare-bones wxWidgets application. This is discussed in Creating wxWidgets Programs with Visual Studio 2015 – Part 1. Call the project HelloTriangle. Change MyProjectApp to HelloTriangleApp. Once you have that program working, you should install the NuGet package called nupengl.core, to include GLEW. Alternatively, you could simply install GLEW on your system and use that. Installing nupengl.core is discussed in Visual Studio, wxWidgets, and OpenGL. Once this is done, we have all of the parts needed to begin coding HelloTriangle.

This post will follow along with the tutorials at open.gl. In the tutorials on that website, the Context creation page shows how to set up an OpenGL program using SFML, SDL, and GLFW. We will use wxWidgets instead. The Drawing polygons page shows how to draw a triangle and then colour the triangle using vertex shaders and fragment shaders. We will not be using shaders; this post simply draws a white triangle on a black background. The code shown in this post can then be modified to use shaders.

If you have followed the steps above, you have a very simple program that simply displays an empty window. This will now be modified. We will add two new classes, called TriangleWindow and TriangleCanvas.

TriangleCanvas subclasses wxGLCanvas. wxGLCanvas is the wxWidgets class that displays OpenGL graphics. In the TriangleCanvas class, we will initialize OpenGL, create the wxGLContext required for OpenGL, and set up the graphics for drawing in the constructor. The paint event handler will paint the background and the triangle. This code is in the OnPaint method. Finally, the destructor does some clean up.

Here is the header file for TriangleCanvas:

#pragma once
#include <memory>
#include "wx/glcanvas.h"

class TriangleCanvas : public wxGLCanvas
{
public:
    TriangleCanvas(wxWindow* parent, wxWindowID id = wxID_ANY,
        const int* attribList = 0, const wxPoint& pos = wxDefaultPosition,
        const wxSize& size = wxDefaultSize, long style = 0L,
        const wxString& name = L"GLCanvas",
        const wxPalette& palette = wxNullPalette);

    virtual ~TriangleCanvas();
    TriangleCanvas(const TriangleCanvas& tc) = delete;
    TriangleCanvas(TriangleCanvas&& tc) = delete;
    TriangleCanvas& operator=(const TriangleCanvas& tc) = delete;
    TriangleCanvas& operator=(TriangleCanvas&& tc) = delete;

private:
    void InitializeGLEW();
    void SetupGraphics();
    void OnPaint(wxPaintEvent& event);

    std::unique_ptr<wxGLContext> m_context;
    GLuint m_vbo; // vertex buffer pointer
    GLuint m_vao; // vertex array pointer
};

The private methods InitializeGLEW and SetupGraphics are helper methods that are called in the constructor. m_context holds the OpenGL context and m_vbo and m_vao are properties used by OpenGL.

Here is the constructor:

TriangleCanvas::TriangleCanvas(wxWindow* parent, wxWindowID id, 
        const int* attribList, const wxPoint& pos, const wxSize& size,
        long style, const wxString& name, const wxPalette& palette)
	: wxGLCanvas(parent, id, attribList, pos, size, style, name, palette),
	m_vbo(0), m_vao(0)
{
	m_context = std::make_unique<wxGLContext>(this);
	Bind(wxEVT_PAINT, &TriangleCanvas::OnPaint, this);
	
	SetCurrent(*m_context);
	InitializeGLEW();
	SetupGraphics();
}

This code is straight-forward. It creates an OpenGL context for the TriangleCanvas, and then binds the OnPaint method to the paint event. Following this, the OpenGL context is set and the two helper methods are called to complete the initialization. The helper methods will only succeed if the context has been set.

InitializeGLEW simply initializes the GLEW so that the OpenGL methods can be accessed. The method is shown here:

void TriangleCanvas::InitializeGLEW()
{
	glewExperimental = true;
	GLenum err = glewInit();
	if (err != GLEW_OK) {
		const GLubyte* msg = glewGetErrorString(err);
		throw std::exception(reinterpret_cast<const char*>(msg));
	}
}

glewInit() must be called to obtain information on the supported extensions from the graphics driver. Experimental and pre-release drivers may not report every available extension through the standard call to glewInit; in that case, GLEW will report that the extension is not supported. By setting glewExperimental to true (or GL_TRUE) before calling glewInit, all of the extensions are exposed.

Following the call to glewInit, the code checks the status returned from the glewInit call, and throws an exception if the call failed. I have not included any code in this program to catch the exception, so the program will simply terminate. Catching the exception is left as an exercise for the reader.

This is the code for the SetupGraphics method:

void TriangleCanvas::SetupGraphics()
{
	// define vertices
	float points[] = {
		0.0f, 0.5f,
		0.5f, -0.5f,
		-0.5f, -0.5f
	};
	// upload vertex data
	glGenBuffers(1, &m_vbo);
	glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
	// setup vertex array objects
	glGenVertexArrays(1, &m_vao);
	glBindVertexArray(m_vao);
	glEnableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
}

I will not provide an explanation of this code; it is available on the Drawing polygons page on open.gl.

The glGenBuffers and glGenVertexArrays calls in the code above allocate buffers on the graphics card. These buffers must be released before the program terminates or a memory leak will result. The code in the TriangleCanvas destructor performs this task:

TriangleCanvas::~TriangleCanvas()
{
	SetCurrent(*m_context);
	glDeleteVertexArrays(1, &m_vao);
	glDeleteBuffers(1, &m_vbo);
}

All of the drawing is performed in the OnPaint method:

void TriangleCanvas::OnPaint(wxPaintEvent& event)
{
	SetCurrent(*m_context);

	// set background to black
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	// draw the graphics
	glDrawArrays(GL_TRIANGLES, 0, 3);
	// and display
	glFlush();
	SwapBuffers();
}

This code is quite simple. The context is set. the glClearColor and glClear calls set a black background, and glDrawArrays draws the triangle. glFlush is called to force the drawing to the backup buffer, and SwapBuffers swaps the buffers to display the buffer that OnPaint just drew on.

That completes the TriangleCanvas.cpp file except for the preprocessor directives at the top of the file:

#include "wx/wxprec.h"
#include <GL/glew.h>
#include "TriangleCanvas.h"

#pragma comment(lib, "glew32.lib")

The TriangleWindow class is very simple. All it does is create a TriangleCanvas object and attach it to the window. Here is the content of TriangleWindow.h:

#pragma once

class TriangleWindow : public wxFrame
{
public:
	TriangleWindow(wxWindow* parent, const std::wstring& title, const wxPoint& pos = wxDefaultPosition,
		const wxSize& size = wxDefaultSize);
	virtual ~TriangleWindow();
	TriangleWindow(const TriangleWindow& tw) = delete;
	TriangleWindow(TriangleWindow&& tw) = delete;
	TriangleWindow& operator=(const TriangleWindow& tw) = delete;
	TriangleWindow& operator=(TriangleWindow&&) = delete;
};

and here is the content of TriangleWindow.cpp:

#include "wx/wxprec.h"
#include "TriangleCanvas.h"
#include "TriangleWindow.h"

const int triCanvasID = 2000;			// TriangleCanvas widget ID

TriangleWindow::TriangleWindow(wxWindow* parent, const std::wstring& title, const wxPoint& pos,
	const wxSize& size)
	: wxFrame(parent, wxID_ANY, title, pos, size, wxMINIMIZE_BOX | wxCLOSE_BOX | 
		wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN)
{
	TriangleCanvas* canvas = new TriangleCanvas(this, triCanvasID, nullptr, { 0, 0 },
	{ 800, 800 });
	Fit();
	Centre();
}

TriangleWindow::~TriangleWindow()
{
}

Displaying the window with the triangle requires only two changes to HelloTriangleApp.cpp. Add a #include directive for TriangleWindow.h, and replace the first line of HelloTriangleApp::OnInit with

	TriangleWindow* mainFrame = new TriangleWindow(nullptr, L"Hello Triangle!");

Now build and run the application. Here is the resulting window:

HelloTriangle

That’s all there is to it.

Visual Studio, wxWidgets, and OpenGL

The immediately previous post discussed OpenGL and many potential libraries and windowing toolkits that work with OpenGL. In this post, I will look at what I use for OpenGL programming on Windows 10 desktop:

  • Visual Studio 2015 Community Edition;
  • wxWidgets; and,
  • GLEW, the OpenGL Extension Wrangler.

The selection of a development environment is very much a personal choice. After using a number of batch build methods and Integrated Development Environments over the last few years, I have settled on Visual Studio as the best choice for me. It contains a C++ compiler that is C++14 compatible and even has the C++17 features that have been approved by the C++ Standards Committee. Visual Studio 2015 also integrates git for source control, and unit testing via Microsoft Unit Test Framework. There is a memory leak detector included in Debug mode. Note that the leak detector only works on the memory allocated on the CPU and does not detect memory leaks in the GPU.

I will be developing some complex applications, so one of the Standard Windowing Toolkit mentioned in my post on OpenGL Graphics, or something similar is required. Since I develop on Windows 10 for the desktop, then any of the standard toolkits will work. Win32 is a C interface that requires a lot of coding to perform any windowing tasks. MFC is a thin shell over Win32. While it is C++, it predates C++99 and retains many of the C structures used in Win32. The other full C++ windowing toolkits, wxWidgets, Qt, and GTKMM, are all multi-platform, and more advanced and C++ friendly than MFC; any one of them would work.

I chose wxWidgets because it is the only one of the multi-platform toolkits that displays using the native look and feel on Windows. Being multi-platform, it has the advantage over the Windows only toolkits in that any code I develop can be easily ported to other operating systems and windowing systems.  It can even be used atop GTK+ on Windows desktops, although that seems to be counter-productive.

Using wxWidgets with Visual Studio is covered in three posts on this blog:

gl.h declares OpenGL 1.1 functions, many of which have been deprecated. It has been supplemented with glu.h and glaux.h, which have also been deprecated. In order to access the full functionality of the OpenGL API as supported by your graphics card, a loading library is required. I use GLEW because it is easily installed for use with Visual Studio, and a number of the tutorials online use it. The OpenGL functions are directly callable, unlike some of the other loading libraries that require you to call a function to retrieve a pointer to the requested function before calling the function. Source code and 32- and 64-bit binaries for GLEW are available for Windows on Sourceforge. Alternatively, GLEW is included along with FreeGLUT and FLFW in a NuGet package called nupengl.core.

Before loading nupengl.core, you must first create a simple wxWidgets project. The process for this is described in Creating wxWidgets Programs with Visual Studio 2015 – Part 1. Select the platform you are building your application for (x86 or x64), and build the project. Once you have done this, you can install nupengl.core. To do this, select the solution in the Solution Explorer, then select the Tools->NuGet Package Manager->Manage NuGet Packages for Solution... menu item. This opens the Nuget – Solution tab shown below:

nupengl

Select the nupengl.core package, then select the projects that you want to include the package in (Hello Triangle in this case). Now click the Install button to install the nupengl.core. nuplegl.core.redist is installed at the same time as nupengl.core, so there is no need to install it explicitly.

You are now ready to create your first OpenGL application. That is the topic of the next post.

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.