wxDC how to 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
apoorv569
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 206
Joined: Tue Oct 20, 2020 3:35 pm

wxDC how to draw on a wxPanel?

Post by apoorv569 » Wed May 05, 2021 6:21 am

I found this wxDC which can draw on various contexts. By looking at some examples on zetcode's website, I am able to draw fine, but if I try to set wxPaintDC to a panel, I get error,

Code: Select all

./src/gtk/dc.cpp(299): assert "cr" failed in wxPaintDCImpl(): using wxPaintDC without being in a native paint event
code I use to draw is,

Code: Select all

void Browser::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(m_TopPanel);
    wxColour gray, white, red, blue;
    wxColour orange, green, brown;

    gray.Set(wxT("#d4d4d4"));
    white.Set(wxT("#ffffff"));
    red.Set(wxT("#ff0000"));
    orange.Set(wxT("#fa8e00"));
    green.Set(wxT("#619e1b"));
    brown.Set(wxT("#715b33"));
    blue.Set(wxT("#0d0060"));

    dc.SetPen(wxPen(gray));

    dc.DrawRectangle(20, 20, 50, 50);
    dc.DrawRectangle(30, 40, 50, 50);

    dc.SetBrush(wxBrush(white));
    dc.DrawRectangle(100, 20, 50, 50);
    dc.DrawRectangle(110, 40, 50, 50);
    wxRegion region1(100, 20, 50, 50);
    wxRegion region2(110, 40, 50, 50);
    region1.Intersect(region2);
    wxRect rect1 = region1.GetBox();
    dc.SetClippingRegion(region1);
    dc.SetBrush(wxBrush(red));
    dc.DrawRectangle(rect1);
    dc.DestroyClippingRegion();

    dc.SetBrush(wxBrush(white));
    dc.DrawRectangle(180, 20, 50, 50);
    dc.DrawRectangle(190, 40, 50, 50);
    wxRegion region3(180, 20, 50, 50);
    wxRegion region4(190, 40, 50, 50);
    region3.Union(region4);
    dc.SetClippingRegion(region3);
    wxRect rect2 = region3.GetBox();
    dc.SetBrush(wxBrush(orange));
    dc.DrawRectangle(rect2);
    dc.DestroyClippingRegion();

    dc.SetBrush(wxBrush(white));
    dc.DrawRectangle(20, 120, 50, 50);
    dc.DrawRectangle(30, 140, 50, 50);
    wxRegion region5(20, 120, 50, 50);
    wxRegion region6(30, 140, 50, 50);
    region5.Xor(region6);
    wxRect rect3 = region5.GetBox();
    dc.SetClippingRegion(region5);
    dc.SetBrush(wxBrush(green));
    dc.DrawRectangle(rect3);
    dc.DestroyClippingRegion();

    dc.SetBrush(wxBrush(white));
    dc.DrawRectangle(100, 120, 50, 50);
    dc.DrawRectangle(110, 140, 50, 50);
    wxRegion region7(100, 120, 50, 50);
    wxRegion region8(110, 140, 50, 50);
    region7.Subtract(region8);
    wxRect rect4 = region7.GetBox();
    dc.SetClippingRegion(region7);
    dc.SetBrush(wxBrush(brown));
    dc.DrawRectangle(rect4);
    dc.DestroyClippingRegion();

    dc.SetBrush(white);
    dc.DrawRectangle(180, 120, 50, 50);
    dc.DrawRectangle(190, 140, 50, 50);
    wxRegion region9(180, 120, 50, 50);
    wxRegion region10(190, 140, 50, 50);
    region10.Subtract(region9);
    wxRect rect5 = region10.GetBox();
    dc.SetClippingRegion(region10);
    dc.SetBrush(wxBrush(blue));
    dc.DrawRectangle(rect5);
    dc.DestroyClippingRegion();
}
but if I set it back to "this" which is also a wxPanel, it works.

the Browser class is inheriting from wxPanel,

Code: Select all

