Sample code for c++ WxWidgets blit an image to the canvas - c++

I am trying to make a basic GUI using wxWidgets and wxFormBuilber to display a chess gameboard and chess pieces from a sprite sheet. I would really appreciate some sample code for:
uploading an image from a file
blitting an image at a specific location

Here's a simplest example I can think of. This uses this set of pieces from wikipedia (licensed under the Creative Commons license). This example only draws the black pieces, but you should be able to figure out how to draw the white pieces with a few simple modifications.
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
class MyFrame: public wxFrame
{
public:
MyFrame();
private:
void OnPaint(wxPaintEvent& event);
wxPanel* m_board;
wxBitmap m_blackRook;
wxBitmap m_blackKnight;
wxBitmap m_blackBishop;
wxBitmap m_blackQueen;
wxBitmap m_blackKing;
wxBitmap m_blackPawn;
};
MyFrame::MyFrame()
:wxFrame(NULL, wxID_ANY, "Chess", wxDefaultPosition, wxSize(1000, 1000))
{
m_board = new wxPanel(this, wxID_ANY);
m_board->Bind(wxEVT_PAINT, &MyFrame::OnPaint, this);
// Load the image.
wxImage im("c:\\640px-Chess_Pieces_Sprite.svg.png", wxBITMAP_TYPE_PNG);
// Extract the images of the pieces from the larger image.
wxBitmap b(im);
m_blackKing = b.GetSubBitmap(wxRect(5,113,100,100));
m_blackQueen = b.GetSubBitmap(wxRect(110,113,100,100));
m_blackBishop = b.GetSubBitmap(wxRect(215,113,100,100));
m_blackKnight = b.GetSubBitmap(wxRect(323,113,100,100));
m_blackRook = b.GetSubBitmap(wxRect(433,113,100,100));
m_blackPawn = b.GetSubBitmap(wxRect(535,113,100,100));
}
void MyFrame::OnPaint(wxPaintEvent&)
{
wxPaintDC dc(m_board);
dc.Clear();
// Draw thie light squares
dc.SetPen(wxColour(209,139,71));
dc.SetBrush(wxColour(209,139,71));
dc.DrawRectangle(0,0,800,800);
// Draw thie dark squares
dc.SetPen(wxColour(255,206,158));
dc.SetBrush(wxColour(255,206,158));
for ( int i = 0 ; i< 8 ; ++i )
{
for ( int j = i%2 ; j< 8 ; j+=2 )
{
dc.DrawRectangle(i*100,j*100,100,100);
}
}
// Draw thie black pieces
dc.DrawBitmap(m_blackRook, 0, 0, true);
dc.DrawBitmap(m_blackKnight, 100, 0, true);
dc.DrawBitmap(m_blackBishop, 200, 0, true);
dc.DrawBitmap(m_blackQueen, 300, 0, true);
dc.DrawBitmap(m_blackKing, 400, 0, true);
dc.DrawBitmap(m_blackBishop, 500, 0, true);
dc.DrawBitmap(m_blackKnight, 600, 0, true);
dc.DrawBitmap(m_blackRook, 700, 0, true);
for ( int i = 0 ; i < 8 ; ++i )
{
dc.DrawBitmap(m_blackPawn, 100*i, 100, true);
}
}
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
::wxInitAllImageHandlers();
MyFrame* frame = new MyFrame();
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
On windows, the application will look something like this:
The important items demonstrated here are
loading the image.
extracting subbitmaps for the individual pieces.
drawing the pieces in a paint handler for the board.
Obviously, you should change the location of the png file in line 38. If you want to take a few extra steps, you can embed the png file in your application.
I tried to keep the example as simple as possible, so there are many things that could be improved upon. For example. I used a separate bitmap for each type of piece. If you want you can use a wxImageList instead. In addition it would be better to use an wxAutoBufferedPaintDC in the paint handler.

Related

How to properly paint content on a wxScrolledWindow?

