예전에 볼포Q&A에 누가 질문해서 해보았던것인데...
누가 또 질문해서 이곳에 올려놓습니다.
TStringGrid에서 Vertical Scroll중에 Grid갱신하기
기본 TStringGrid에서는 ScrollBar를 이용해서 Scroll할때
중간에 썸(THUMB) 버튼을 잡아서 움직이는 중에는 Grid의 내용이 갱신이 되지 않습니다.
StringGrid의 ScrollBar의 썸(Thumb)을 잡아 움직이는 중에도 Grid의 내용이 갱신되도록 만들어 보았습니다.
(참. 세로 스크롤만 햇습니다.)
1. sub-classing으로 WM_VSCROLL 메세지를 확인한후
2. scroll방향에 맞게 SB_PAGEDOWN / SB_PAGEUP 메세지를 Grid WndProc에 보내면 된다.
void * SGridProc;
FARPROC SGridDefaultProc;
void __fastcall TForm1::FormCreate(TObject *Sender)
{
SGridProc = MakeObjectInstance(StringGridProc);
SGridDefaultProc = (FARPROC)SetWindowLong(StringGrid1->Handle,GWL_WNDPROC, (LPARAM)SGridProc);
}
//---------------------------------------------------------------------------
WPARAM OW=0;
void __fastcall TForm1::StringGridProc(TMessage &Msg)
{
if(Msg.Msg==WM_VSCROLL)
Msg.Result = CallWindowProc(SGridDefaultProc,StringGrid1->Handle,Msg.Msg,Msg.WParam,Msg.LParam);
if(Msg.WParam>10)
{
if(OW.WParam)StringGrid1->Perform(WM_VSCROLL,SB_PAGEDOWN,0);
else StringGrid1->Perform(WM_VSCROLL,SB_PAGEUP,0);
OW=Msg.WParam;
}
}
else
{
Msg.Result = CallWindowProc(SGridDefaultProc,StringGrid1->Handle,Msg.Msg,Msg.WParam,Msg.LParam);
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
SetWindowLong(StringGrid1->Handle,GWL_WNDPROC, (LPARAM)SGridDefaultProc);
FreeObjectInstance(SGridProc);
}
//---------------------------------------------------------------------------
[중요사항]
* 중간에 WParam이 10보다 큰경우에만 처리한것은
Scroll이 시작이나 종료될때 10보다 작은 WParam값을 가지므로 정확한 방향값을 알수 없기 때문이다.
* SendMessage를 하지 않고 Perform을 한것은 똑같은 WM_VSCROLL 메세지이므로
동작이 꼬이지 않고 바로 StringGrid의 WinProc를 호출하기 위함이다.
다시말해
StringGrid1->Perform(WM_VSCROLL,SB_PAGEDOWN,0); 이 코드는
CallWindowProc(SGridDefaultProc,StringGrid1->Handle,WM_VSCROLL,SB_PAGEDOWN,0); 과 같은 내용이다.
SubClassing을 MakeObjectInstance 라는 VCL함수를 이용하였으므로
반드시 종료할때는 FreeObjectInstance로 free해주도록 한다.
MakeObjectInstance 를 이용하지 않고 TControl의 WindowProc를 이용한 sub-classing으로 수정해서 올립니다.
그것이 좀더 직관적이어서 쓰기편할것 같습니다.
//xxx.h
TWndMethod SGridOrgProc2;
void __fastcall TForm1::StringGridProc2(TMessage &Msg);
//xxx.cpp
void __fastcall TForm1::FormCreate(TObject *Sender)
{
//테스트용 초기화
for(int i=0;iRowCount;i++)
StringGrid2->Cells[0][i]=IntToStr(i+1);
//sub-classing 설정
SGridOrgProc2=StringGrid2->WindowProc;
StringGrid2->WindowProc=StringGridProc2;
}
//---------------------------------------------------------------------------
WPARAM OW2=0;
void __fastcall TForm1::StringGridProc2(TMessage &Msg)
{
SGridOrgProc2(Msg);
if(Msg.Msg==WM_VSCROLL)
{
if(Msg.WParam>10)
{
WPARAM w=Msg.WParam;
if(OW2)
{
Msg.WParam=SB_PAGEDOWN;
SGridOrgProc2(Msg);
}
else
{
Msg.WParam=SB_PAGEUP;
Msg.LParam=0;
SGridOrgProc2(Msg);
}
OW2=w;
}
}
}
Delphi버젼
var
SGridOrgProc: TWndMethod;
OW: Integer;
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
for i:=0 to StringGrid1.RowCount-1 do
begin
StringGrid1.Cells[0,i]:=IntToStr(i);
end;
SGridOrgProc:=StringGrid1.WindowProc;
StringGrid1.WindowProc:=StringGridProc;
end;
procedure TForm1.StringGridProc(var Msg: TMessage);
var
w: Integer;
begin
SGridOrgProc(Msg);
if(Msg.Msg=WM_VSCROLL)then
begin
if(Msg.WParam>10)then
begin
w:=Msg.WParam;
if(OW)then
begin
Msg.WParam:=SB_PAGEDOWN;
SGridOrgProc(Msg);
end
else
begin
Msg.WParam:=SB_PAGEUP;
Msg.LParam:=0;
SGridOrgProc(Msg);
end;
OW:=w;
end;
end;
end;
그럼..
goThumbTracking = true로 해주면 잘됩니다.
지난번에도 이런게 있는줄 확인 했는데...
기억이 나질 않아서... 쩝쩝...
역시 머리 나쁘면 손발이 고생입니다.