Here's a window with a splitter and a wrap sizer. To reproduce the problem, move the sash until drawing artifacts appear.
#include <wx/wx.h> #include <wx/wrapsizer.h> #include <wx/splitter.h> class MyApp : public wxApp { public: virtual bool OnInit(); }; wxIMPLEMENT_APP(MyApp); class MyFrame : public wxFrame { public: MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size); }; bool MyApp::OnInit() { MyFrame *frame = new MyFrame("Hello World", wxDefaultPosition, wxDefaultSize); frame->Show(true); return true; } MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size) : wxFrame(nullptr, wxID_ANY, title, pos, size) { wxSplitterWindow *splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_BORDER | wxSP_LIVE_UPDATE); splitter->SetMinimumPaneSize(FromDIP(150)); auto controlsPanel = new wxScrolled<wxPanel>(splitter); controlsPanel->SetScrollRate(0, FromDIP(10)); auto controlsSizer = new wxBoxSizer(wxVERTICAL); auto text = new wxStaticText(controlsPanel, wxID_ANY, "Panes:"); controlsSizer->Add(text, 0, wxALL, FromDIP(5)); auto paneSizer = new wxWrapSizer(wxHORIZONTAL); for (int i = 0; i < 10; i++) { auto p = new wxPanel(controlsPanel, wxID_ANY, wxDefaultPosition, FromDIP(wxSize(45, 45))); p->SetBackgroundColour(*wxRED); paneSizer->Add(p, 0, wxRIGHT | wxBOTTOM, FromDIP(3)); } controlsSizer->Add(paneSizer, 0, wxALL, FromDIP(5)); controlsPanel->SetSizer(controlsSizer); auto rightPanel = new wxPanel(splitter); splitter->SplitVertically(controlsPanel, rightPanel); splitter->SetSashPosition(FromDIP(220)); this->SetSize(FromDIP(800), FromDIP(400)); this->SetMinSize({FromDIP(400), FromDIP(200)}); }
This mainly reproduces on Linux:
With custom controls instead of wxPanel
things may get even more ugly:
#include <wx/wx.h> #include <wx/wrapsizer.h> #include <wx/splitter.h> #include <wx/graphics.h> #include <wx/dcbuffer.h> class MyApp : public wxApp { public: virtual bool OnInit(); }; wxIMPLEMENT_APP(MyApp); class MyFrame : public wxFrame { public: MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size); }; bool MyApp::OnInit() { MyFrame *frame = new MyFrame("Hello World", wxDefaultPosition, wxDefaultSize); frame->Show(true); return true; } class SelectablePane : public wxWindow { public: SelectablePane(wxWindow *parent, wxWindowID id, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize); wxSize DoGetBestSize() const override { return FromDIP(wxSize(45, 45)); } bool selected = false; private: void OnPaint(wxPaintEvent &evt); }; MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size) : wxFrame(nullptr, wxID_ANY, title, pos, size) { wxSplitterWindow *splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_BORDER | wxSP_LIVE_UPDATE); splitter->SetMinimumPaneSize(FromDIP(150)); auto controlsPanel = new wxScrolled<wxPanel>(splitter); controlsPanel->SetScrollRate(0, FromDIP(10)); auto controlsSizer = new wxBoxSizer(wxVERTICAL); auto text = new wxStaticText(controlsPanel, wxID_ANY, "Panes:"); controlsSizer->Add(text, 0, wxALL, FromDIP(5)); auto paneSizer = new wxWrapSizer(wxHORIZONTAL); for (int i = 0; i < 15; i++) { auto p = new SelectablePane(controlsPanel, wxID_ANY); paneSizer->Add(p, 0, wxRIGHT | wxBOTTOM, FromDIP(3)); } controlsSizer->Add(paneSizer, 0, wxALL, FromDIP(5)); controlsPanel->SetSizer(controlsSizer); auto rightPanel = new wxPanel(splitter); splitter->SplitVertically(controlsPanel, rightPanel); splitter->SetSashPosition(FromDIP(220)); this->SetSize(FromDIP(800), FromDIP(400)); this->SetMinSize({FromDIP(400), FromDIP(200)}); } // wxFULL_REPAINT_ON_RESIZE needed for Windows SelectablePane::SelectablePane(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size) : wxWindow(parent, id, pos, size, wxFULL_REPAINT_ON_RESIZE) { this->SetBackgroundStyle(wxBG_STYLE_PAINT); // needed for windows this->Bind(wxEVT_PAINT, &SelectablePane::OnPaint, this); } void SelectablePane::OnPaint(wxPaintEvent &evt) { wxAutoBufferedPaintDC dc(this); dc.Clear(); auto gc = wxGraphicsContext::Create(dc); if (gc) { wxRect selectionRect{0, 0, this->GetSize().GetWidth(), this->GetSize().GetHeight()}; selectionRect.Deflate(FromDIP(1)); const auto roundness = 5; gc->SetPen(*wxYELLOW_PEN); gc->SetBrush(*wxBLACK_BRUSH); gc->DrawRoundedRectangle(selectionRect.GetX(), selectionRect.GetY(), selectionRect.GetWidth(), selectionRect.GetHeight(), roundness); gc->SetPen(*wxWHITE_PEN); gc->SetBrush(*wxWHITE_BRUSH); auto pw = FromDIP(8); gc->DrawEllipse(selectionRect.GetX() + selectionRect.GetWidth() / 2 - pw / 2, selectionRect.GetY() + selectionRect.GetHeight() / 2 - pw / 2, pw, pw); delete gc; } }
It's more difficult to reproduce it on Mac or Windows. The worst behavior I could get was not wrapping (without any drawing artifacts):
ā
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
Here's a simpler app that reproduces this bug every time on Mac, Windows, and Linux. The layout is simple:
controlsSizer
(vertical wxBoxSizer
)
hideButton
,showButton
,groupSizer
(vertical wxBoxSizer
)
text
describing the group,paneSizer
(horizontal wxWrapSizer
)
wxPanel
sgroupSizer
(vertical wxBoxSizer
)
text
describing the group,paneSizer
(horizontal wxWrapSizer
)
wxPanel
sThe idea is to control the visibility of the last group with the hide/show buttons.
Problems:
You need to resize the window a bit, then the panels appear, and wxWrapSizers
work as expected... until we play around with the hide/show buttons.
#include <wx/wx.h> #include <wx/wrapsizer.h> #include <wx/splitter.h> class MyApp : public wxApp { public: virtual bool OnInit(); }; wxIMPLEMENT_APP(MyApp); class MyFrame : public wxFrame { public: MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size); }; bool MyApp::OnInit() { MyFrame *frame = new MyFrame("Hello World", wxDefaultPosition, wxDefaultSize); frame->Show(true); return true; } MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size) : wxFrame(nullptr
, wxID_ANY, title, pos, size) { auto controlsPanel = new wxPanel(this);
auto controlsSizer = new wxBoxSizer
(wxVERTICAL); auto hideButton = new wxButton(controlsPanel, wxID_ANY, "Hide"); controlsSizer->Add(hideButton, 0, wxALL, FromDIP(5)); auto showButton = new wxButton(controlsPanel, wxID_ANY, "Show"); controlsSizer->Add(showButton, 0, wxALL, FromDIP(5)); wxSizer *sizerToHide = nullptr; for (int g = 0; g < 2; g++) { auto groupSizer = new wxBoxSizer(wxVERTICAL);
auto text = new wxStaticText(controlsPanel, wxID_ANY, "Panes:"
); groupSizer->Add(text, 0, wxALL, FromDIP(5));
auto paneSizer = new wxWrapSizer(wxHORIZONTAL); for (int i = 0; i < 10; i++) { auto p = new wxPanel(controlsPanel, wxID_ANY, wxDefaultPosition, FromDIP(wxSize(45, 45))); p->SetBackgroundColour(*wxRED); paneSizer->Add(p, 0, wxRIGHT | wxBOTTOM, FromDIP(3
)); } groupSizer->Add(paneSizer, 0, wxALL, FromDIP(5)); controlsSizer->Add(groupSizer, 0, wxEXPAND); sizerToHide = groupSizer; } controlsPanel->SetSizer(controlsSizer); this->SetSize(FromDIP(200), FromDIP(700)); this->SetMinSize({FromDIP(100), FromDIP(200)}); showButton->Bind(wxEVT_BUTTON, [controlsSizer, sizerToHide, this](wxCommandEvent &event) { controlsSizer->Show(sizerToHide, true, true); controlsSizer->Layout(); }); hideButton->Bind(wxEVT_BUTTON, [controlsSizer, sizerToHide](wxCommandEvent &event) { controlsSizer->Hide(sizerToHide, true); controlsSizer->Layout(); }); }
ā
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
FWIW this definitely doesn't look right, but I don't much about wxWrapSizer
and just have no time to debug it right now. If anybody could look into this, it would be really great...
ā
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.