I am creating an animation timeline widget using wxWidgets.
The widget consist of a wxFrame with a wxScrolledWindow child:
I want to support horizontal zooming by changing the timeline window virtual size when the user rolls mouse middle button.
Zooming without scrolling works well. But when i start scrolling(forward and backward) things get messed up.
So to troubleshoot I decided to do a simple test:
Draw a line from the window top left corner to the bottom right corner. And the test fails!
Without scrolling -> Test pass
Zoom then scroll to right -> Test fails
Scroll back to left -> Test also fails
I have no idea of whats going on. Here my CPP code:
In .H:
class AnimationFrame : public wxFrame
{
public:
AnimationFrame();
private:
void onTimelineMouseWheel(wxMouseEvent& ev);
void onTimelinePaint(wxPaintEvent& ev);
// The scrolled window.
wxScrolledWindow* m_timelineWindow;
};
In .CPP:
AnimationFrame::AnimationFrame()
{
assert(wxXmlResource::Get()->LoadFrame(this, NULL, "AnimationFrame"));
m_timelineWindow = (wxScrolledWindow*)wxWindow::FindWindowByName("TimelineScrolledWindow", this);
assert(m_timelineWindow);
wxPanel* headerPanel = (wxPanel*)wxWindow::FindWindowByName("HeaderPanel", this);
assert(headerPanel);
// Adjust panel sizes.
{
headerPanel->SetMaxSize(wxSize(headerPanel->GetMaxSize().x, 40));
m_timelineWindow->SetMaxSize(wxSize(m_timelineWindow->GetMaxSize().x, 100));
this->SetMinSize(wxSize(this->GetSize().x, 250));
this->SetSize(wxSize(this->GetSize().x, 250));
this->SetMaxSize(wxSize(this->GetSize().x, 250));
}
// Timeline events from the scrolled window.
m_timelineWindow->Bind(wxEVT_MOUSEWHEEL, &AnimationFrame::onTimelineMouseWheel, this);
m_timelineWindow->Bind(wxEVT_PAINT, std::bind(&AnimationFrame::onTimelinePaint, this, std::placeholders::_1));
}
void AnimationFrame::onTimelineMouseWheel(wxMouseEvent& ev)
{
static const nbFloat32 scrollIntensity = 1.20f;
const nbFloat32 delta = scrollIntensity * (nbFloat32)(ev.GetWheelRotation() / ev.GetWheelDelta());
const nbFloat32 sizeFactor = delta >= 0.0 ? delta : 1.0f / -delta;
const wxSize currentVirtualSize = m_timelineWindow->GetVirtualSize();
wxSize targetVirtualSize = wxSize((nbUint32)((nbFloat32)currentVirtualSize.x * sizeFactor), currentVirtualSize.y);
targetVirtualSize.x = std::min(targetVirtualSize.x, 5000);
targetVirtualSize.x = std::max(targetVirtualSize.x, m_timelineWindow->GetSize().x);
m_timelineWindow->SetVirtualSize(targetVirtualSize);
this->Refresh();
}
void AnimationFrame::onTimelinePaint(wxPaintEvent& ev)
{
// Init the DC.
wxPaintDC dc(m_timelineWindow);
PrepareDC(dc);// from the scrolling sample. Doesnt seems to do anything.
/*
wxFont font(12, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
dc.SetFont(font);
dc.SetBackgroundMode(wxTRANSPARENT);
dc.SetTextForeground(*wxBLACK);
dc.SetTextBackground(*wxWHITE);
*/
// Now draw line.
dc.DrawLine(wxPoint(0, 0), wxPoint(m_timelineWindow->GetSize().x, m_timelineWindow->GetSize().y));
}
Addional information:
As you certainly realised the widget is loaded from CPP using the XRC format. Here the generated code from wxFormBuilder for the widget.
XRC: https://1drv.ms/u/s!Ak_u4fVrMHMkrTe59Fuo4X2b-fRO?e=2Z0lw0
CPP: https://1drv.ms/u/s!Ak_u4fVrMHMkrTi_8w5UIkwFTl9t?e=BZBlLs

