Cannot draw something with DC Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Pille456
Knows some wx things
Knows some wx things
Posts: 44
Joined: Wed Sep 03, 2008 5:29 pm

Cannot draw something with DC

Post by Pille456 »

Hi,
I tried to draw something on a window but without any effect. Look at this :

Code: Select all

#include "wx/wx.h"
#include "wx/sizer.h"

class MyWindow : public wxFrame
{

public:
    MyWindow(const wxString& title);

    void paintEvent(wxPaintEvent& evt);

    void render(wxDC& dc);
};


class MyApp: public wxApp
{
    bool OnInit();
};

IMPLEMENT_APP(MyApp)


bool MyApp::OnInit()
{
    MyWindow *myWindow = new MyWindow(wxT("Test"));
    myWindow->Show(true);

    return true;
}

MyWindow::MyWindow(const wxString& title): wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(1000,800))
{
   this->Connect(wxID_ANY,wxEVT_PAINT ,wxCommandEventHandler(MyWindow::paintEvent),NULL,this); // this dosent, any ideas how to connect here=
   wxClientDC dc(this);
   render(dc);
}

void MyWindow::paintEvent(wxPaintEvent& evt)
{
    wxPaintDC dc(this);
    render(dc);
}

void MyWindow::render(wxDC& dc)
{
    dc.DrawText(wxT("Testing"), 40, 60);

    dc.SetBrush(*wxGREEN_BRUSH); 
    dc.SetPen( wxPen( wxColor(255,0,0), 5 ) ); 
    dc.DrawCircle( wxPoint(200,100), 25 );

    dc.SetBrush(*wxBLUE_BRUSH); // blue filling
    dc.SetPen( wxPen( wxColor(255,175,175), 10 ) ); 
    dc.DrawRectangle( 300, 100, 400, 200 );

    dc.SetPen( wxPen( wxColor(0,0,0), 3 ) );
    dc.DrawLine( 300, 100, 700, 300 ); 
}
I simply see nothing
Last edited by Pille456 on Tue Oct 07, 2008 12:26 pm, edited 1 time in total.
tan
wxWorld Domination!
wxWorld Domination!
Posts: 1471
Joined: Tue Nov 14, 2006 7:58 am
Location: Saint-Petersburg, Russia

Post by tan »

Hi,
there is one mistake here:

Code: Select all

MyWindow::MyWindow(const wxString& title): wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(1000,800))
{
//   this->Connect(wxID_ANY,wxEVT_PAINT ,wxCommandEventHandler(MyWindow::paintEvent),NULL,this); // this dosent, any ideas how to connect here=

// You have to use wxPaintEventHandler macro instead of wxCommandEventHandler
   this->Connect(wxID_ANY,wxEVT_PAINT ,wxPaintEventHandler(MyWindow::paintEvent),NULL,this);

// These lines are unnecessary, comment out them
/*
   wxClientDC dc(this);
   render(dc);
*/
}
OS: Windows XP Pro
Compiler: MSVC++ 7.1
wxWidgets: 2.8.10
bloodlee
Experienced Solver
Experienced Solver
Posts: 77
Joined: Thu Nov 30, 2006 10:49 am
Location: Shenzhen, CHN

Post by bloodlee »

Maybe you can try to add static event table to handle paint event.
I think

Code: Select all

EVT_PAINT()
is what you need.
Pille456
Knows some wx things
Knows some wx things
Posts: 44
Joined: Wed Sep 03, 2008 5:29 pm

Post by Pille456 »

A static event table works, I already checked that, but I always used "Connect" in my project and so I wanted to use it here too.
tan's version works fine, thanks!

I also tried "wxClientDC", because I have to refresh things and so I must repaint stuff at any time in my program. This doesnt work.
This is not "the" big problem, because I can use "Update() / Refresh()" to call the paint event, but just for correctness: How would a version wit wxClientDC look like?
tan
wxWorld Domination!
wxWorld Domination!
Posts: 1471
Joined: Tue Nov 14, 2006 7:58 am
Location: Saint-Petersburg, Russia

Post by tan »

Pille456 wrote: tan's version works fine, thanks!
Glad to hear it :)
Pille456 wrote: I also tried "wxClientDC", because I have to refresh things and so I must repaint stuff at any time in my program. This doesnt work.
This is not "the" big problem, because I can use "Update() / Refresh()" to call the paint event, but just for correctness: How would a version wit wxClientDC look like?
It doesn't make much sense to redraw ALL scene outside the paint event, use Refresh() for that. Sometimes it may be useful for drawing small changes on the scene (e.g. on mouse dragging of any object). Use wxClientDC for that, as usual:

