How can I draw on a wxPanel 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.
Post Reply
FelixDev
Earned a small fee
Earned a small fee
Posts: 16
Joined: Fri Aug 20, 2021 7:02 pm

How can I draw on a wxPanel

Post by FelixDev »

Hello,
I want to draw on a wxPanel, which is located next to another one containing GUI-elements. Both panels are assigned to a sizer. Now my question is: How do I implement the class for the panel I want to draw on, correctly. I have had a look at various examples, but I didn't fully understand, how the declaration of the panel I want to draw on works.
I hope, anyone can help me with this issue - thanks in advance!
Best,
Felix
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How can I draw on a wxPanel

Post by doublemax »

When posting any question, please be more concrete about what your problem is.

https://wiki.wxwidgets.org/Drawing_on_a_panel_with_a_DC
Use the source, Luke!
FelixDev
Earned a small fee
Earned a small fee
Posts: 16
Joined: Fri Aug 20, 2021 7:02 pm

Re: How can I draw on a wxPanel

Post by FelixDev »

Hello,
thank you for your quick reply. I will try to be more concrete, when describing my problem(s) in the future.
I have created a (somewhat messy) example, only containing the panels and a drawPane and added a comment to my code, trying to describe my problem in a better way.

Code: Select all

#include "wx/wx.h" 

#include "wx/sizer.h"

class BasicPane : public wxPanel
{
public:
	BasicPane(wxFrame* parent);
	void paintEvent(wxPaintEvent& e);

	void paintNow();
	void render(wxDC& dc);

	DECLARE_EVENT_TABLE()
};

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

 wxFrame* frame;
 BasicPane* drawPane;
 
public:

};

class MyFrame : public wxFrame 
{
public:
	MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
	
	wxBoxSizer* s1 = new wxBoxSizer(wxHORIZONTAL);
	wxPanel* panel1 = new wxPanel(this, wxID_ANY);
	wxPanel* panel2 = new wxPanel(this, wxID_ANY);
};

wxIMPLEMENT_APP(MyApp);

bool MyApp::OnInit()
{
	
	
	
	auto frame = new MyFrame("HELLO wxDC", wxDefaultPosition, wxDefaultSize);
	
	drawPane = new  BasicPane((wxFrame*)frame);

	frame->Show();

	return true;
}

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

MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(nullptr, wxID_ANY, title, pos, size)
{
	panel1->SetBackgroundColour(wxColor(255, 1, 0));
	panel2->SetBackgroundColour(wxColor(2, 155, 0));
	
	//I want to draw something on panel1; panel2 contains the GUI elements

	s1->Add(panel1, 1, wxEXPAND);
	s1->Add(panel2, 1, wxEXPAND);

	this->SetSizerAndFit(s1);
	
}
BasicPane::BasicPane(wxFrame* parent) : wxPanel(parent) {

}

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

void BasicPane::paintNow() {
	wxClientDC dc(this);
	render(dc);
}
   
void BasicPane::render(wxDC& dc) {
	dc.DrawText(wxT("Test"), 40, 60);
}
I hope, my problem is now a little bit more clear.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How can I draw on a wxPanel

Post by doublemax »

You can't just draw something on a panel and expect it to stay there forever. The ways it works is that you need to draw the content of the panel when ever the OS requests it. You do that by catching the wxEVT_PAINT event (for that panel!) and do the drawing in the paint event handler.

Code: Select all

dc.DrawText(wxT("Test"), 40, 60);
Does this appear on the panel?


Code: Select all

	wxBoxSizer* s1 = new wxBoxSizer(wxHORIZONTAL);
	wxPanel* panel1 = new wxPanel(this, wxID_ANY);
	wxPanel* panel2 = new wxPanel(this, wxID_ANY);
This stuff in the class declaration doesn't make any sense. Put it into the constructor.

Code: Select all

drawPane = new  BasicPane((wxFrame*)frame);
This panel is not part of the sizer structure, so it will probably be covered by the two other panels.
Use the source, Luke!
FelixDev
Earned a small fee
Earned a small fee
Posts: 16
Joined: Fri Aug 20, 2021 7:02 pm

Re: How can I draw on a wxPanel

Post by FelixDev »

Hello and thank you for your reply and suggestions.
doublemax wrote: Tue Aug 24, 2021 5:45 pm

Code: Select all

dc.DrawText(wxT("Test"), 40, 60);
Does this appear on the panel?
Basically, yes. When I don't have the other two panels and only the "drawPane", the text is displayed. Right now, the two colored panels take up the whole space in the window, while the "drawPane" is just a little grey rectangle in the top left corner.
doublemax wrote: Tue Aug 24, 2021 5:45 pm

Code: Select all

drawPane = new  BasicPane((wxFrame*)frame);
This panel is not part of the sizer structure, so it will probably be covered by the two other panels.
So my problem with this is the following:

Code: Select all

MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size) : wxFrame(nullptr, wxID_ANY, title, pos, size)
{
	//other code...

	s1->Add(panel1, 1, wxEXPAND);
	s1->Add(panel2, 1, wxEXPAND);
	s1->Add(drawPane, 1, wxEXPAND);
	this->SetSizerAndFit(s1);
}
Whenever I want to add the "drawPane" directly to the sizer s1, Microsoft Visual Studio tells me, that the identifier "drawPane" isn't identified. So my question in this case would be how I could add it to the sizer structure correctly.

Thank you for help!
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How can I draw on a wxPanel

Post by doublemax »

Whenever I want to add the "drawPane" directly to the sizer s1, Microsoft Visual Studio tells me, that the identifier "drawPane" isn't identified. So my question in this case would be how I could add it to the sizer structure correctly.
You created "drawPane" inside MyApp::OnInit, therefore it's unknown inside MyFrame. Move the construction of "drawPane" to the MyFrame constructor.

Here's another minimal sample for you to study :)

Code: Select all

#include <wx/wx.h>

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

wxIMPLEMENT_APP(MyApp);

class CustomPanel : public wxPanel
{
public:
  CustomPanel(wxWindow *parent) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
  {
     Bind(wxEVT_PAINT, &CustomPanel::OnPaint, this);
     SetBackgroundStyle(wxBG_STYLE_PAINT);
  };

  void OnPaint(wxPaintEvent &event)
  {
    wxPaintDC dc(this);
    dc.SetBackground(*wxYELLOW);
    dc.Clear();

    dc.DrawText( wxString::Format("size: %d x %d", GetClientSize().x, GetClientSize().y), 10, 10); 
  };
};

class MyFrame : public wxFrame
{
public:
  MyFrame() : wxFrame(NULL, wxID_ANY, "Minimal Sample")
  {
    wxBoxSizer *mainSizer = new wxBoxSizer(wxHORIZONTAL);

      CustomPanel *panel1 = new CustomPanel(this);
      mainSizer->Add(panel1, 1, wxEXPAND, 0);

      wxPanel *panel2 = new wxPanel(this, wxID_ANY);
      panel2->SetBackgroundColour(*wxBLUE);
      mainSizer->Add(panel2, 1, wxEXPAND, 0);

    SetSizer(mainSizer);
  };
};

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

   return true;
}
Use the source, Luke!
Post Reply