Board index » delphi » Fast Delphi table scrolling: PeekMessage() tricks

Fast Delphi table scrolling: PeekMessage() tricks

I have had a play with PeekMessage(). The function works, but the
catch is as follows.

I am scrolling a linked table. The "seek" in the link slows the
scolling down. So I only want to "seek" and locate the record pointer
in the other table when the user has STOPPED scrolling. While the user
is scolling, I don't want seeks. So I thought, if there are Messages
pending, with PeekMessage(), then don't seek, else do. Sounds simple,
but the trick is this.

I set the seek filter to WM_MOUSEFIRST/LAST. The user presses the
mouse down continuously on the scroll bar of a DBGrid. This results in
PeekMessage() returning false, which is not what we want. Only
continous and very fast Mouse up/mouse down/mouse up/mouse down action
would return true.

If I use 0 and 0 in the filter to catch ANY message, the result always
returns true. The reason, I think, is that any mouse click in my
display has some consequence, i.e. a PAINT message, so the PeekMessage
returns true at all times, so does not help.

What would be great would be if there was a OnMouseUp() handler which
works when the user releases the mouse on the DBGrid scroll bar.
Sadly, OnMouseUp() works only inside the DBGrid, not on its scrolls
bars. OnMouseUp() with TForm's KeyPreview:=true does not respond at
all, I have found.

One more thing I tested was polling with GetKeyState() for the Mouse
buttons. I thought while the mouse is DOWN do not update the "seek",
otherwise do. Unfortunately, by the time the mouse is UP, the
scrolling has finished. This is the way the Windows scroll bars seem
to work. So the seek never happens and the table record pointer is not

These issues all concern the scroll bars, everything else can be
handled with OnKeyUp() and OnMouseUp() elsewhere.

Real tricky...

Email appreciated

>It sounds like that you are after the Win API function 'PeekMessage'.
>It returns True if a message is available, and False it not.  It also
>has filter parameters so that you can specify that you only want Mouse
>and Keyboard messages.  Hope this helps...


Re:Fast Delphi table scrolling: PeekMessage() tricks

Matthew <  > wrote in article

> I have had a play with PeekMessage(). The function works, but the
> catch is as follows.


Here is a method I have used previously:

  TForm1 = class(TForm)
    RefreshCount: Integer;
    procedure WMUser( var msg: TMessage ); message wm_user;


procedure TForm1.WMUser(var msg: TMessage );
  Dec( RefreshCount );
  if RefreshCount <= 0 then

// fuzzy on the declaration here
procedure TForm1.OnDataChange(Sender: TObject; Field: TField );
  if Assigned(Field) then Exit;
  if Table.State = dsBrowse then begin
    Inc( RefreshCount );
    PostMessage( Handle, wm_user, 0, 0 );

This will batch up the requests for the query update and then
only perform it when the last one is needed.

Ryan VanIderstine

Re:Fast Delphi table scrolling: PeekMessage() tricks

Matthew <  > wrote in article

> I have had a play with PeekMessage(). The function works, but the
> catch is as follows.


Here is a method that works :

1. I assume that you execute the "detail" query in the "datachange" event of
    the master data source

2. In this event, you disable a Ttimer,  set it to 100 msecs, en re-enable it
    You move the code that executes the detail query to the timer event.

This is the code you would use :
procedure TForm1.DSMasterDataChange(Sender: TObject; Field: TField);
    UpdateTimer.Enabled := False; { reset Timer }
    UpdateTimer.Interval := 100;
    UpdateTimer.Enabled := True;

procedure TForm1.UpdateTimerTimer(Sender: TObject);
  UpdateTimer.Enabled := False;           { reset timer }
  QueryDetail.Close;                               { execute detail query }
  QueryDetail.Params[0].AsString := QueryMasterForeignKey.Value;

As long as the user scrolls through the master records, the master datasource
keeps firing the datachange event.
Each time this event fires, you reset a 100 millesecond Ttimer, preventing the
timer event from firing until the user stops scrolling the master records.

The timer event is fired 100 milliseconds after the user stops scrolling, and
the detail query is refreshed.

As an added performance improvement, you should also check that the
foreign key value of the master record has actually changed, since there is
no need refreshing the detail query if the data is still valid.

I have used this method in a form with two linked Dbgrids, and the scrolling
speed through the master records is extremely fast, and you do not really notice
the 100 msec delay once you stop scrolling.

I too tried peeking messages, and user messages, but could not
get it to work, and this method is VERY simple, but effective.

Danny Heijl

AT WORK :      | HOME :
Danny Heijl    |
CEVI VZW       | Danny Heijl
Bisdomplein 3  | Winterstraat 4
9000 Gent      | 9000 Gent
Belgium        | Belgium

Other Threads