In a 32-bit VCL Application in Windows 10 in Delphi 11 Alexandria, I am trying to be notified when I END the horizontal scrolling in a TListView
with this interposer class code:
type
TListView = class(Vcl.ComCtrls.TListView)
private
procedure WMNotify(var AMessage: TWMNotify); message WM_NOTIFY; // used for other purposes
procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
procedure WMVScroll(var Msg: TWMHScroll); message WM_VSCROLL;
procedure WMHScroll(var Msg: TWMHScroll); message WM_HSCROLL;
protected
procedure CreateWnd; override;
end;
implementation
procedure TListView.CNCommand(var Message: TWMCommand);
begin
case Message.NotifyCode of
EN_VSCROLL: CodeSite.Send('TListView.CNCommand: EN_VSCROLL'); // does not work
EN_HSCROLL: CodeSite.Send('TListView.CNCommand: EN_HSCROLL'); // does not work
end;
inherited ;
end;
procedure TListView.WMHScroll(var Msg: TWMHScroll);
begin
CodeSite.Send('TListView.WMHScroll: WM_HSCROLL'); // does work
inherited;
end;
procedure TListView.WMVScroll(var Msg: TWMHScroll);
begin
CodeSite.Send('TListView.WMVScroll: WM_VSCROLL'); // does work
inherited;
end;
However, only WHILE scrolling I get constantly notified by WM_HSCROLL
and WM_VSCROLL
generating a lot of messages.
But I need to be notified only at the END of the horizontal scrolling! Is this possible?
CodePudding user response:
The comments given to the Q are very relevant.
First, as Remy Lebeau stated, the WM_HSCROLL
message tells you if the operation is done:
procedure TListView.WMHScroll(var Msg: TWMHScroll);
begin
inherited;
if Msg.ScrollCode = SB_ENDSCROLL then
ShowMessage('End scroll')
end;
However, this only lets you know when a scrolling operation initiated by the horizontal scroll bar is done. Currently, this includes these scroll-bar operations:
- Thumb released
- Scroll bar LEFT or RIGHT button clicked
- Scroll bar empty area clicked (for page scroll)
- Scroll bar context menu item selected
But there are many other ways the list view control can be scrolled, which have nothing to do with the scroll bar:
- Using your mouse's horizontal scrolling wheel (or the standard vertical wheel if there is only a horizontal scroll bar and no vertical one)
- Using your keyboard's left and right arrow keys (or Ctrl Left/Right for page scroll)
- With
MultiSelect = True
, making a selection rectangle with the mouse (start dragging outside any list-view item)
Hence, by reacting only to WM_HSCROLL
, you will not detect these scrolling events. Almost certainly, you want to react when the scroll position has changed, no matter how it was changed.
And, as AmigoJack wrote, it is not absolutely clear what "end" means (other than when you release the mouse button after having dragging the scroll bar thumb). For instance, if you scroll using your mouse wheel, is the result a single large scroll operation or several small ones? After all, in any case, even thumb tracking, the control repaints itself at every small step.
So probably your best option is to use
procedure TListView.CNNotify(var Message: TMessage);
begin
inherited;
if PNMHDR(Message.lParam).code = LVN_ENDSCROLL then
// Scrolled
end;
According to the documentation,
Notifies a list-view control's parent window when a scrolling operation ends.
Notice that the documentation says that the notification is sent when the operation ends. Still, you will find that it is sent for every small update while you drag the scroll bar thumb. As mentioned above, this is reasonable: scrolling has indeed been performed after every such small step.