Code: Select all

void MyWindow::OnAnyEvent(wxAnyEvent& ev)
{
    wxClientDC dc(this);
    DoSomeRendering(dc);
}
Show more code if you have any troubles.
OS: Windows XP Pro
Compiler: MSVC++ 7.1
wxWidgets: 2.8.10
Pille456
Knows some wx things
Knows some wx things
Posts: 44
Joined: Wed Sep 03, 2008 5:29 pm

Post by Pille456 »

Whats the differences between update and refresh?

Momently I have another strange (but understandable) "error" in my program:
The stuff I want to draw will be geometric objects in different colors, sizes etc. Therefore the background color should be white and because of this I would like to draw the stuff on a panel with white background.
This dosent work, because the panel overdraws everything I draw. But if I delete the panel I have a black background (already tried to set the frame background, but without any effect).
The strange thing is, that there arent any other objects except sizers, so I dont know why there is a black background color.
tan
wxWorld Domination!
wxWorld Domination!
Posts: 1471
Joined: Tue Nov 14, 2006 7:58 am
Location: Saint-Petersburg, Russia

Post by tan »

Pille456 wrote:Whats the differences between update and refresh?
Refresh() just appends the paint event to the message queue, then repainting doesn't happen immediately but only during the next event loop iteration.
Update() immediately repaints the invalidated area of the window (but it doesn't invalidate any area of the window so nothing happens if nothing has been invalidated). Use combination

Code: Select all

Refresh();
Update();
to immediately redraw the window unconditionally.
Pille456 wrote: Momently I have another strange (but understandable) "error" in my program:
The stuff I want to draw will be geometric objects in different colors, sizes etc. Therefore the background color should be white and because of this I would like to draw the stuff on a panel with white background.
This dosent work, because the panel overdraws everything I draw.
Do you paint on the panel or on the frame?
Try to call SetBackgroundStyle(wxBG_STYLE_CUSTOM) for the panel.
Pille456 wrote: But if I delete the panel I have a black background (already tried to set the frame background, but without any effect).
The strange thing is, that there arent any other objects except sizers, so I dont know why there is a black background color.
As i mentioned, it is more easy to help if you provide some relevant code.
OS: Windows XP Pro
Compiler: MSVC++ 7.1
wxWidgets: 2.8.10
Pille456
Knows some wx things
Knows some wx things
Posts: 44
Joined: Wed Sep 03, 2008 5:29 pm

Post by Pille456 »

I paint on the frame. Painting on the panel causes a crash..
"SetBackgroundStyle(wxBG_STYLE_CUSTOM)" lets the panel look totally ugly,so I dont think that is what I'm searching for.

Here my code (I try to short it a bit):

Code: Select all

MyWindow:MyWindow(const wxString& title): wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(1000,800)),boids(){    
    sizer_GroupAll = new wxBoxSizer(wxHORIZONTAL); //this sizer should contain everything
    sizer_GroupAllInfo = new wxBoxSizer(wxVERTICAL); //some options
    sizer_Drawing = new wxBoxSizer(wxVERTICAL); //place where to draw stuff
    panel_Drawing = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
    panel_GroupAllInfo = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
    panel_Drawing->SetBackgroundColour(wxColour(255, 255, 255));
    sizer_Drawing->Add(panel_Drawing, 1, wxEXPAND, 5);
    sizer_GroupAll->Add(sizer_Drawing, 1, wxEXPAND, 5);

    //tons of buttons etc.
    
    sizer_GroupAllInfo->Add(panel_GroupAllInfo, 1, wxEXPAND|wxLEFT, 2);
    sizer_GroupAll->Add(sizer_GroupAllInfo, 0, wxEXPAND, 5);
    SetSizer(sizer_GroupAll);

    panel_Drawing->Connect(wxID_ANY, wxEVT_PAINT, wxPaintEventHandler(MyWindow::DrawScene), NULL, panel_Drawing); 
    Centre();
    StartProgram();
}

MyWindow::StartProgram() {
//Finally here will be a main loop like:
while(...) {
   FirstObject.Move(); //Just a moving Object on the screen
   SecondObject.Move();
   //etc.
   Refresh();
   Update();
  }
}

Mywindow::DrawScene(wxPaintEvent &evt) {
   wxPaintDC dc(this);  
   FirstObject.Draw(dc);
   SecondObject.Draw(dc);
   //etc.
}
EDIT: After hours of debugging I found out, that using "wxBufferedPaintDC" instead of "wxPaintDC" causes the background of the panel do be drawn black. That was the problem...