Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

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
deepti
Earned some good credits
Earned some good credits
Posts: 115
Joined: Tue Jul 17, 2018 5:38 pm

Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by deepti » Mon Jul 23, 2018 4:37 am

Hi All,

I have my own class "AGE_ScrolledWindow", derived from wxScrolledWindow. Then there is an "Add" button. On click of this button, I add an instance of "wxCollapsiblePane". So, when the user clicks the "Add" button many times, several instances of "wxCollapsiblePane" are created.
When a new "wxCollapsiblePane" is added, scrollbar should go to the bottom, so that the newly added control is visible. I am achieving this through the "OnSize" handler of "AGE_ScrolledWindow", as below and it works fine.

Code: Select all

void AGE_ScrolledWindow::OnSize(wxSizeEvent& Event)
{
wxScrolledWindow::HandleOnSize(Event);

int r = GetScrollLines(wxVERTICAL);

SetScrollPos(wxVERTICAL, r);
Scroll(0, r);

Refresh();
Update();
}
But, the problem is when I expand/collapse any of these "wxCollapsiblePane", the scrollbar should not hit the bottom of the wxScrolledWindow. Instead, it should show the currently selected wxCollapsiblePane instance.

However, what I do see is that if i open some other window (any random application), and then re-open my dialog box again, the view is correct. That is the repainting of window happens and then it shows the correct view (of the currently selected wxCollapsiblePane instance).
But, how can I achieve this repainting of the new scrolled position immediately (as soon as a wxCollapsiblePane instance is collapsed or expanded) ?

This is what I have written in handler for wxEVT_COLLAPSIBLEPANE_CHANGED event. But it is still not repainting immediately.

Code: Select all

void PropertiesDialog::OnMetaDataControlExpand(wxCollapsiblePaneEvent& event)
{

wxCollapsiblePane* p = dynamic_cast<wxCollapsiblePane*>(event.GetEventObject());
p->SetFocus();
wxPoint pt = p->GetPosition();

m_metaDataScrolledWindow->Scroll(0, pt.y/16);
m_metaDataScrolledWindow->SetScrollPos(wxVERTICAL, pt.y/16);
wxClientDC dc(m_metaDataScrolledWindow);
m_metaDataScrolledWindow->DoPrepareDC(dc);

p->Refresh();
p->Update();
m_metaDataScrolledWindow->Refresh();
m_metaDataScrolledWindow->Update();
RefreshRect(m_metaDataScrolledWindow->GetClientRect());
Update();


m_metaDataScrolledWindow->FitInside();
m_metaDataControlsbox->FitInside(m_metaDataScrolledWindow);
m_metaDataScrolledWindow->Refresh();
m_metaDataControlsbox->SetSizeHints(m_metaDataScrolledWindow);
m_metaDataControlsbox->Layout();
}
Please help!

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

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by doublemax » Mon Jul 23, 2018 4:55 am

Please try to create minimal, compilable sample that shows the problem.
Use the source, Luke!

deepti
Earned some good credits
Earned some good credits
Posts: 115
Joined: Tue Jul 17, 2018 5:38 pm

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by deepti » Tue Jul 24, 2018 10:21 am

Thank you again for your reply.
Please find attached the minimal sample .cpp and .h files.
Also, I have recorded a video showing the repainting issue. The video can be found at the link below:

https://drive.google.com/file/d/1u_55NC ... sp=sharing

Please do help! Thanks a lot in advance!!
Attachments
PropertiesDialog.h
(1.53 KiB) Downloaded 20 times
PropertiesDialog.cpp
(7.09 KiB) Downloaded 20 times

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

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by doublemax » Tue Jul 24, 2018 6:13 pm

Sorry, but this is not a compilable sample, it has several external dependencies and i won't spend half an hour to make it work.

So, just some general comments without begin able to test it myself.

1) Why is the code to scroll to be bottom in the OnSize handler? Do you really want to scroll to be bottom each time the size of the window changes? You should know that during a Layout() call, it's possible that there are size events happening. I'm almost certain this is the core of your problem.

2) You should only execute the code to scroll to the bottom after you added a new element to the window.

3) The code in OnRefreshMetadataPage and OnMetaDataControlExpand looks far too complicated. I'm sure you don't need most of it. I guess these are all the experiments trying to get the result you want.
Use the source, Luke!

deepti
Earned some good credits
Earned some good credits
Posts: 115
Joined: Tue Jul 17, 2018 5:38 pm

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by deepti » Wed Jul 25, 2018 6:33 am

Thank you @doublemax!!!! You are a savior!!! You saved my day!! Please accept my greatest thanks :-))

"You should know that during a Layout() call, it's possible that there are size events happening" ---this was it!!
I was trying to set the new scroll position before the call to Layout(). Since, that didn't work, I introduced the OnSize() handler and that screwed up the whole thing..
Setting the scroll position before the call to Layout() fixed the issue for me. Thanks a lot once again :)

And yes, I've cleaned up OnRefreshMetadataPage and OnMetaDataControlExpand functions. Those had desperate function calls in an attempt to fix the issue.

Just one more question for now - Is there a way we can get all controls of a specific type through some wxWindow function. Like say, I want all instances of wxCollapsiblePane that are present in a window. I basically need to collapse all of them in one shot.

