Skip to content

WxWidgets:DeviceContexts

Draw Text

void SVMMediaPlayer::drawFireText(wxDC * dc)
{
    wxColour colour("black");
    dc->SetTextForeground(colour);
    dc->DrawText(wxT("Hello, world!"), 0, 0);
}

Draw Rect example

void SVMMediaPlayer::drawRect(wxDC * dc, wxPen & pen, int x, int y, int width, int height)
{
    // defend of reallocate (static).
    // {
    static wxRect rect;
    static wxPointList point_list;
    static wxPoint p0, p1, p2, p3;
    // }

    rect.x = x;
    rect.y = y;
    rect.width = width;
    rect.height = height;

    p0 = rect.GetBottomLeft();
    p1 = rect.GetBottomRight();
    p2 = rect.GetTopRight();
    p3 = rect.GetTopLeft();

    point_list.Clear();
    point_list.Append(&p0);
    point_list.Append(&p1);
    point_list.Append(&p2);
    point_list.Append(&p3);
    point_list.Append(&p0);

    assert(dc != NULL);
    dc->SetPen(pen);
    dc->DrawLines(&point_list);
}

Render loop

Using idle events

Pros:

  • doesn't hog the system, as it renders only when it can
  • one of the fastest ways possible in wx (on my MacBook 2GHz I get around 3500 fps with the code below)

Cons:

  • framerate is not necessarly regular
  • can stop rendering when you do something else, for instance open a menu
#include "wx/sizer.h"
#include "wx/wx.h"

class BasicDrawPane : public wxPanel
{
public:
    BasicDrawPane(wxFrame* parent);

    void paintEvent(wxPaintEvent& evt);
    void paintNow();
    void render( wxDC& dc );

    DECLARE_EVENT_TABLE()
};

class MyFrame;

class MyApp: public wxApp
{
    bool render_loop_on;
    bool OnInit();
    void onIdle(wxIdleEvent& evt);

    MyFrame* frame;
    BasicDrawPane* drawPane;
public:
    void activateRenderLoop(bool on);
};

IMPLEMENT_APP(MyApp)

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame((wxFrame *)NULL, -1,  wxT("Hello wxDC"), wxPoint(50,50), wxSize(400,200))
    {
    }
    void onClose(wxCloseEvent& evt)
    {
        wxGetApp().activateRenderLoop(false);
        evt.Skip(); // don't stop event, we still want window to close
    }
    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_CLOSE(MyFrame::onClose)
END_EVENT_TABLE()

bool MyApp::OnInit()
{
    render_loop_on = false;

    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    frame = new MyFrame();

    drawPane = new BasicDrawPane( frame );
    sizer->Add(drawPane, 1, wxEXPAND);

    frame->SetSizer(sizer);
    frame->Show();

    activateRenderLoop(true);
    return true;
}

void MyApp::activateRenderLoop(bool on)
{
    if(on && !render_loop_on)
    {
        Connect( wxID_ANY, wxEVT_IDLE, wxIdleEventHandler(MyApp::onIdle) );
        render_loop_on = true;
    }
    else if(!on && render_loop_on)
    {
        Disconnect( wxEVT_IDLE, wxIdleEventHandler(MyApp::onIdle) );
        render_loop_on = false;
    }
}
void MyApp::onIdle(wxIdleEvent& evt)
{
    if(render_loop_on)
    {
        drawPane->paintNow();
        evt.RequestMore(); // render continuously, not only once on idle
    }
}

BEGIN_EVENT_TABLE(BasicDrawPane, wxPanel)
EVT_PAINT(BasicDrawPane::paintEvent)
END_EVENT_TABLE()

BasicDrawPane::BasicDrawPane(wxFrame* parent) :
wxPanel(parent)
{
}
void BasicDrawPane::paintEvent(wxPaintEvent& evt)
{
    wxPaintDC dc(this);
    render(dc);
}
void BasicDrawPane::paintNow()
{
    wxClientDC dc(this);
    render(dc);
}
void BasicDrawPane::render( wxDC& dc )
{
    static int y = 0;
    static int y_speed = 2;

    y += y_speed;
    if(y<0) y_speed = 2;
    if(y>200) y_speed = -2;

    dc.SetBackground( *wxWHITE_BRUSH );
    dc.Clear();
    dc.DrawText(wxT("Testing"), 40, y);
}

Using a timer

Pros:

  • Regular framerate
  • Doesn't stop like idle events when you do something else, like open a menu

Cons:

  • Not as fast as idle events
  • Implementation quality depends on your platform; some platforms provide better timers than others.
#include <wx/sizer.h>
#include <wx/wx.h>
#include <wx/timer.h>

class BasicDrawPane;

class RenderTimer : public wxTimer
{
    BasicDrawPane* pane;
public:
    RenderTimer(BasicDrawPane* pane);
    void Notify();
    void start();
};

class BasicDrawPane : public wxPanel
{
public:
    BasicDrawPane(wxFrame* parent);

    void paintEvent(wxPaintEvent& evt);
    void paintNow();
    void render( wxDC& dc );

    DECLARE_EVENT_TABLE()
};

class MyFrame;

class MyApp: public wxApp
{
    bool OnInit();

    MyFrame* frame;
public:
};
RenderTimer::RenderTimer(BasicDrawPane* pane) : wxTimer()
{
    RenderTimer::pane = pane;
}
void RenderTimer::Notify()
{
    pane->Refresh();
}
void RenderTimer::start()
{
    wxTimer::Start(10);
}

IMPLEMENT_APP(MyApp)

class MyFrame : public wxFrame
{
    RenderTimer* timer;
    BasicDrawPane* drawPane;
public:
    MyFrame() : wxFrame((wxFrame *)NULL, -1,  wxT("Hello wxDC"), wxPoint(50,50), wxSize(400,200))
    {
        wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
        drawPane = new BasicDrawPane( this );
        sizer->Add(drawPane, 1, wxEXPAND);
        SetSizer(sizer);

        timer = new RenderTimer(drawPane);
        Show();
        timer->start();
    }
    ~MyFrame()
    {
        delete timer;
    }
    void onClose(wxCloseEvent& evt)
    {
        timer->Stop();
        evt.Skip();
    }
    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_CLOSE(MyFrame::onClose)
END_EVENT_TABLE()

bool MyApp::OnInit()
{
    frame = new MyFrame();
    frame->Show();

    return true;
}

BEGIN_EVENT_TABLE(BasicDrawPane, wxPanel)
EVT_PAINT(BasicDrawPane::paintEvent)
END_EVENT_TABLE()

BasicDrawPane::BasicDrawPane(wxFrame* parent) :
wxPanel(parent)
{
}
void BasicDrawPane::paintEvent(wxPaintEvent& evt)
{
    wxPaintDC dc(this);
    render(dc);
}
void BasicDrawPane::paintNow()
{
    wxClientDC dc(this);
    render(dc);
}
void BasicDrawPane::render( wxDC& dc )
{
    static int y = 0;
    static int y_speed = 2;

    y += y_speed;
    if(y<0) y_speed = 2;
    if(y>200) y_speed = -2;

    dc.SetBackground( *wxWHITE_BRUSH );
    dc.Clear();
    dc.DrawText(wxT("Testing"), 40, y);
}

Note: When using this method with wxMSW it is very important to include

wxPaintDC dc(this);

Favorite site

References


  1. Drawing_and_Printing_in_C++_with_wxWidgets.pdf