Scrolling DBGrid

I think this should be quite easy, but still can't make it work...

What I want is to be able to scroll records in DBGrid with a mouse wheel. However, i can't even get it reacting on mouse wheel, as there is no such event defined for DBGrid. I only found it in the Form event list, but it doesn't work.

Your help would be highly appreciated.

Comments

  • : I think this should be quite easy, but still can't make it work...
    :
    : What I want is to be able to scroll records in DBGrid with a mouse wheel. However, i can't even get it reacting on mouse wheel, as there is no such event defined for DBGrid. I only found it in the Form event list, but it doesn't work.
    :
    : Your help would be highly appreciated.
    :
    I don't know if the following works, but you could give it a shot. In the form's OnMouseWheel() check if the mouse is in the grid (see the Mouse variable and TControl object in the help files for more info). If it is, then call the Grid's DataSource.DataSet.Next() (or Prior()) to perform the actual scrolling.
  • [b][red]This message was edited by ieri at 2004-9-9 11:27:1[/red][/b][hr]
    Hi!
    zibadian's offer works (I tried it before) but there is more better solution:
    add TApplicationEvent (Delphi 7) (maybe TApplication in prev. versions- I'm not sure.)
    Add this code to onMessage event:

    procedure TFrm1.ApplicationEvents1Message(var Msg: tagMSG;
    var Handled: Boolean);
    var
    i: SmallInt;
    begin
    if Msg.message = WM_MOUSEWHEEL then
    begin
    Msg.message := WM_KEYDOWN;
    Msg.lParam := 0;
    i := HiWord(Msg.wParam) ;
    if i > 0 then
    Msg.wParam := VK_UP
    else
    Msg.wParam := VK_DOWN;
    Handled := False;
    end;
    end;



  • [b][red]This message was edited by zibadian at 2004-9-9 15:31:47[/red][/b][hr]
    : [b][red]This message was edited by ieri at 2004-9-9 11:27:1[/red][/b][hr]
    : Hi!
    : zibadian's offer works (I tried it before) but there is more better solution:
    : add TApplicationEvent (Delphi 7) (maybe TApplication in prev. versions- I'm not sure.)
    : Add this code to onMessage event:
    :
    : procedure TFrm1.ApplicationEvents1Message(var Msg: tagMSG;
    : var Handled: Boolean);
    : var
    : i: SmallInt;
    : begin
    : if Msg.message = WM_MOUSEWHEEL then
    : begin
    : Msg.message := WM_KEYDOWN;
    : Msg.lParam := 0;
    : i := HiWord(Msg.wParam) ;
    : if i > 0 then
    : Msg.wParam := VK_UP
    : else
    : Msg.wParam := VK_DOWN;
    : Handled := False;
    : end;
    : end;
    :
    :
    :
    :
    The TApplicationEvents is also known in Delphi 5. This solution might cause problems, if you want to use the mousewheel for other things, when the grid doesn't have the focus. For example: when a memo is focused and you want the mousewheel to move the scrollbar instead of the text-cursor. It is better to include a check if the message is intended for the grid.
    Another disadvantage of this code is that, when used for too many different special-handling, it might slow down the program. This is because each message must be preprocessed by the OnMessage(), then processed by the stub into an event. And finally that event is processed by the control itself.
  • 1. "This solution might cause problems, if you want to use the mousewheel for other things, when the grid doesn't have the focus. "
    I check if the dbgrid is focused at the beginning of the event handler. it works.

    2. "it might slow down the program." What can cause slowing down? I really dont have any idea.

    3. I tried prior and next methods before. But it didnt scroll one by one. I think it was because of the mouse configuration (Set in Control Panel).


  • : 1. "This solution might cause problems, if you want to use the mousewheel for other things, when the grid doesn't have the focus. "
    : I check if the dbgrid is focused at the beginning of the event handler. it works.
    :
    : 2. "it might slow down the program." What can cause slowing down? I really dont have any idea.
    :
    : 3. I tried prior and next methods before. But it didnt scroll one by one. I think it was because of the mouse configuration (Set in Control Panel).
    :
    :
    :
    1. I included this as a note, because the posted code didn't check it.
    2. The OnMessage() is called for every message the entire application gets, which are 100's per second (if not more). A single if-then is at least a single operation and always has some memory latency (http://encyclopedia.thefreedictionary.com/Latency) accompanied with it. This is in this case not noticable, but if you put several if-then's in the OnMessage(), then it might become noticable.
    3. The mouse settings have probable nothing to do with it, because the OnMouseWheel() is called only once per click. This means that the Prior or Next is called only once per click, which should scroll the grid one by one for each click. But perhaps the database handling components work different than I thought (I never use them myself).
  • : : 1. "This solution might cause problems, if you want to use the mousewheel for other things, when the grid doesn't have the focus. "
    : : I check if the dbgrid is focused at the beginning of the event handler. it works.
    : :
    : : 2. "it might slow down the program." What can cause slowing down? I really dont have any idea.
    : :
    : : 3. I tried prior and next methods before. But it didnt scroll one by one. I think it was because of the mouse configuration (Set in Control Panel).
    : :
    : :
    : :
    : 1. I included this as a note, because the posted code didn't check it.
    : 2. The OnMessage() is called for every message the entire application gets, which are 100's per second (if not more). A single if-then is at least a single operation and always has some memory latency (http://encyclopedia.thefreedictionary.com/Latency) accompanied with it. This is in this case not noticable, but if you put several if-then's in the OnMessage(), then it might become noticable.
    : 3. The mouse settings have probable nothing to do with it, because the OnMouseWheel() is called only once per click. This means that the Prior or Next is called only once per click, which should scroll the grid one by one for each click. But perhaps the database handling components work different than I thought (I never use them myself).
    :

    My Ideal would be, that why dont we extend the capability of the DBGrid, with deriving a new component from TDBGrid, override the windwos wndProc, process the message, and do the proper actions.
    I wrote a component like this before. This component manages the scrolling and adds a new event 'OnMouseWheel' for futher processing if its nesessary.

    Here I post the code:

    [code]
    unit WheelGrid;

    interface

    uses
    SysUtils, Classes, Controls, Grids, DBGrids, Messages, dialogs, Windows;
    type TmwState = (mwUp,mwDown); // mousewheel direction status
    type TMouseWheel = procedure(Sender : TObject;WheelDirection:TMwState) of object; // new event
    type
    TWheelGrid = class(TDBGrid)
    private
    FOnMouseWheel: TMouseWheel;
    procedure SetOnMouseWheel(const Value: TMouseWheel);
    { Private declarations }
    protected
    { Protected declarations }
    public
    procedure WndProc(var Message: TMessage);override; //overriding the wndproc of the grid
    { Public declarations }
    published
    property OnMouseWheel : TMouseWheel read FOnMouseWheel write SetOnMouseWheel; // add the new property
    { Published declarations }
    end;

    procedure Register;

    implementation

    procedure Register;
    begin
    RegisterComponents('OSoft', [TWheelGrid]);
    end;

    { TWheelGrid }

    procedure TWheelGrid.SetOnMouseWheel(const Value: TMouseWheel);
    begin
    FOnMouseWheel := Value;
    end;

    procedure TWheelGrid.WndProc(var Message: TMessage);
    var
    WData : SmallInt; //wheel data
    begin

    if Message.Msg = WM_MOUSEWHEEL then //it the windows message is mousewheen (NT ONLY!)
    begin
    WData := HiWord(Message.WParam); //The HI part of the data gives the wheel movement multipled by mouse delta (120 usually)
    // it lower then 0 then wheel up, else wheel down
    Message.Msg := WM_KEYDOWN; //change the message to WM_KEYDOWN
    Message.LParam := 0; //reset lparam
    if WDAta>0 then // if wheel up
    begin
    if Assigned(FOnMouseWheel) then FOnMouseWheel(self,mwUp); //call the event handler
    Message.WParam := VK_UP; // new windows message parameter is VK_UP
    end
    else
    begin
    if Assigned(FOnMouseWheel) then FOnMouseWheel(self,mwDown); //call the event handler
    Message.WParam := VK_DOWN; // new windows message parameter is VK_DOWN
    end;
    end;
    inherited WndProc(Message); // inherit whith the original, or cahnged windows message
    end;

    end.
    [/code]

    I prefer writing components in this case, cos' this way it is reusable.
    In the components OnMouseWheel event you can check the direction like:
    [code]
    procedure TForm1.WheelGrid1MouseWheel(Sender: TObject;
    WheelDirection: TmwState);
    begin
    if WheelDirection = mwUP then
    ShowMessage('UP')
    else
    ShowMessage('DOWN');
    end;
    [/code]

    This way, the question of time latencies, wont matter, cos' the component windproc invoked only, if a message is sent to.
    Will not effect the speed of your entire application.
    SoftMan

  • [b][red]This message was edited by zibadian at 2004-9-10 3:35:45[/red][/b][hr]
    : : : 1. "This solution might cause problems, if you want to use the mousewheel for other things, when the grid doesn't have the focus. "
    : : : I check if the dbgrid is focused at the beginning of the event handler. it works.
    : : :
    : : : 2. "it might slow down the program." What can cause slowing down? I really dont have any idea.
    : : :
    : : : 3. I tried prior and next methods before. But it didnt scroll one by one. I think it was because of the mouse configuration (Set in Control Panel).
    : : :
    : : :
    : : :
    : : 1. I included this as a note, because the posted code didn't check it.
    : : 2. The OnMessage() is called for every message the entire application gets, which are 100's per second (if not more). A single if-then is at least a single operation and always has some memory latency (http://encyclopedia.thefreedictionary.com/Latency) accompanied with it. This is in this case not noticable, but if you put several if-then's in the OnMessage(), then it might become noticable.
    : : 3. The mouse settings have probable nothing to do with it, because the OnMouseWheel() is called only once per click. This means that the Prior or Next is called only once per click, which should scroll the grid one by one for each click. But perhaps the database handling components work different than I thought (I never use them myself).
    : :
    :
    : My Ideal would be, that why dont we extend the capability of the DBGrid, with deriving a new component from TDBGrid, override the windwos wndProc, process the message, and do the proper actions.
    : I wrote a component like this before. This component manages the scrolling and adds a new event 'OnMouseWheel' for futher processing if its nesessary.
    :
    : Here I post the code:
    :
    : [code]
    : unit WheelGrid;
    :
    : interface
    :
    : uses
    : SysUtils, Classes, Controls, Grids, DBGrids, Messages, dialogs, Windows;
    : type TmwState = (mwUp,mwDown); // mousewheel direction status
    : type TMouseWheel = procedure(Sender : TObject;WheelDirection:TMwState) of object; // new event
    : type
    : TWheelGrid = class(TDBGrid)
    : private
    : FOnMouseWheel: TMouseWheel;
    : procedure SetOnMouseWheel(const Value: TMouseWheel);
    : { Private declarations }
    : protected
    : { Protected declarations }
    : public
    : procedure WndProc(var Message: TMessage);override; //overriding the wndproc of the grid
    : { Public declarations }
    : published
    : property OnMouseWheel : TMouseWheel read FOnMouseWheel write SetOnMouseWheel; // add the new property
    : { Published declarations }
    : end;
    :
    : procedure Register;
    :
    : implementation
    :
    : procedure Register;
    : begin
    : RegisterComponents('OSoft', [TWheelGrid]);
    : end;
    :
    : { TWheelGrid }
    :
    : procedure TWheelGrid.SetOnMouseWheel(const Value: TMouseWheel);
    : begin
    : FOnMouseWheel := Value;
    : end;
    :
    : procedure TWheelGrid.WndProc(var Message: TMessage);
    : var
    : WData : SmallInt; //wheel data
    : begin
    :
    : if Message.Msg = WM_MOUSEWHEEL then //it the windows message is mousewheen (NT ONLY!)
    : begin
    : WData := HiWord(Message.WParam); //The HI part of the data gives the wheel movement multipled by mouse delta (120 usually)
    : // it lower then 0 then wheel up, else wheel down
    : Message.Msg := WM_KEYDOWN; //change the message to WM_KEYDOWN
    : Message.LParam := 0; //reset lparam
    : if WDAta>0 then // if wheel up
    : begin
    : if Assigned(FOnMouseWheel) then FOnMouseWheel(self,mwUp); //call the event handler
    : Message.WParam := VK_UP; // new windows message parameter is VK_UP
    : end
    : else
    : begin
    : if Assigned(FOnMouseWheel) then FOnMouseWheel(self,mwDown); //call the event handler
    : Message.WParam := VK_DOWN; // new windows message parameter is VK_DOWN
    : end;
    : end;
    : inherited WndProc(Message); // inherit whith the original, or cahnged windows message
    : end;
    :
    : end.
    : [/code]
    :
    : I prefer writing components in this case, cos' this way it is reusable.
    : In the components OnMouseWheel event you can check the direction like:
    : [code]
    : procedure TForm1.WheelGrid1MouseWheel(Sender: TObject;
    : WheelDirection: TmwState);
    : begin
    : if WheelDirection = mwUP then
    : ShowMessage('UP')
    : else
    : ShowMessage('DOWN');
    : end;
    : [/code]
    :
    : This way, the question of time latencies, wont matter, cos' the component windproc invoked only, if a message is sent to.
    : Will not effect the speed of your entire application.
    : SoftMan
    :
    :
    I dislike creating new components, because the source code is not very portable to other computers. For my work I never know if I'm working on the same machine again, and thus never know if my components are already installed. As for the speed, that's correct.
  • Well, first of all, thanks very much to all of you for your help.

    Secondly, I want to contribute a little to the discussion and state that on the net I also found the following code for scrolling DBGrid:

    [code]
    procedure TForm1.MyMessageHandler(var Msg: TMsg; var Handled: Boolean);
    begin
    if (Msg = META_SETTEXTJUSTIFICATION)
    and (Msg.Handle = DBGrid1.Handle)
    and assigned(DBGrid1.Datasource)
    and assigned(DBGrid1.Datasource.Dataset) then
    begin
    if Msg.wParam > 0 then
    DBGrid1.Datasource.Dataset.Next
    else
    DBGrid1.Datasource.Dataset.Previous;
    end;
    end;
    [/code]

    It didn't work, however, until I changed META_SETTEXTJUSTIFICATION to 522 and Msg.Handle to Msg.hwnd. I have no idea how it works, but it works perfectly for my DBGrid where I draw all the cells manually. In the case of default drawing, however, it works really stange, sometimes scrolling by two records, etc. And also, I believe, it is subject to the same issue of slowing down performance.
  • : Well, first of all, thanks very much to all of you for your help.
    :
    : Secondly, I want to contribute a little to the discussion and state that on the net I also found the following code for scrolling DBGrid:
    :
    : [code]
    : procedure TForm1.MyMessageHandler(var Msg: TMsg; var Handled: Boolean);
    : begin
    : if (Msg = META_SETTEXTJUSTIFICATION)
    : and (Msg.Handle = DBGrid1.Handle)
    : and assigned(DBGrid1.Datasource)
    : and assigned(DBGrid1.Datasource.Dataset) then
    : begin
    : if Msg.wParam > 0 then
    : DBGrid1.Datasource.Dataset.Next
    : else
    : DBGrid1.Datasource.Dataset.Previous;
    : end;
    : end;
    : [/code]
    :
    : It didn't work, however, until I changed META_SETTEXTJUSTIFICATION to 522 and Msg.Handle to Msg.hwnd. I have no idea how it works, but it works perfectly for my DBGrid where I draw all the cells manually. In the case of default drawing, however, it works really stange, sometimes scrolling by two records, etc. And also, I believe, it is subject to the same issue of slowing down performance.
    :

    Hi
    You can try this, works for all grids on the form

    [code]
    procedure TForm1.MyMessageHandler(var Msg: TMsg; var Handled: Boolean);
    begin
    if (Msg.message = META_SETTEXTJUSTIFICATION) then
    if ActiveControl is TDBGrid then
    begin
    if msg.wParam >0 then
    SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_UP,0)
    else
    SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_DOWN,0);
    handled := true;
    end
    end;
    [/code]
    SoftMan

  • : Hi
    : You can try this, works for all grids on the form
    :
    : [code]
    : procedure TForm1.MyMessageHandler(var Msg: TMsg; var Handled: Boolean);
    : begin
    : if (Msg.message = META_SETTEXTJUSTIFICATION) then
    : if ActiveControl is TDBGrid then
    : begin
    : if msg.wParam >0 then
    : SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_UP,0)
    : else
    : SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_DOWN,0);
    : handled := true;
    : end
    : end;
    : [/code]
    : SoftMan
    :
    :

    Well, somehow it says "Undeclared identifier 'handled'". Did I miss something?
  • [b][red]This message was edited by softman at 2004-9-13 8:36:42[/red][/b][hr]
    : : Hi
    : : You can try this, works for all grids on the form
    : :
    : : [code]
    : : procedure TForm1.MyMessageHandler(var Msg: TMsg; var Handled: Boolean);
    : : begin
    : : if (Msg.message = META_SETTEXTJUSTIFICATION) then
    : : if ActiveControl is TDBGrid then
    : : begin
    : : if msg.wParam >0 then
    : : SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_UP,0)
    : : else
    : : SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_DOWN,0);
    : : handled := true;
    : : end
    : : end;
    : : [/code]
    : : SoftMan
    : :
    : :
    :
    : Well, somehow it says "Undeclared identifier 'handled'". Did I miss something?
    :

    Well, for me it works, check if you added,
    Application.OnMessage := MyMessageHandler; at main form's FormCreate?

    'Handled' is the var parameter of the procedure, should work. Didn't you confused Handled, and Handle?

  • : [b][red]This message was edited by softman at 2004-9-13 8:36:42[/red][/b][hr]
    : : : Hi
    : : : You can try this, works for all grids on the form
    : : :
    : : : [code]
    : : : procedure TForm1.MyMessageHandler(var Msg: TMsg; var Handled: Boolean);
    : : : begin
    : : : if (Msg.message = META_SETTEXTJUSTIFICATION) then
    : : : if ActiveControl is TDBGrid then
    : : : begin
    : : : if msg.wParam >0 then
    : : : SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_UP,0)
    : : : else
    : : : SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_DOWN,0);
    : : : handled := true;
    : : : end
    : : : end;
    : : : [/code]
    : : : SoftMan
    : : :
    : : :
    : :
    : : Well, somehow it says "Undeclared identifier 'handled'". Did I miss something?
    : :
    :
    : Well, for me it works, check if you added,
    : Application.OnMessage := MyMessageHandler; at main form's FormCreate?
    :
    : 'Handled' is the var parameter of the procedure, should work. Didn't you confused Handled, and Handle?
    :
    :

    OK, I understood where the problem was. In my Application.OnMessage procedure boolean var parameter is Handler not Handled.

    And thanks for the code, it works perfectly.
  • : : [b][red]This message was edited by softman at 2004-9-13 8:36:42[/red][/b][hr]
    : : : : Hi
    : : : : You can try this, works for all grids on the form
    : : : :
    : : : : [code]
    : : : : procedure TForm1.MyMessageHandler(var Msg: TMsg; var Handled: Boolean);
    : : : : begin
    : : : : if (Msg.message = META_SETTEXTJUSTIFICATION) then
    : : : : if ActiveControl is TDBGrid then
    : : : : begin
    : : : : if msg.wParam >0 then
    : : : : SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_UP,0)
    : : : : else
    : : : : SendMessage(ActiveControl.Handle,WM_KEYDOWN,VK_DOWN,0);
    : : : : handled := true;
    : : : : end
    : : : : end;
    : : : : [/code]
    : : : : SoftMan
    : : : :
    : : : :
    : : :
    : : : Well, somehow it says "Undeclared identifier 'handled'". Did I miss something?
    : : :
    : :
    : : Well, for me it works, check if you added,
    : : Application.OnMessage := MyMessageHandler; at main form's FormCreate?
    : :
    : : 'Handled' is the var parameter of the procedure, should work. Didn't you confused Handled, and Handle?
    : :
    : :
    :
    : OK, I understood where the problem was. In my Application.OnMessage procedure boolean var parameter is Handler not Handled.
    :
    : And thanks for the code, it works perfectly.
    :
    Which Delphi version do you use, SaMo?
  • [b][red]This message was edited by SaMo at 2004-9-14 3:29:59[/red][/b][hr]
    : : OK, I understood where the problem was. In my Application.OnMessage procedure boolean var parameter is Handler not Handled.
    : :
    : : And thanks for the code, it works perfectly.
    : :
    : Which Delphi version do you use, SaMo?
    :

    Delphi 6 Enterprise. But nevermind. I recall now that I might have manually changed it to Handler a while ago for some other purposes and forgot to change back.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories