Home > Net >  How to be notified at the END of Horizontal Scrolling in TListView?
How to be notified at the END of Horizontal Scrolling in TListView?

Time:02-14

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.

  • Related