How to draw only completely visible items in wxScrolledCanvas 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
fishnet37222
Experienced Solver
Experienced Solver
Posts: 74
Joined: Sat May 06, 2017 1:40 pm

How to draw only completely visible items in wxScrolledCanvas

Post by fishnet37222 »

I'm creating my own custom control that derives from wxScrolledCanvas. I've noticed an issue when I set the vertical scroll rate to be the height of one of the items. If the height of the control itself isn't an exact multiple of the item height, then there's a duplicate item drawn when I scroll to the bottom of the control as shown in the screenshot below. The partial green block at the bottom should not be there.

2021-04-10_23-10-39.png
2021-04-10_23-10-39.png (827 Bytes) Viewed 1060 times

Here is my paint event code:

Code: Select all

void ColorList::ColorList_Paint(wxPaintEvent& event)
{
	wxAutoBufferedPaintDC dc(this);
	this->DoPrepareDC(dc);
	auto* gc = wxGraphicsContext::Create(dc);
	
	auto size = this->GetVirtualSize();
	
	gc->SetBrush(wxTheColourDatabase->Find("WHITE"));
	gc->SetPen(wxTheColourDatabase->Find("WHITE"));
	gc->DrawRectangle(0, 0, size.GetWidth(), size.GetHeight());

	auto actualSize = this->GetClientSize();
	auto viewStart = this->GetViewStart();
	
	gc->SetPen(wxTheColourDatabase->Find("BLACK"));
	for (auto i = 0; i < this->colors.size(); i++)
	{
		auto drawX = 5;
		auto drawY = 5 + this->itemHeight * i;
		auto drawWidth = size.GetWidth() - 10;
		auto drawHeight = this->itemHeight - 10;
		
//		if ((drawY < viewStart.y * this->itemHeight) || (drawY + drawHeight > viewStart.y * this->itemHeight + actualSize.GetHeight()))
//		{
//			continue;
//		}
		
		gc->SetBrush(this->colors[i]);
		gc->DrawRectangle(drawX, drawY, drawWidth, drawHeight);
	}
	
	delete gc;
}
The commented out code is what I tried to use to work around the issue. When I uncomment it, I get other drawing issues, such as partially drawn items as shown in this screenshot:

2021-04-10_23-48-57.png
2021-04-10_23-48-57.png (3.09 KiB) Viewed 1060 times

What is the proper way to only draw the items that are completely visible within the scroll view?
Dave F.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to draw only completely visible items in wxScrolledCanvas

Post by doublemax »

Try adding the wxFULL_REPAINT_ON_RESIZE window style flag. Despite its name, it sometimes fixed redraw issues in scrolled windows, even when they're happening while scrolling, not resizing.
Use the source, Luke!
fishnet37222
Experienced Solver
Experienced Solver
Posts: 74
Joined: Sat May 06, 2017 1:40 pm

Re: How to draw only completely visible items in wxScrolledCanvas

Post by fishnet37222 »

I already have that style applied.

Code: Select all

ColorList::ColorList(wxWindow* parent, wxWindowID id, std::initializer_list<wxColour> colors) : colors(colors)
{
	this->SetBackgroundStyle(wxBG_STYLE_PAINT);
	this->Create(parent, id, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE | wxVSCROLL | wxBORDER_SIMPLE);
	this->Bind(wxEVT_PAINT, &ColorList::ColorList_Paint, this);
	this->CalcVirtualSize();
}
Dave F.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to draw only completely visible items in wxScrolledCanvas

Post by doublemax »

Can you create a minimal, compilable sample that shows the problem?
Use the source, Luke!
fishnet37222
Experienced Solver
Experienced Solver
Posts: 74
Joined: Sat May 06, 2017 1:40 pm

Re: How to draw only completely visible items in wxScrolledCanvas

Post by fishnet37222 »

I created a small sample and pushed it to my GitHub. You can access it from the following link: https://github.com/fishnet37222/ScrollSample
Dave F.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to draw only completely visible items in wxScrolledCanvas

Post by doublemax »

I didn't have time for a deeper look, but the clearing of the background with DrawRectangle() seems to be the problem. If i just add dc.Clear() before or after DoPrepareDC(), the redraw issue goes away.
Use the source, Luke!
Post Reply