Below, it should probably be considered a workaround for the defective behavior of the OS, because if the themes are not included, the standard window procedure of the list control does fine with finger tracking. For some reason, when themes are turned on (the test is shown here with Vista and later), the control relies on Word scroll position data of size WM_VSCROLL .
First, a simple project to duplicate the problem below is a list of the virtual (owner) drawing of the owner ( lbVirtualOwnerDraw ) with 600,000 elements (since the data for the element is not cached, it does not take a minute to fill in the field). A high list will be good for easily following the behavior:
type TForm1 = class(TForm) ListBox1: TListBox; procedure ListBox1Data(Control: TWinControl; Index: Integer; var Data: string); procedure ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); procedure FormCreate(Sender: TObject); end; [...] procedure TForm1.FormCreate(Sender: TObject); begin ListBox1.Count := 600000; end; procedure TForm1.ListBox1Data(Control: TWinControl; Index: Integer; var Data: string); begin Data := IntToStr(Index) + ' listbox item number'; end; procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); begin // just simple drawing to be able to clearly see the items if odSelected in State then begin ListBox1.Canvas.Brush.Color := clHighlight; ListBox1.Canvas.Font.Color := clHighlightText; end; ListBox1.Canvas.FillRect(Rect); ListBox1.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, ListBox1.Items[Index]); end;
To see the problem, just drag the mouse over the scroll bar, you will notice how the elements are wrapped to start from the beginning for each 65536, as described by Arno in the comments on the question. And when you release your thumb, it will be attached to the item at the top of High(Word) .
Below the workaround, it hooks WM_VSCROLL on the control and manually adjusts the thumb and position. The sample uses the interpolator class for simplicity, but any other subclass method:
type TListBox = class(stdctrls.TListBox) private procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL; end; [...] procedure TListBox.WMVScroll(var Msg: TWMVScroll); var Info: TScrollInfo; begin // do not intervene when themes are disabled if ThemeServices.ThemesEnabled then begin Msg.Result := 0; case Msg.ScrollCode of SB_THUMBPOSITION: Exit; // Nothing to do, thumb is already tracked SB_THUMBTRACK: begin ZeroMemory(@Info, SizeOf(Info)); Info.cbSize := SizeOf(Info); Info.fMask := SIF_POS or SIF_TRACKPOS; if GetScrollInfo(Handle, SB_VERT, Info) and (Info.nTrackPos <> Info.nPos) then TopIndex := TopIndex + Info.nTrackPos - Info.nPos; end; else inherited; end; end else inherited; end;
Sertac akyuz
source share