Browser::Browser(wxWindow* window)
    : wxPanel(window, wxID_ANY, wxDefaultPosition, wxDefaultSize),
      m_ConfigFilepath("config.yaml"), m_DatabaseFilepath("sample.hive")
{
this is what my application looks like,
Image

but this draws it here,
Image

the top part where the buttons are is a wxPanel, where I want to draw, but it draws on the parent panel of the app, hence not respecting other widgets space.

Code: Select all

    m_TopPanel = new wxPanel(m_TopSplitter, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
I want to draw on this panel m_TopPanel which is on a wxSplitter.

How can I correct this?

User avatar
doublemax
Moderator
Moderator
Posts: 16018
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxDC how to draw on a wxPanel?

Post by doublemax » Wed May 05, 2021 7:31 am

You're not showing one important part, where/how you bind the event handler. You're probably binding it to the frame instead of the panel.
Use the source, Luke!

apoorv569
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 206
Joined: Tue Oct 20, 2020 3:35 pm

Re: wxDC how to draw on a wxPanel?

Post by apoorv569 » Wed May 05, 2021 7:53 am

doublemax wrote:
Wed May 05, 2021 7:31 am
You're not showing one important part, where/how you bind the event handler. You're probably binding it to the frame instead of the panel.
You mean this,

Code: Select all

    this->Connect(wxEVT_PAINT, wxPaintEventHandler(Browser::OnPaint));
    this->Centre();
changing this to m_TopPanel gives me this error,

GDB output

Code: Select all

(SampleHive:2098423): Gtk-CRITICAL **: 13:20:04.684: gtk_box_gadget_distribute: assertion
'size >= 0' failed in GtkCheckButton
./src/common/wincmn.cpp(1703): assert "!m_hasFont" failed in GetFont(): we have invalid explicit font?

(SampleHive:2098423): Gtk-WARNING **: 13:20:04.792: gtk_window_set_titlebar() called on a
realized window
[Thread 0x7ffff30ba640 (LWP 2098435) exited]
[Detaching after vfork from child process 2098695]
[Thread 0x7ffff23a4640 (LWP 2098437) exited]

Thread 1 "SampleHive" received signal SIGSEGV, Segmentation fault.
0x00007ffff7917e23 in wxWindowBase::GetFont() const () from /usr/lib/libwx_gtk3u_core-3.0.so.0
(gdb)

User avatar
doublemax
Moderator
Moderator
Posts: 16018
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxDC how to draw on a wxPanel?

Post by doublemax » Wed May 05, 2021 8:15 am

Code: Select all

this->Connect(wxEVT_PAINT, wxPaintEventHandler(Browser::OnPaint));
Yes, you're catching the wxEVT_PAINT event of the frame. In its event handler you can only draw onto the frame, not onto anyhing else.

Use:

Code: Select all

m_TopPanel->Bind(wxEVT_PAINT, &Browser::OnPaint, this);
Even cleaner would be to subclass wxPanel and move the paint event handler there.
changing this to m_TopPanel gives me this error,
There must be something else wrong, can you post the whole frame ctor?
Use the source, Luke!

PB
Part Of The Furniture
Part Of The Furniture
Posts: 3042
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxDC how to draw on a wxPanel?

Post by PB » Wed May 05, 2021 8:30 am

doublemax wrote:
Wed May 05, 2021 8:15 am
changing this to m_TopPanel gives me this error,
There must be something else wrong, can you post the whole frame ctor?
To me it seems like the usual Connect() mistake with the wrong event sink (handler method belongs to Browser but it will be called with a wxPanel instance), easily avoided by using Bind() as you showed.

apoorv569
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 206
Joined: Tue Oct 20, 2020 3:35 pm

Re: wxDC how to draw on a wxPanel?

Post by apoorv569 » Wed May 05, 2021 9:00 am

Was trying something, adding this seems to fix the problem,

Code: Select all

    m_TopPanel->Connect(wxEVT_PAINT, wxPaintEventHandler(Browser::OnPaint), NULL, this);
    m_TopPanel->Centre();
doublemax wrote:
Wed May 05, 2021 8:15 am
Use:

Code: Select all

m_TopPanel->Bind(wxEVT_PAINT, &Browser::OnPaint, this);
Even cleaner would be to subclass wxPanel and move the paint event handler there.
Bind() also works.

Post Reply