I have a
PaintBox embedded in a
ScrollBox that can be stretched. The
PaintBox can be large in size (e.g.
256×4096), which makes the
ScrollBox.VerticalScrollBar useful for scrolling. In
PaintBox, I render the grid, but for efficient rendering, instead of repainting the entire component, I only repaint the grid cells that fit in
PaintBox.Canvas.ClipRect — of course, the rendering is in the
PaintBox.OnPaint event.
Everything works very efficiently, but there is a problem — if I grab the
ScrollBox slider with my mouse and move it up/down quickly, holes fall out in the
PaintBox. The faster I scroll the
ScrollBox, the bigger the holes fall out. Interestingly, the background is rendered (
clMenu color), but the cells are clipped. Each cell is a separate
TPortableNetworkGraphic, so painting the cell is limited to
PaintBox.Canvas.Draw call.
The
PaintBox.OnPaint code looks like this:
procedure TFormMain.PaintBoxStampsPaint(ASender: TObject);
var
PaintBox: TPaintBox absolute ASender;
var
VisibleRect: TRect;
VisibleCellFirst: Integer;
VisibleCellLast: Integer;
var
ItemIndex: Integer;
ItemRect: TRect;
ItemStyle: TTextStyle;
begin
// Get the rect that has to be repainted.
VisibleRect := PaintBox.Canvas.ClipRect;
// Calculate the index of the first and last cell (checked, calculations are valid)
VisibleCellFirst := (VisibleRect.Top div FontsEditor.Buffers.CellHeight) * FontsEditor.Grid.SizeX;
VisibleCellLast := VisibleCellFirst + (VisibleRect.Height div FontsEditor.Buffers.CellHeight) * FontsEditor.Grid.SizeX - 1;
if VisibleRect.Bottom mod FontsEditor.Buffers.CellHeight > 0 then
VisibleCellLast += FontsEditor.Grid.SizeX;
VisibleCellLast := Min(VisibleCellLast, FontsEditor.Grid.ItemIndexLast);
// Paint the background under all cells that have to be repainted.
PaintBox.Canvas.Brush.Color := clMenu;
PaintBox.Canvas.FillRect(VisibleRect);
// Paint all cells that intersects with the "PaintBox.Canvas.ClipRect" rect.
for ItemIndex := VisibleCellFirst to VisibleCellLast do
begin
// Get calculated rect of the cell (checked, calculations are valid)
ItemRect := FontsEditor.Grid.ItemRect[ItemIndex];
// Get the cell graphic and draw it.
PaintBox.Canvas.Draw(ItemRect.Left, ItemRect.Top, FontsEditor.Buffers.Cell[ItemIndex]);
// Render the item index inside the cell.
ItemStyle := PaintBox.Canvas.TextStyle;
ItemStyle.Alignment := taCenter;
ItemStyle.Layout := tlCenter;
PaintBox.Canvas.TextRect(ItemRect, 0, 0, ItemIndex.ToString(), ItemStyle);
end;
end;
You can see the results of this code in the attachments:
- After the program window appears on the screen (correct appearance).
- After scrolling with the mouse wheel (also correct appearance).
- After scrolling with the ScrollBox slider — it contains empty bars with the background color (clMenu), but the graphics are not completely painted?
Why do these things happen?