同步滚动组件Delphi [英] Synchronized Scrolling Components Delphi
问题描述
尝试 / p>
SendMessage(gridX.Handle,WM_VSCROLL,SB_LINEDOWN,0);
另外
程序TForm1.GridXCustomWndProc(var Msg:TMessage);
begin
Msg.Result:= CallWindowProc(POldWndProc,gridX.Handle,Msg.Msg,Msg.wParam,Msg.lParam);
if(Msg.Msg = WM_VSCROLL)then
begin
gridY.SetActiveRow(gridX.GetActiveRow);
gridY.Perform(Msg.Msg,Msg.wParam,Msg.lParam);
SetScrollPos(gridY.Handle,SB_VERT,HIWORD(Msg.wParam),True);
结束
结束
和
程序TForm1.GridxCustomWndProc(var Msg:TMessage);
begin
if(Msg.Msg = WM_VSCROLL)then
begin
gridY.SetActiveRow(gridX.GetActiveRow);
gridY.Perform(Msg.Msg,Msg.wParam,Msg.lParam);
SetScrollPos(gridY.Handle,SB_VERT,HIWORD(Msg.wParam),True);
结束
继承WndProc(Msg);
结束
第一个只是一个临时解决方案,第二个结果是无效内存读取,第三个结果是堆栈溢出。所以这些解决方案似乎都不适合我。我会喜欢一些关于如何完成这项任务的投入!感谢提前。
更新:解决方案
private
[...]
GridXWndProc,GridXSaveWndProc:指针;
GridYWndProc,GridYSaveWndProc:指针;
程序GridXCustomWndProc(var Msg:TMessage);
程序GridYCustomWndProc(var Msg:TMessage);
procedure TForm1.FormCreate(Sender:TObject);
begin
GridXWndProc:= classes.MakeObjectInstance(GridXCustomWndProc);
GridXSaveWndProc:=指针(GetWindowLong(GridX.Handle,GWL_WNDPROC));
SetWindowLong(GridX.Handle,GWL_WNDPROC,LongInt(GridXWndProc));
GridYWndProc:= classes.MakeObjectInstance(GridYCustomWndProc);
GridYSaveWndProc:=指针(GetWindowLong(GridY.Handle,GWL_WNDPROC));
SetWindowLong(GridY.Handle,GWL_WNDPROC,LongInt(GridYWndProc));
结束
程序TForm1.GridXCustomWndProc(var Msg:TMessage);
begin
Msg.Result:= CallWindowProc(GridXSaveWndProc,GridX.Handle,Msg.Msg,Msg.WParam,Msg.LParam);
case Msg.Msg
WM_KEYDOWN:
begin
case TWMKey(Msg).CharCode of VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT:
GridY.Perform(Msg。消息,帕帕姆女士,帕拉姆女士);
结束
结束
WM_VSCROLL:
GridY.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
WM_HSCROLL:
GridY.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
WM_MOUSEWHEEL:
begin
ActiveControl:= GridY;
GridY.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
结束
WM_DESTROY:
begin
SetWindowLong(GridX.Handle,GWL_WNDPROC,Longint(GridXSaveWndProc));
Classes.FreeObjectInstance(GridXWndProc);
结束
结束
结束
procedure TForm1.GridXMouseDown(Sender:TObject; Button:TMouseButton; Shift:TShiftState; X,Y:Integer);
begin
GridY.SetActiveRow(GridX.GetActiveRow);
结束
程序TForm1.GridYCustomWndProc(var Msg:TMessage);
begin
Msg.Result:= CallWindowProc(GridYSaveWndProc,GridY.Handle,Msg.Msg,Msg.WParam,Msg.LParam);
case Msg.Msg
WM_KEYDOWN:
begin
case TWMKey(Msg).CharCode of VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT:
GridX.Perform(Msg。消息,帕帕姆女士,帕拉姆女士);
结束
结束
WM_VSCROLL:
GridX.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
WM_HSCROLL:
GridX.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
WM_MOUSEWHEEL:
begin
ActiveControl:= GridX;
GridX.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
结束
WM_DESTROY:
begin
SetWindowLong(GridY.Handle,GWL_WNDPROC,Longint(GridYSaveWndProc));
Classes.FreeObjectInstance(GridYWndProc);
结束
结束
结束
procedure TForm1.GridYMouseDown(Sender:TObject; Button:TMouseButton; Shift:TShiftState; X,Y:Integer);
begin
GridX.SetActiveRow(GridY.GetActiveRow);
结束
感谢 - Sertac Akyuz的解决方案。当使用网格集成到VCL表单应用程序中时,它们将在滚动中相互模仿,并突出显示所选记录。
可能正在为两个网格实现消息覆盖。 GridX滚动GridY,然后GridY滚动GridX,依次... SO。您可以通过用标记围绕块来保护表面滚动代码。
键入
TForm1 = class(TForm)
[..]
private
FNoScrollGridX,FNoScrollGridY:Boolean;
[...]
程序TForm1.GridXCustomWndProc(var Msg:TMessage);
begin
Msg.Result:= CallWindowProc(POldWndProc,gridX.Handle,Msg.Msg,Msg.wParam,Msg.lParam);
如果(Msg.Msg = WM_VSCROLL)然后
开始
如果不是FNoScrollGridX然后
开始
FNoScrollGridX:= True
gridY.SetActiveRow (gridX.GetActiveRow);
gridY.Perform(Msg.Msg,Msg.wParam,Msg.lParam);
// SetScrollPos(gridY.Handle,SB_VERT,HIWORD(Msg.wParam),True);
结束
FNoScrollGridX:= False;
结束
结束
GridY的类似代码。 BTW,你不需要SetScrollPos。
编辑:
TForm1 = class
[..]
private
GridXWndProc,GridXSaveWndProc:Pointer;
GridYWndProc,GridYSaveWndProc:指针;
程序GridXCustomWndProc(var Msg:TMessage);
程序GridYCustomWndProc(var Msg:TMessage);
[..]
程序TForm1.FormCreate(发件人:TObject);
begin
[..]
GridXWndProc:= classes.MakeObjectInstance(GridXCustomWndProc);
GridXSaveWndProc:=指针(GetWindowLong(GridX.Handle,GWL_WNDPROC));
SetWindowLong(GridX.Handle,GWL_WNDPROC,LongInt(GridXWndProc));
GridYWndProc:= classes.MakeObjectInstance(GridYCustomWndProc);
GridYSaveWndProc:=指针(GetWindowLong(GridY.Handle,GWL_WNDPROC));
SetWindowLong(GridY.Handle,GWL_WNDPROC,LongInt(GridYWndProc));
结束
程序TForm1.GridXCustomWndProc(var Msg:TMessage);
begin
Msg.Result:= CallWindowProc(GridXSaveWndProc,GridX.Handle,
Msg.Msg,Msg.WParam,Msg.LParam);
case Msg.Msg
WM_KEYDOWN:
begin
case TWMKey(Msg).CharCode of
VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT:
GridY.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
结束
结束
WM_VSCROLL:GridY.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
WM_MOUSEWHEEL:
begin
ActiveControl:= GridY;
GridY.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
结束
WM_DESTROY:
begin
SetWindowLong(GridX.Handle,GWL_WNDPROC,Longint(GridXSaveWndProc));
Classes.FreeObjectInstance(GridXWndProc);
结束
结束
结束
程序TForm1.GridYCustomWndProc(var Msg:TMessage);
begin
Msg.Result:= CallWindowProc(GridYSaveWndProc,GridY.Handle,
Msg.Msg,Msg.WParam,Msg.LParam);
case Msg.Msg
WM_KEYDOWN:
begin
case TWMKey(Msg).CharCode of
VK_UP,VK_DOWN,VK_PRIOR,VK_NEXT:
GridX.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
结束
结束
WM_VSCROLL:GridX.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
WM_MOUSEWHEEL:
begin
ActiveControl:= GridX;
GridY.Perform(Msg.Msg,Msg.WParam,Msg.LParam);
结束
WM_DESTROY:
begin
SetWindowLong(GridY.Handle,GWL_WNDPROC,Longint(GridYSaveWndProc));
Classes.FreeObjectInstance(GridYWndProc);
结束
结束
结束
I am trying to synchronize the scrolling of two TDBGrid components in a VCL Forms application, I am having difficulties intercepting the WndProc of each grid component without some stack issues. I have tried sending WM_VSCROLL messages under scrolling events but this still results in the incorrect operation. It needs to work for clicking the scrollbar, as well as highlighting a cell, or an up or down mouse button. The whole idea is to have two grids next to each other displaying a sort of matching dialog.
Tried
SendMessage( gridX.Handle, WM_VSCROLL, SB_LINEDOWN, 0 );
Also
procedure TForm1.GridXCustomWndProc( var Msg: TMessage );
begin
Msg.Result := CallWindowProc( POldWndProc, gridX.Handle, Msg.Msg, Msg.wParam, Msg.lParam );
if ( Msg.Msg = WM_VSCROLL ) then
begin
gridY.SetActiveRow( gridX.GetActiveRow );
gridY.Perform( Msg.Msg, Msg.wParam, Msg.lParam );
SetScrollPos( gridY.Handle, SB_VERT, HIWORD( Msg.wParam ), True );
end;
end;
And
procedure TForm1.GridxCustomWndProc( var Msg: TMessage );
begin
if ( Msg.Msg = WM_VSCROLL ) then
begin
gridY.SetActiveRow( gridX.GetActiveRow );
gridY.Perform( Msg.Msg, Msg.wParam, Msg.lParam );
SetScrollPos( gridY.Handle, SB_VERT, HIWORD( Msg.wParam ), True );
end;
inherited WndProc( Msg );
end;
The First is only a temporary solution, the second results in invalid memory reads, and the third results in a stack overflow. So none of these solutions seems to work for me. I'd love some input on how to accomplish this task! Thanks in advance.
UPDATE: Solution
private
[...]
GridXWndProc, GridXSaveWndProc: Pointer;
GridYWndProc, GridYSaveWndProc: Pointer;
procedure GridXCustomWndProc( var Msg: TMessage );
procedure GridYCustomWndProc( var Msg: TMessage );
procedure TForm1.FormCreate(Sender: TObject);
begin
GridXWndProc := classes.MakeObjectInstance( GridXCustomWndProc );
GridXSaveWndProc := Pointer( GetWindowLong( GridX.Handle, GWL_WNDPROC ) );
SetWindowLong( GridX.Handle, GWL_WNDPROC, LongInt( GridXWndProc ) );
GridYWndProc := classes.MakeObjectInstance( GridYCustomWndProc );
GridYSaveWndProc := Pointer( GetWindowLong( GridY.Handle, GWL_WNDPROC ) );
SetWindowLong( GridY.Handle, GWL_WNDPROC, LongInt( GridYWndProc ) );
end;
procedure TForm1.GridXCustomWndProc( var Msg: TMessage );
begin
Msg.Result := CallWindowProc( GridXSaveWndProc, GridX.Handle, Msg.Msg, Msg.WParam, Msg.LParam );
case Msg.Msg of
WM_KEYDOWN:
begin
case TWMKey( Msg ).CharCode of VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT:
GridY.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
end;
end;
WM_VSCROLL:
GridY.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
WM_HSCROLL:
GridY.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
WM_MOUSEWHEEL:
begin
ActiveControl := GridY;
GridY.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
end;
WM_DESTROY:
begin
SetWindowLong( GridX.Handle, GWL_WNDPROC, Longint( GridXSaveWndProc ) );
Classes.FreeObjectInstance( GridXWndProc );
end;
end;
end;
procedure TForm1.GridXMouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
begin
GridY.SetActiveRow( GridX.GetActiveRow );
end;
procedure TForm1.GridYCustomWndProc( var Msg: TMessage );
begin
Msg.Result := CallWindowProc( GridYSaveWndProc, GridY.Handle, Msg.Msg, Msg.WParam, Msg.LParam );
case Msg.Msg of
WM_KEYDOWN:
begin
case TWMKey( Msg ).CharCode of VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT:
GridX.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
end;
end;
WM_VSCROLL:
GridX.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
WM_HSCROLL:
GridX.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
WM_MOUSEWHEEL:
begin
ActiveControl := GridX;
GridX.Perform( Msg.Msg, Msg.WParam, Msg.LParam );
end;
WM_DESTROY:
begin
SetWindowLong( GridY.Handle, GWL_WNDPROC, Longint( GridYSaveWndProc ) );
Classes.FreeObjectInstance( GridYWndProc );
end;
end;
end;
procedure TForm1.GridYMouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer );
begin
GridX.SetActiveRow( GridY.GetActiveRow );
end;
Thanks to - Sertac Akyuz for the solution. When integrated into a VCL forms application using grids, they will mimmic each other in scrolling, and highlighting the selected record.
You are probably implementing the message override for both of the grids. GridX scrolls GridY, which in turn scrolls GridX, which in turn ... SO. You can protect the superficial scrolling code by surrounding the block with flags.
type
TForm1 = class(TForm)
[..]
private
FNoScrollGridX, FNoScrollGridY: Boolean;
[..]
procedure TForm1.GridXCustomWndProc( var Msg: TMessage );
begin
Msg.Result := CallWindowProc(POldWndProc, gridX.Handle, Msg.Msg, Msg.wParam, Msg.lParam );
if ( Msg.Msg = WM_VSCROLL ) then
begin
if not FNoScrollGridX then
begin
FNoScrollGridX := True
gridY.SetActiveRow( gridX.GetActiveRow );
gridY.Perform( Msg.Msg, Msg.wParam, Msg.lParam );
// SetScrollPos( gridY.Handle, SB_VERT, HIWORD( Msg.wParam ), True );
end;
FNoScrollGridX := False;
end;
end;
Similiar code for the GridY. BTW, you shouln't need the SetScrollPos.
edit:
TForm1 = class(TForm)
[..]
private
GridXWndProc, GridXSaveWndProc: Pointer;
GridYWndProc, GridYSaveWndProc: Pointer;
procedure GridXCustomWndProc(var Msg: TMessage);
procedure GridYCustomWndProc(var Msg: TMessage);
[..]
procedure TForm1.FormCreate(Sender: TObject);
begin
[..]
GridXWndProc := classes.MakeObjectInstance(GridXCustomWndProc);
GridXSaveWndProc := Pointer(GetWindowLong(GridX.Handle, GWL_WNDPROC));
SetWindowLong(GridX.Handle, GWL_WNDPROC, LongInt(GridXWndProc));
GridYWndProc := classes.MakeObjectInstance(GridYCustomWndProc);
GridYSaveWndProc := Pointer(GetWindowLong(GridY.Handle, GWL_WNDPROC));
SetWindowLong(GridY.Handle, GWL_WNDPROC, LongInt(GridYWndProc));
end;
procedure TForm1.GridXCustomWndProc(var Msg: TMessage);
begin
Msg.Result := CallWindowProc(GridXSaveWndProc, GridX.Handle,
Msg.Msg, Msg.WParam, Msg.LParam);
case Msg.Msg of
WM_KEYDOWN:
begin
case TWMKey(Msg).CharCode of
VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT:
GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
end;
end;
WM_VSCROLL: GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
WM_MOUSEWHEEL:
begin
ActiveControl := GridY;
GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
end;
WM_DESTROY:
begin
SetWindowLong(GridX.Handle, GWL_WNDPROC, Longint(GridXSaveWndProc));
Classes.FreeObjectInstance(GridXWndProc);
end;
end;
end;
procedure TForm1.GridYCustomWndProc(var Msg: TMessage);
begin
Msg.Result := CallWindowProc(GridYSaveWndProc, GridY.Handle,
Msg.Msg, Msg.WParam, Msg.LParam);
case Msg.Msg of
WM_KEYDOWN:
begin
case TWMKey(Msg).CharCode of
VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT:
GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
end;
end;
WM_VSCROLL: GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
WM_MOUSEWHEEL:
begin
ActiveControl := GridX;
GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam);
end;
WM_DESTROY:
begin
SetWindowLong(GridY.Handle, GWL_WNDPROC, Longint(GridYSaveWndProc));
Classes.FreeObjectInstance(GridYWndProc);
end;
end;
end;
这篇关于同步滚动组件Delphi的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!