We help IT Professionals succeed at work.

Find out when bottom or top line in a listbox or memo has been displayed

seabear
seabear asked
on
Medium Priority
527 Views
Last Modified: 2010-04-04
I am telling a listbox or memo to scroll down line by line with a perform statement. I want to disable the down button I am using when the user has scrolled to the bottom.

procedure TForm1.sbDownClick(Sender: TObject);
begin
    listbox4.Perform(WM_VSCROLL, SB_LINEDOWN,0);
    if ( ? have scrolled to the bottom ? ) then
    begin
        sbDown.enabled := false;
    end;
end;

How can I find out when the bottom line of the list items or memo lines has been displayed? I will also need to solve a similar problem when scrolling up.

Thanks in advance - Dan
Comment
Watch Question

For a listbox:

sbDown.Enabled := ListBox.ItemIndex < (ListBox.ItemIndex -1);
sbUp.Enabled := ListBox.ItemIndex > 0;

I hope this helps you.

Stu
CERTIFIED EXPERT
Top Expert 2004

Commented:
even for a memo is a message to get the first visible line,
(didn't have in mind the exact name )

just compare it with your lines.count property)
Dammit.  I just re-read my post and realised a mistake:

sbDown.Enabled := ListBox.ItemIndex < (ListBox.Items.Count-1);
sbUp.Enabled := ListBox.ItemIndex > 0;


Sorry 'bout that.

Commented:
I think seabear wants to be notified when the user SCROLLS to the bottom or to the top, and not just when the user SELECTS the top/bottom line/item.

If that's the case, then you'll need to create custom
components derived from TMemo and TListBox that handle
scrollbar events (unless there are some Delphi events I don't know about).

You could do it like this:

//-------------------- BOF Code Snippet -------------------

unit Scrollers;

uses
 Windows, System, Controls; //..... etc

interface

type
  TScrollMemo = class(TMemo)
  private
    FOnScrollToTop, FOnScrollToBottom: TNotifyEvent;
    procedure SetOnScrollToTop(ostt: TNotifyEvent);
    procedure SetOnScrollToBottom(ostb: TNotifyEvent);
  protected
    procedure WMVScroll(var msg: TMessage); message WM_VSCROLL;
    procedure DoOnScrollToTop; virtual;
    procedure DoOnScrollToBottom; virtual;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property OnScrollToTop: TNotifyEvent read FOnScrollToTop write SetOnScrollToTop;
    property OnScrollToBottom: TNotifyEvent read FOnScrollToBottom write SetOnScrollToBottom;
  end;

  TScrollListBox = class(TListBox)
  private
    FOnScrollToTop, FOnScrollToBottom: TNotifyEvent;
    procedure SetOnScrollToTop(ostt: TNotifyEvent);
    procedure SetOnScrollToBottom(ostb: TNotifyEvent);
  protected
    procedure WMVScroll(var msg: TMessage); message WM_VSCROLL;
    procedure DoOnScrollToTop; virtual;
    procedure DoOnScrollToBottom; virtual;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property OnScrollToTop: TNotifyEvent read FOnScrollToTop write SetOnScrollToTop;
    property OnScrollToBottom: TNotifyEvent read FOnScrollToBottom write SetOnScrollToBottom;
  end;

procedure Register;


implementation


procedure Register;
begin
  // !check the syntax of the next line!
  RegisterComponents('MyStandard',[TScrollMemo, TScrollListBox]);
end;

//---------------------- TScrollMemo's implementation ----------------------

constructor TScrollMemo.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FOnScrollToTop := nil;
  FOnScrollToBottom := nil;
end;

procedure TScrollMemo.WMVScroll(var msg: TMessage);
begin
  if msg.wParam = SB_TOP then
    DoScrollToTop
  else
    if msg.wParam = SB_BOTTOM then
      DoScrollToBottom;
end;

procedure TScrollMemo.DoScrollToTop;
begin
  if Assigned(FOnScrollToTop) then
    FOnScrollToTop(Self);
end;

procedure TScrollMemo.DoScrollToBottom;
begin
  if Assigned(FOnScrollToBottom) then
    FOnScrollToBottom(Self);
end;

procedure TScrollMemo.SetOnScrollToTop(ostt: TNotifyEvent);
begin
  FOnScrollToTop := ostt;
end;

procedure TScrollMemo.SetOnScrollToBottom(ostb: TNotifyEvent);
begin
  FOnScrollToBottom := ostb;
end;

//---------------------- TScrollListBox's implementation ----------------------

constructor TScrollListBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FOnScrollToTop := nil;
  FOnScrollToBottom := nil;
end;

procedure TScrollListBox.WMVScroll(var msg: TMessage);
begin
  if msg.wParam = SB_TOP then
    DoScrollToTop
  else
    if msg.wParam = SB_BOTTOM then
      DoScrollToBottom;
end;

procedure TScrollListBox.DoScrollToTop;
begin
  if Assigned(FOnScrollToTop) then
    FOnScrollToTop(Self);
end;

procedure TScrollListBox.DoScrollToBottom;
begin
  if Assigned(FOnScrollToBottom) then
    FOnScrollToBottom(Self);
end;

procedure TScrollListBox.SetOnScrollToTop(ostt: TNotifyEvent);
begin
  FOnScrollToTop := ostt;
end;

procedure TScrollListBox.SetOnScrollToBottom(ostb: TNotifyEvent);
begin
  FOnScrollToBottom := ostb;
end;

end.
You could try something like this:

procedure TForm1.sbDownClick(Sender: TObject);
var
  ScrllInf : TScrollInfo;
begin
  Listbox4.Perform(WM_VSCROLL, SB_LINEDOWN,0);
  FillChar(ScrllInf, SizeOf(ScrllInf), 0);
  with ScrllInf do
  begin
    cbSize := SizeOf(ScrllInf);
    fMask := SIF_ALL;
  end;
  GetScrollInfo(Listbox4.Handle, SB_VERT, ScrllInf);
  if ScrllInf.nPos = Round(ScrllInf.nMax / 2) - 1 then
    sbDown.Enabled := False;
end;

Cheers,

Alan

Author

Commented:
Thanks to everyone who gave answers, Rondi was right in that I wanted to find out when the user scrolls to the end, not if they select the bottom line. Alan I have modified your code slightly, I found that in your code if the user selects a line in the list then goes back to scrolling the disable does not happen, there is also a problem if I decide to scroll several lines for each click of the down button. However if I change the bottom lines to
    if ScrllInf.nPos > ScrllInf.nMax - ScrllInf.nPage  then
        sbDown.Enabled := False;
then everything appears to work fine

 All the best - Dan

Commented:
I tried the accepted answer with a TMemo component in C++Builder 6, but with no effects. The GetScrollInfo API call returns 0 and leaves the ScrllInf structure empty. Can anyone give a hint what could be the problem?

10x

Explore More ContentExplore courses, solutions, and other research materials related to this topic.