wxWidgets: Frame size is not changing in Image panel

I am using wxWidgets 'An Image Panel' code. Here I made only one change.
I want frame size should be equal to image size, My Image size is 762x463, but my frame size is different. frame SetSize function is not working.
wxImagePanel::wxImagePanel(wxFrame* parent, wxString file, wxBitmapType format) :
wxPanel(parent)
{
image.LoadFile(file, format);
}
void wxImagePanel::paintEvent(wxPaintEvent & evt)
{
// depending on your system you may need to look at double-buffered dcs
wxPaintDC dc(this);
render(dc);
}
void wxImagePanel::paintNow()
{
// depending on your system you may need to look at double-buffered dcs
wxClientDC dc(this);
render(dc);
}
void wxImagePanel::render(wxDC& dc)
{
dc.DrawBitmap( image, 0, 0, false );
}
class MyApp: public wxApp
{
wxFrame *frame;
wxImagePanel * drawPane;
public:
bool OnInit()
{
// make sure to call this first
wxInitAllImageHandlers();
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
wxBitmap image(wxT("properties.png"), wxBITMAP_TYPE_PNG);
frame = new wxFrame(NULL, wxID_ANY, wxT("Hello wxDC"), wxPoint(50,50), wxSize(image.GetWidth(), image.GetHeight())); // 762x463
// then simply create like this
drawPane = new wxImagePanel( frame, wxT("image.jpg"), wxBITMAP_TYPE_JPEG);
sizer->Add(drawPane, 1, wxEXPAND);
frame->SetSizer(sizer);
frame->Show();
return true;
}
};
To make the frame sized to display the image, you need to make 2 changes:
In the constructor wxImagePanel::wxImagePanel, you need to add a line to set a minimum size for the image panel.
wxImagePanel::wxImagePanel(wxFrame* parent, wxString file, wxBitmapType format) :
wxPanel(parent)
{
image.LoadFile(file, format);
SetMinSize(image.GetSize());
...
An alternate, and possibly better, solution would be to override wxWindow::DoGetBestClientSize for your wxImagePanel class and have it return image.GetSize();.
Incidentally, in the code shown above, there is nothing that actually connects the paint handler to the paint event, so you probably also want to add a line like
Bind(wxEVT_PAINT, &wxImagePanel::paintEvent, this);
to the constructor as well.
In the body of MyApp::OnInit, change the line
frame->SetSizer(sizer);
to
frame->SetSizerAndFit(sizer);
Using the SetSizerAndFit method will tell the frame to resize itself to the smallest size necessary to display all of its contents. Since in step 1 the minimum size of the image panel was set to the size of image and the image panel is the only content of the frame, the frame will be sized to fit the image.

wxWidgets best control for drawing realtime graphics [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I made a little App using SDL to show some sprite animations, and it works really fine. It's important that the rendering is as smooth as possible.
Since now I need some GUI, I decided to use wxWidgets 3 to create kind of the same application but where I can now also add some GUI elements like menus, modals, etc.
After diving into the wxWidget's wiki, I found there are different ways to draw into a window.
For example:
wxClientDC
wxPaintDC
wxGLCanvas
I also found other kind of classes like the "Graphics Context classes" which I'm still not sure if they could be useful for what I need.
My application already uses an internal buffer which just needs to be copied.
So my question is What's the most appropriate way to do this on wxWidgets?
And, how much performance/overhead does that solution impose?
What would be the difference in performance/overhead between the different methods wxWidgets has for drawing pixels inside a window? Why one uses OnPaint events while others don't.
Here's one way to do this:
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include <wx/timer.h>
#include <wx/dcclient.h>
#include <wx/rawbmp.h>
///////////// Declarations
class MyFrame : public wxFrame
{
public:
MyFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo",
wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize,
int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
~MyFrame();
private:
// Event Handlers
void OnPaint( wxPaintEvent& event );
void OnTimer(wxTimerEvent& event);
// Helper function
void RebuildBufferAndRefresh();
// Private data
wxWindow* m_renderSurface;
int m_width;
int m_height;
wxBitmap m_bitmapBuffer;
wxTimer m_timer;
int m_curRGB;
unsigned char* m_pixelData;
};
class MyApp : public wxApp
{
public:
virtual bool OnInit() wxOVERRIDE;
};
wxDECLARE_APP(MyApp);
///////////// Implementation
MyFrame::MyFrame( wxWindow* parent, int id, wxString title, wxPoint pos,
wxSize size, int style )
:wxFrame( parent, id, title, pos, size, style )
{
m_width=100;
m_height=100;
m_pixelData = new unsigned char[3*m_width*m_height];
m_renderSurface = new wxWindow(this, wxID_ANY, wxDefaultPosition,
wxSize(m_width,m_height));
m_renderSurface->SetBackgroundStyle(wxBG_STYLE_PAINT);
m_renderSurface->Bind(wxEVT_PAINT,&MyFrame::OnPaint,this);
wxBoxSizer* bSizer = new wxBoxSizer( wxVERTICAL );
bSizer->Add( m_renderSurface, 0 );
this->SetSizer( bSizer );
Layout();
m_timer.SetOwner(this);
m_timer.Start(17);
this->Bind(wxEVT_TIMER,&MyFrame::OnTimer,this);
m_curRGB=0;
}
MyFrame::~MyFrame()
{
m_timer.Stop();
delete[] m_pixelData;
}
void MyFrame::OnPaint( wxPaintEvent& event )
{
wxPaintDC dc(m_renderSurface);
if(m_bitmapBuffer.IsOk())
{
dc.DrawBitmap(m_bitmapBuffer,0,0);
}
}
void MyFrame::OnTimer(wxTimerEvent& event)
{
RebuildBufferAndRefresh();
}
void MyFrame::RebuildBufferAndRefresh()
{
// Build the pixel buffer here, for this simple example just set all
// pixels to the same value and then increment that value.
for ( int y = 0; y < m_height; ++y )
{
for ( int x = 0; x < m_width; ++x )
{
m_pixelData[3*y*m_width+3*x]=m_curRGB;
m_pixelData[3*y*m_width+3*x+1]=m_curRGB;
m_pixelData[3*y*m_width+3*x+2]=m_curRGB;
}
}
++m_curRGB;
if(m_curRGB>255)
{
m_curRGB=0;
}
// Now transfer the pixel data into a wxBitmap
wxBitmap b(m_width,m_height,24);
wxNativePixelData data(b);
if ( !data )
{
// ... raw access to bitmap data unavailable, do something else ...
return;
}
wxNativePixelData::Iterator p(data);
int curPixelDataLoc = 0;
for ( int y = 0; y < m_height; ++y )
{
wxNativePixelData::Iterator rowStart = p;
for ( int x = 0; x < m_width; ++x, ++p )
{
p.Red() = m_pixelData[curPixelDataLoc++];
p.Green() = m_pixelData[curPixelDataLoc++];
p.Blue() = m_pixelData[curPixelDataLoc++];
}
p = rowStart;
p.OffsetY(data, 1);
}
m_bitmapBuffer=b;
m_renderSurface->Refresh();
m_renderSurface->Update();
}
bool MyApp::OnInit()
{
MyFrame* frame = new MyFrame(NULL);
frame->Show();
return true;
}
wxIMPLEMENT_APP(MyApp);
The basic idea here is copy your buffer into a wxBitmap and then draw that bitmap in the paint handler. The paint handler is then triggered by the calls to Refresh and Update. The reason for this is that system will also call the paint method for various reasons such as the mouse cursor running over the render surface. By doing it this way, there is a bitmap that can be drawn for both your and the system's calls to refresh the surface.
In the simple example posted above, I'm just using a simple timer to call the RebuildBufferAndRefresh method approximately 60 times a second. Your application will probably have a better way to to determine when a refresh is needed and you can use that way to call RebuildBufferAndRefresh instead.
Obviously most of the work is done in the RebuildBufferAndRefresh method. That method is broken into 3 parts. The first part builds the internal buffer. The second part copies that buffer into a wxBitmap for the reasons stated above. The third part just calls refresh and update to force the render surface to be redrawn.
There may be better ways to do this, but I think this is the most straight forward wxWidgets-ey to do constantly render a buffer of pixel data to a window.
As to how much overhead this approach requires, it's basically a memcopy from your buffer to a bitmap, but the nested loop will be less efficient than a real memcopy. After that the paint handler does nothing but draw the bitmap. That will probably be accomplished by a blit to the system's backbuffer and should be quite fast. I hope that helps.

Image corruption in wxScrolledWindow while scrolling

I want to view an image in one of wxSplitterWindow using wxScrolledWindow.
I derived class from wxPanel, which I add into wxScrolledWindow. But the result is not what i want.(
class ImagePanel : public wxPanel
{
public:
//ImagePanel(wxFrame* parent);
ImagePanel(wxWindow* parent);
void paintEvent(wxPaintEvent& event);
void paintNow();
void setBitmap(wxBitmap& imBitmap);
void setBitmap(wxImage& img);
int GetHeight();
int GetWidth();
void render(wxDC& dc);
DECLARE_EVENT_TABLE()
private:
wxBitmap curBitmap;
};
Paint event:
void ImagePanel::paintEvent(wxPaintEvent& event)
{
wxBufferedPaintDC dc(this);
render(dc);
}
This is how I have written the interface into main frame constructor:
topSizer = new wxBoxSizer(wxVERTICAL);
topSplitter = new wxSplitterWindow(this,ID_TOPSPLITTER,wxDefaultPosition,wxDefaultSize,wxSP_LIVE_UPDATE|wxSP_3D);
topSizer->Add(topSplitter,1,wxALL|wxEXPAND,0);
imagePanel = new wxPanel(topSplitter,ID_IMAGEPANEL);
imageSizer = new wxBoxSizer(wxVERTICAL);
imagePanel->SetSizer(imageSizer);
optionPanel = new wxPanel(topSplitter,ID_OPTIONPANEL);
optionSizer = new wxBoxSizer(wxVERTICAL);
optionPanel->SetSizer(optionSizer);
topSplitter->SplitVertically(imagePanel, optionPanel);
topSplitter->SetMinimumPaneSize(200);
//===========================================
//image panel interface
imageScWindow=new wxScrolledWindow(imagePanel,ID_IMAGESCWINDOW,wxDefaultPosition,wxDefaultSize,
wxVSCROLL|wxHSCROLL|wxALL|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE);
imgArea = new ImagePanel(imageScWindow);
imageSizer->Add(imageScWindow,1,wxEXPAND,0);
scrollSizer = new wxBoxSizer(wxVERTICAL);
imageScWindow->SetSizer(scrollSizer);
scrollSizer->Add(imgArea,1,wxEXPAND,0);
imageScWindow->SetTargetWindow(imgArea);
And this is the function that loads image:
void MainFrame::Setpic(wxCommandEvent& event)
{
wxString path = GetCurrentWorkingDir()+wxT("\\")+tmptxt1->GetValue();
wxImage img(path);
wxBitmap imBitmap(img,-1);
imgArea->setBitmap(imBitmap);
imageScWindow->SetScrollbars(1,1,imgArea->GetWidth(),imgArea->GetHeight());
imageScWindow->Refresh();
}
Thats what i get:
https://i.imgur.com/x1GIlrl.png
I have also tried to do like this in the constructor, without SetTargetArea:
//===========================================
//image panel interface
imageScWindow=new wxScrolledWindow(imagePanel,ID_IMAGESCWINDOW,wxDefaultPosition,wxDefaultSize,
wxVSCROLL|wxHSCROLL|wxALL|wxALWAYS_SHOW_SB|wxFULL_REPAINT_ON_RESIZE);
imgArea = new ImagePanel(imageScWindow);
imageSizer->Add(imageScWindow,1,wxEXPAND,0);
scrollSizer = new wxBoxSizer(wxVERTICAL);
imageScWindow->SetSizer(scrollSizer);
scrollSizer->Add(imgArea,1,wxEXPAND,0);
Then image shows properly, but if I change the frame size or move splitter, scrollbars disappear, and I have to set them again somwhere.
Then i tried to do like this:
int prvx,prvy;
void ImagePanel::paintEvent(wxPaintEvent& event)
{
reinterpret_cast<wxScrolledWindow*>(this->GetParent())->GetViewStart(&prvx,&prvy);
reinterpret_cast<wxScrolledWindow*>(this->GetParent())->SetScrollbars(1,1,curBitmap.GetWidth(),curBitmap.GetHeight());
reinterpret_cast<wxScrolledWindow*>(this->GetParent())->Scroll(wxPoint(prvx,prvy));
wxBufferedPaintDC dc(this);
render(dc);
}
It shows properly, but lags while scrolling, even without wxFULL_REPAINT_ON_RESIZE in wxScrolledWindow. The reason why it is in paint event: if I add this into OnSize event, program crashes. What to do?
I'm not sure where to begin answering your question. Here's a minimal sample of a frame that has a splitter with a bitmap on the left and a panel on the right. I hope you can adapt this sample to do what you need.
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include <wx/scrolwin.h>
#include <wx/splitter.h>
#include <wx/dcbuffer.h>
class MyFrame : public wxFrame
{
public:
MyFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo",
wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize,
int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
private:
void OnScrollPaint( wxPaintEvent& event );
wxScrolledCanvas* m_canvas;
wxBitmap m_bitmap;
};
MyFrame::MyFrame( wxWindow* parent, int id, wxString title, wxPoint pos,
wxSize size, int style )
:wxFrame( parent, id, title, pos, size, style )
{
m_bitmap=wxBitmap ("test.png", wxBITMAP_TYPE_PNG );
wxSplitterWindow* m_splitter1
= new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSP_LIVE_UPDATE );
m_canvas = new wxScrolledCanvas( m_splitter1, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSTATIC_BORDER|wxHSCROLL|wxVSCROLL );
m_canvas->SetScrollRate( 5, 5 );
m_canvas->SetVirtualSize(m_bitmap.GetWidth(), m_bitmap.GetHeight());
m_canvas->SetBackgroundStyle(wxBG_STYLE_PAINT);
m_canvas->Bind( wxEVT_PAINT, &MyFrame::OnScrollPaint , this );
wxPanel* m_panel2 = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition,
wxDefaultSize, wxSTATIC_BORDER|wxTAB_TRAVERSAL );
m_splitter1->SplitVertically( m_canvas, m_panel2, GetSize().x/2 );
}
void MyFrame::OnScrollPaint( wxPaintEvent& event )
{
wxAutoBufferedPaintDC dc(m_canvas);
m_canvas->DoPrepareDC(dc);
dc.Clear();
dc.DrawBitmap(m_bitmap,0,0);
}
class MyApp : public wxApp
{
public:
virtual bool OnInit()
{
wxInitAllImageHandlers();
MyFrame* frame = new MyFrame(NULL);
frame->Show();
return true;
}
};
wxIMPLEMENT_APP(MyApp);
To run this, be sure to change "test.png" in line 35 to the name of an actual image file on your computer (and change wxBITMAP_TYPE_PNG if the image file isn't a png).
The important parts are:
Set the background style of the canvas to wxBG_STYLE_PAINT as shown in line 46.
In the paint handler, call the DoPrepareDC method on the paintdc.
By the way, the paint handler shown in my sample isn't very good. It draws the entire bitmap every time. A better approach would be to get the update region and only redraw the parts that are needed, but I wanted to keep this simple.

Translate screen drawing to another part of the screen

Is it possible to make it so that all drawing to an area "A" is translated to an area "B"?
For example drawing to the area(0,0)(100,100) and have it appear in area(200,200)(300,300).
The question is actually tagged with windows and graphics. This might have been targeted to Win32 and GDI (where I've unfortunately nearly no experience). So, the following might be seen as proof of concept:
I couldn't resist to implement the idea / concept using QWindow and QPixmap.
The concept is:
open a window fullscreen (i.e. without decoration)
make a snapshot and store it internally (in my case a )
display the internal image in window (the user cannot notice the difference)
perform a loop where pixmap is modified and re-displayed periodically (depending or not depending on user input).
And this is how I did it in Qt:
I opened a QWindow and made it fullscreen. (Maximum size may make the window full screen as well but it still will have decoration (titlebar with system menu etc.) which is unintended.)
Before painting anything, a snapshot of this window is done. That's really easy in Qt using QScreen::grabWindow(). The grabbed contents is returned as QPixmap and stored as member of my derived Window class.
The visual output just paints the stored member QPixmap.
I used a QTimer to force periodical changes of the QPixmap. To keep the sample code as short as possible, I didn't make the effort of shuffling tiles. Instead, I simply scrolled the pixmap copying a small part, moving the rest upwards, and inserting the small stripe at bottom again.
The sample code qWindowRoll.cc:
#include <QtWidgets>
class Window: public QWindow {
private:
// the Qt backing store for window
QBackingStore _qBackStore;
// background pixmap
QPixmap _qPixmap;
public:
// constructor.
Window():
QWindow(),
_qBackStore(this)
{
showFullScreen();
}
// destructor.
virtual ~Window() = default;
// disabled:
Window(const Window&) = delete;
Window& operator=(const Window&) = delete;
// do something with pixmap
void changePixmap()
{
enum { n = 4 };
if (_qPixmap.height() < n) return; // not yet initialized
const QPixmap qPixmapTmp = _qPixmap.copy(0, 0, _qPixmap.width(), n);
//_qPixmap.scroll(0, -n, 0, n, _qPixmap.width(), _qPixmap.height() - n);
{ QPainter qPainter(&_qPixmap);
qPainter.drawPixmap(
QRect(0, 0, _qPixmap.width(), _qPixmap.height() - n),
_qPixmap,
QRect(0, n, _qPixmap.width(), _qPixmap.height() - n));
qPainter.drawPixmap(0, _qPixmap.height() - n, qPixmapTmp);
}
requestUpdate();
}
protected: // overloaded events
virtual bool event(QEvent *pQEvent) override
{
if (pQEvent->type() == QEvent::UpdateRequest) {
paint();
return true;
}
return QWindow::event(pQEvent);
}
virtual void resizeEvent(QResizeEvent *pQEvent)
{
_qBackStore.resize(pQEvent->size());
paint();
}
virtual void exposeEvent(QExposeEvent*) override
{
paint();
}
// shoot screen
// inspired by http://doc.qt.io/qt-5/qtwidgets-desktop-screenshot-screenshot-cpp.html
void makeScreenShot()
{
if (QScreen *pQScr = screen()) {
_qPixmap = pQScr->grabWindow(winId());
}
}
private: // internal stuff
// paint
void paint()
{
if (!isExposed()) return;
QRect qRect(0, 0, width(), height());
if (_qPixmap.width() != width() || _qPixmap.height() != height()) {
makeScreenShot();
}
_qBackStore.beginPaint(qRect);
QPaintDevice *pQPaintDevice = _qBackStore.paintDevice();
QPainter qPainter(pQPaintDevice);
qPainter.drawPixmap(0, 0, _qPixmap);
_qBackStore.endPaint();
_qBackStore.flush(qRect);
}
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
// setup GUI
Window win;
win.setVisible(true);
// setup timer
QTimer qTimer;
qTimer.setInterval(50); // 50 ms -> 20 Hz (round about)
QObject::connect(&qTimer, &QTimer::timeout,
&win, &Window::changePixmap);
qTimer.start();
// run application
return app.exec();
}
I compiled and tested with Qt 5.9.2 on Windows 10. And this is how it looks:
Note: On my desktop, the scrolling is smooth. I manually made 4 snapshots and composed a GIF in GIMP – hence the image appears a bit stuttering.