Thanks in advance!

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

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by doublemax » Wed Jul 25, 2018 6:43 am

Just one more question for now - Is there a way we can get all controls of a specific type through some wxWindow function. Like say, I want all instances of wxCollapsiblePane that are present in a window. I basically need to collapse all of them in one shot.
Not with one single call. You could use wxWindow::GetChildren() to get a list of all children. But you'd still have to iterate over the list and check the type of the window, e.g. with wxDynamicCast().

http://docs.wxwidgets.org/trunk/classwx ... 706c91a494
http://docs.wxwidgets.org/trunk/group__ ... 4a6df3c38a
Use the source, Luke!

deepti
Earned some good credits
Earned some good credits
Posts: 115
Joined: Tue Jul 17, 2018 5:38 pm

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by deepti » Thu Jul 26, 2018 6:44 am

Yes, I thought as much too. Thank you for confirming.

One more question I now have is, how I can set the minimum width of the wxCollapsiblePane?
By calling the SetMinSize(400, 0) function on the sizer containing the wxCollapsiblePane instance, it works fine when I expand the pane. The width is set to 400. But, even when it is not expanded, I want the width to be 400 (i.e, it should occupy most of the dialog's width).
Attached is a screenshot showing the issue (width is set to 400 only when expanded, and not otherwise).
wxCollapsible-minWidthIssue.png
wxCollapsible-minWidthIssue.png (44.9 KiB) Viewed 1859 times
Could you please help with this?

Thank you!!

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

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by doublemax » Thu Jul 26, 2018 7:20 am

calling the SetMinSize(400, 0) function on the sizer
Did you try calling SetMinSize() for the wxCollapsiblePane itself?

BTW:

Code: Select all

	wxBoxSizer* item1 = new wxBoxSizer(wxVERTICAL);

	wxCollapsiblePane *collpane = new wxCollapsiblePane(m_metaDataScrolledWindow, collpaneID, "Details", wxDefaultPosition/*, wxSize(600, 800)*/);
	// add the pane with a zero proportion value to the 'sz' sizer which contains it
	item1->Add(collpane, 0, wxEXPAND | wxALL, 5);
	itemGridSizer->Add(item1);
A sizer that only contains one element usually doesn't make sense. Why are you not adding collpane directly into itemGridSizer?
Use the source, Luke!

deepti
Earned some good credits
Earned some good credits
Posts: 115
Joined: Tue Jul 17, 2018 5:38 pm

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by deepti » Thu Jul 26, 2018 9:45 am

Thank you for your reply.

"Did you try calling SetMinSize() for the wxCollapsiblePane itself?" --yes, I have tried that as well. It does set the initial (when not expanded) width correctly. But when expanded, the size remains the same. It does not show the controls correctly as seen in the screenshot below:

Regarding your question on why I put the wxCollapsiblePane in a sizer, I actually have one big sizer (itemGridSizer) containing 2 more sizers - the first sizer contains the wxCollapsiblePane instance, and the second sizer is for the "Remove" button.
wxCollapsible-minWidthIssue.png
wxCollapsible-minWidthIssue.png (39.83 KiB) Viewed 1844 times
Thank you!

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

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by doublemax » Thu Jul 26, 2018 11:51 am

I actually have one big sizer (itemGridSizer) containing 2 more sizers - the first sizer contains the wxCollapsiblePane instance, and the second sizer is for the "Remove" button.
That's what i mean. A sizer that contains only 1 element usually doesn't make sense. You could put the wxCollapsiblePane and the remove button into one sizer. This is not the cause for the problem, but makes the sizer code more complicated than necessary.

I built a small sample that shows how i would have done this. Maybe it contains some parts you can use. The file is a replacement for "minimal.cpp" from the "minimal" sample. Just rename the old file, replace it with this one and it should compile and run.
Attachments
minimal.cpp
(8.5 KiB) Downloaded 31 times
Use the source, Luke!

deepti
Earned some good credits
Earned some good credits
Posts: 115
Joined: Tue Jul 17, 2018 5:38 pm

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by deepti » Thu Jul 26, 2018 1:45 pm

Sure, I get your point. Will make changes accordingly.
But as you mentioned, the width of the wxCollapsiblePane instance does not change still. Any ideas on that please.
I have called the SetMinimumWidth on the collapsible pane directly, it's window (GetPane()) and the sizer. But none of that is helping :(
Will be grateful if you could give some pointers.

Thanks in advance..

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

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by doublemax » Thu Jul 26, 2018 2:52 pm

Do you really want a fixed size or do you just want the panes to extend to the right edge of the window? The latter is what i did in my code and it can be achieved by setting the proper wxEXPAND flag in the right places when adding an item to a sizer.
Use the source, Luke!

deepti
Earned some good credits
Earned some good credits
Posts: 115
Joined: Tue Jul 17, 2018 5:38 pm

Re: Refresh/Repainting issue - wxScrolledWindow with many wxCollapsiblePane instances

Post by deepti » Fri Jul 27, 2018 2:35 pm

Yes, I just wanted the panes to extend to the right edge of the window. Got that done, by referring to the code you shared.
Thank you so much @doublemax. You made my life really simple!!

Post Reply