LCL/TreeView: Avoid flicker when hot-tracking is active. Based on patch by @d7_2_laz, issue #41290.

This commit is contained in:
wp_xyz 2025-01-20 11:37:25 +01:00
parent baef5a1511
commit e897d845ea
2 changed files with 38 additions and 1 deletions

View File

@ -3453,6 +3453,7 @@ type
FMouseDownOnFoldingSign: Boolean; FMouseDownOnFoldingSign: Boolean;
FMultiSelectStyle: TMultiSelectStyle; FMultiSelectStyle: TMultiSelectStyle;
FHotTrackColor: TColor; FHotTrackColor: TColor;
FHotTrackedPrevNodeIdx: Integer;
FDisabledFontColor: TColor; FDisabledFontColor: TColor;
FOnAddition: TTVExpandedEvent; FOnAddition: TTVExpandedEvent;
FOnAdvancedCustomDraw: TTVAdvancedCustomDrawEvent; FOnAdvancedCustomDraw: TTVAdvancedCustomDrawEvent;

View File

@ -3498,6 +3498,7 @@ begin
FTreeLinePenPattern[1] := 1; FTreeLinePenPattern[1] := 1;
FExpandSignColor := clWindowFrame; FExpandSignColor := clWindowFrame;
FHotTrackColor := clNone; FHotTrackColor := clNone;
FHotTrackedPrevNodeIdx := -1;
FDisabledFontColor := clGrayText; FDisabledFontColor := clGrayText;
FPathDelimiter := '/'; FPathDelimiter := '/';
// Accessibility // Accessibility
@ -6011,6 +6012,9 @@ begin
end; end;
procedure TCustomTreeView.UpdateHotTrack(X, Y: Integer); procedure TCustomTreeView.UpdateHotTrack(X, Y: Integer);
var
lNode, nodeUnderCursorY: TTreeNode;
R: TRect;
begin begin
FNodeUnderCursor := nil; FNodeUnderCursor := nil;
if Cursor = crHandPoint then if Cursor = crHandPoint then
@ -6020,7 +6024,38 @@ begin
FNodeUnderCursor := GetNodeAt(X, Y); FNodeUnderCursor := GetNodeAt(X, Y);
if Assigned(FNodeUnderCursor) then if Assigned(FNodeUnderCursor) then
Cursor := crHandPoint; Cursor := crHandPoint;
Invalidate;
// Invalidate;
// Too global, can lead to massive flicker (issue #41290). Replaced by code below.
// Invalidate only the affected lines (at least if not MultiSelect)
// Affected lines are: where the cursor is now, and where it was before.
if Self.MultiSelect then
Invalidate
else
begin
// Invalidate the previous hot node
nodeUnderCursorY := GetNodeAtY(Y); // Instead of GetNodeAt(X, Y). Need to trigger redraw across full row for OwnerDraw
if FHotTrackedPrevNodeIdx >= Items.Count then
FHotTrackedPrevNodeIdx := -1;
if FHotTrackedPrevNodeIdx > -1 then
begin
lNode := Items[FHotTrackedPrevNodeIdx];
if Assigned(lNode) and lNode.Visible then
begin
R := lNode.DisplayRect(False);
InvalidateRect(Handle, @R, True);
end;
FHotTrackedPrevNodeIdx := -1;
end;
// Invalidate the current hot node
if Assigned(nodeUnderCursorY) then
begin
R := nodeUnderCursorY.DisplayRect(False);
InvalidateRect(Handle, @R, True);
FHotTrackedPrevNodeIdx := nodeUnderCursorY.AbsoluteIndex;
end;
end;
end; end;
procedure TCustomTreeView.MouseUp(Button: TMouseButton; Shift: TShiftState; procedure TCustomTreeView.MouseUp(Button: TMouseButton; Shift: TShiftState;
@ -6238,6 +6273,7 @@ begin
if tvoHotTrack in FOptions then if tvoHotTrack in FOptions then
begin begin
FNodeUnderCursor:=nil; FNodeUnderCursor:=nil;
FHotTrackedPrevNodeIdx:=-1;
Cursor:=crDefault; Cursor:=crDefault;
Invalidate; Invalidate;
end; end;