To answer my own question, here is a minimal paint example in C++ using wxWidgets. I have mainly assembled snippets from the book Cross-Platform GUI Programming with wxWidgets which is available online for free.
The drawing is as smooth as it can get, there are no problems with mouse event frequency, as can be seen from the screenshot. Note that the drawing will be lost when the window is resized, though.
Here is the C++ source code, assumed to be in a file minimal.cpp
.
// Name: minimal.cpp
// Purpose: Minimal wxWidgets sample
// Author: Julian Smart, extended by Heinrich Apfelmus
#include <wx/wx.h>
// **************************** Class declarations ****************************
class MyApp : public wxApp {
virtual bool OnInit();
};
class MyFrame : public wxFrame {
public:
MyFrame(const wxString& title); // constructor
void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
void OnMotion(wxMouseEvent& event);
private:
DECLARE_EVENT_TABLE() // this class handles events
};
// **************************** Implementation ****************************
// **************************** MyApp
DECLARE_APP(MyApp) // Implements MyApp& GetApp()
IMPLEMENT_APP(MyApp) // Give wxWidgets the means to create a MyApp object
// Initialize the application
bool MyApp::OnInit() {
// Create main application window
MyFrame *frame = new MyFrame(wxT("Minimal wxWidgets App"));
//Show it
frame->Show(true);
//Start event loop
return true;
}
// **************************** MyFrame
// Event table for MyFrame
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
EVT_MENU(wxID_EXIT , MyFrame::OnQuit)
END_EVENT_TABLE()
void MyFrame::OnAbout(wxCommandEvent& event) {
wxString msg;
msg.Printf(wxT("Hello and welcome to %s"), wxVERSION_STRING);
wxMessageBox(msg, wxT("About Minimal"), wxOK | wxICON_INFORMATION, this);
}
void MyFrame::OnQuit(wxCommandEvent& event) {
Close();
}
// Draw a dot on every mouse move event
void MyFrame::OnMotion(wxMouseEvent& event) {
if (event.Dragging())
{
wxClientDC dc(this);
wxPen pen(*wxBLACK, 3); // black pen of width 3
dc.SetPen(pen);
dc.DrawPoint(event.GetPosition());
dc.SetPen(wxNullPen);
}
}
// Create the main frame
MyFrame::MyFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title)
{
// Create menu bar
wxMenu *fileMenu = new wxMenu;
wxMenu *helpMenu = new wxMenu;
helpMenu->Append(wxID_ABOUT, wxT("&About...\tF1"), wxT("Show about dialog"));
fileMenu->Append(wxID_EXIT, wxT("E&xit\tAlt-X"), wxT("Quit this program"));
// Now append the freshly created menu to the menu bar...
wxMenuBar *menuBar = new wxMenuBar();
menuBar->Append(fileMenu, wxT("&File"));
menuBar->Append(helpMenu, wxT("&Help"));
// ... and attach this menu bar to the frame
SetMenuBar(menuBar);
// Create a status bar just for fun
CreateStatusBar(2);
SetStatusText(wxT("Warning: Resize erases drawing."));
// Create a panel to draw on
// Note that the panel will be erased when the window is resized.
wxPanel* panel = new wxPanel(this, wxID_ANY);
// Listen to mouse move events on that panel
panel->Connect( wxID_ANY, wxEVT_MOTION, wxMouseEventHandler(MyFrame::OnMotion));
}
To build, I use the following Makefile
, but this will not work for you, since you probably don't have the macosx-app
utility. Please consult the wiki guide to Building a MacOSX application bundle.
CC = g++ -m32
minimal: minimal.o
$(CC) -o minimal minimal.o `wx-config --libs`
macosx-app $@
minimal.o: minimal.cpp
$(CC) `wx-config --cxxflags` -c minimal.cpp -o minimal.o
clean:
rm -f *.o minimal