|
또 다시 조금 수정...
sub-classing 으로
WM_MOUSEMOVE 대신 WM_LBUTTONDOWN를 처리했어요
위에보다 조금은 낫군요..
어느정도는 쓸만할것 같은데.....
한가지 정도 문제가 있네요...
심각한 문제는 아닌데....
그럼...
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
int __fastcall IABS(int a ,int b)
{
if(a>b)return a-b;
else return b-a;
}
//---------------------------------------------------------------------------
bool bSize; //현재 Column을 Sizing중인지 확인하는 변수
TPoint FsPoint,LaPoint; // Sizing할때 수직으로 선을 그리는데.... 좌표값 저장
int iColNum; // Sizing하는 Column의 인덱스
TColor clPenColor; // 원래 StringGrid에 설정된 Pen의 Color 임시 저장 변수
TPenMode pmPenMode; // 원래 StringGrid에 설정된 Pen의 Mode 임시 저장 변수
//Sizing하면서 현재위치를 수직으로 선을 그릴때 Pen의 색갈과 mode를 변경하기때문에 원래 설정을
//임시로 저장해둔다.
typedef void __fastcall (__closure *TWNDPROC)(TMessage &msg); //VCL용 WNDPROC 타입 선언
TWNDPROC OriginalProc; // WNDPROC 형 변수 선언
void __fastcall TForm1::FormCreate(TObject *Sender)
{
//빼도 되는 코드 ... 임시로 값을 넣음
for(int r=0;r<sgrd->RowCount;r++)
{
for(int c=0;c<sgrd->RowCount;c++)
{
sgrd->Cells[r][c]=IntToStr(r)+" - "+IntToStr(c);
}
}
pmPenMode=sgrd->Canvas->Pen->Mode; //원래 PenMode와
clPenColor=sgrd->Canvas->Pen->Color; //원래 PenColor를 임의 변수에 저장
sgrd->Options=sgrd->Options>>goColSizing; // 원래 Column변경이 옵션에 설정되어있다면 빼버린다.
//sub-classing 위해
OriginalProc=sgrd->WindowProc; //StringGrid의 원래 WndProc를 변수에 저장하고
sgrd->WindowProc=SGridMessageProc; //새로만든 WndProc함수를 StringGrid에 설정해줍니다.
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SGridMessageProc(TMessage &msg) //StringGrid에 윈도우process로 걸어둔 함수
{
if(msg.Msg==WM_LBUTTONDOWN) //마우스 왼쪽 버튼을 Down할때 처리
{
if(sgrd->Cursor==crHSplit) //mouse ㅡmove 하면서
{
bSize=true; //여기서 부터 Sizing시작한다.
int X;
X=msg.LParamLo; // 메세지 LParam의 하위값이 mouse X좌표값이며 상위값이 Y값이다.
FsPoint.x=X;
FsPoint.y=0;
LaPoint.x=X;
LaPoint.y=sgrd->RowCount*(sgrd->DefaultRowHeight+sgrd->GridLineWidth);
// XOR모드로 현재 마우스 커서 위치에 세로로 선을 그린다
sgrd->Canvas->Pen->Mode=pmNot;
sgrd->Canvas->Pen->Color=clBlack;
sgrd->Canvas->MoveTo(FsPoint.x,FsPoint.y);
sgrd->Canvas->LineTo(LaPoint.x,LaPoint.y);
sgrd->Canvas->Pen->Mode=pmPenMode;
sgrd->Canvas->Pen->Color=clPenColor;
return; // Sizing시작하는 시점에 원래 Proc에 마우스 down 메세지를 보내면 Grid에 선택된 위치가 바뀌며
// 만약 column이 많이 scrollbar가 생겼다면 stroll이 일어날수 있습니다.
// 여기서 return해버리면 그런 현상이 살아집니다.
}
}
OriginalProc(msg); //그밖에 메세지는 원래 StringGrid의 WndProc함수를 보내서 동작하도록 합니다.
}
//---------------------------------------------------------------------------
void __fastcall TForm1::sgrdMouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
//
}
//---------------------------------------------------------------------------
void __fastcall TForm1::sgrdMouseMove(TObject *Sender, TShiftState Shift,
int X, int Y)
{
if(bSize)
{
// Sizing중에 이전에 그린 세로 선을 XOR모드로 다시 그려 삭제한다.
// 그리고 현재 움직이는 마우스 위치에 다시 세로선을 그린다.
sgrd->Canvas->Pen->Mode=pmNot;
sgrd->Canvas->Pen->Color=clBlack;
sgrd->Canvas->MoveTo(FsPoint.x,FsPoint.y);
sgrd->Canvas->LineTo(LaPoint.x,LaPoint.y); //XOR모드로 이전에 위치에 다시 그려 삭제
Label2->Caption="X:"+IntToStr(X)+" , Y:"+IntToStr(Y);
FsPoint.x=X;
FsPoint.y=0;
LaPoint.x=X;
LaPoint.y=sgrd->RowCount*(sgrd->DefaultRowHeight+sgrd->GridLineWidth); //세로선의 높이는 계산..
sgrd->Canvas->MoveTo(FsPoint.x,FsPoint.y); //현재 위치에 세로선을 그림
sgrd->Canvas->LineTo(LaPoint.x,LaPoint.y);
sgrd->Canvas->Pen->Mode=pmPenMode;
sgrd->Canvas->Pen->Color=clPenColor;
}
else
{
//마우스가 down되지 않는 상태 sizing중이 아닌경우
//현재 마우스 커서가 column의 경계선에 와 있는가 확인한다.
if(!Shift.Contains(ssLeft))
{
int iX=0;
int iCol,iRow;
sgrd->MouseToCell(X,Y,iCol,iRow); //X,Y좌표로 현재 커서위치의 셀을 찾는다.
TRect rc=sgrd->CellRect(iCol,iRow); // 현재 커서위치의 셀의 좌표를 찾는다.
if(IABS(rc.right,X)<3) // 커서가 셀의 오른쪽 경계선에 가까이 있나 확인
{
sgrd->Cursor=crHSplit; //커서를 변경
iColNum=iCol; // Sizing을 위해 마우스움직임이 끝난경우 (MouseUp때) Size를 변경해줘야할 컬럼
return;
}
else if(IABS(rc.Left,X)<3) // 커서가 셀의 왼쪽 경계선에 가까이 있나 확인
{
sgrd->Cursor=crHSplit;
iColNum=iCol-1; // Sizing을 위해 마우스움직임이 끝난경우 (MouseUp때) Size를 변경해줘야할 컬럼
return;
}
}
if(sgrd->Cursor==crHSplit) //셀의 경계선에 가까이 있지 않는경우 마우스 커서를 Default로 바꿔준다.
{
sgrd->Cursor=crDefault;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::sgrdMouseUp(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
sgrd->Canvas->Pen->Color=clWhite;
if(bSize)
{
TRect rc=sgrd->CellRect(iColNum,0);
if(rc.Left<=X) //sizing을 왼쪽으로 많이해서 Colulm의 넓이가 0이거나 0보자 작아지는것을 막는다.
{
sgrd->ColWidths[iColNum]=X-rc.Left; //Sizing이 끝난경우 Column의 넓이를 변경해준다.
}
}
bSize=false;
sgrd->Cursor=crDefault;
sgrd->Invalidate(); //화면을 갱신해준다.
}
//---------------------------------------------------------------------------
장성호 님이 쓰신 글 :
: 위의 답변을 수정하였습니다.
: 위글의 방법으로 할경우 스크롤바가 생겼을때 처리에 심각한 문제가 있습니다.
:
: MouseMove때 Column의 경계선에 마우스가 와있는지 확인하는 방법을 바꾸었으며
:
: 또 MouseUp때 현재 sizing중이었으면 선택된 컬럼의 넓이를 수정해주는 부분도 좀 바뀌었습니다.
:
: 그리고 Sizing중일때 Mouse가 Down된 상태로 움직이므로
: Cell의 선택이 바뀝니다.
: 이문제를 해결하기위해
: Sizing중에는 Grid의 Options에서 goRangeSelect 를 뺐다고
: 끝난후(MouseUp)이벤트에 복귀시켰습니다.
:
: 그렇게 해도 Sizing중에 선택된 Cell이 단 하나지만 움직이는 위치에 따라 바뀝니다.
: 그걸 해결하기 위해 Sizing중에는 sub-classing으로 WM_MOUSEMOVE 메세지만 처리하고
: return했습니다.
:
:
: 그러나 아직 문제가 남아있네요
:
: [남은 문제들...]
: 1. Sizing하면서 StringGrid를 벗어나는 경우에 처리에 문제가 있습니다.
: 이건 어떻게 해야 될까요? 아직 저도 특별한 아이디어가 안떠오르네요..
: 좋은생각나면 수정해서 올려드리겠습니다.
:
:
: TForm1 *Form1;
: //---------------------------------------------------------------------------
: __fastcall TForm1::TForm1(TComponent* Owner)
: : TForm(Owner)
: {
: }
: //---------------------------------------------------------------------------
: int __fastcall IABS(int a ,int b)
: {
: if(a>b)return a-b;
: else return b-a;
: }
: //---------------------------------------------------------------------------
: bool bSize;
: TPoint FsPoint,LaPoint;
: int iColNum;
: TColor clPenColor;
: TPenMode pmPenMode;
:
: typedef void __fastcall (__closure *TWNDPROC)(TMessage &msg); //VCL용 WNDPROC 타입 선언
: TWNDPROC OriginalProc;
:
: void __fastcall TForm1::FormCreate(TObject *Sender)
: {
: //
: for(int r=0;r<sgrd->RowCount;r++)
: {
: for(int c=0;c<sgrd->RowCount;c++)
: {
: sgrd->Cells[r][c]=IntToStr(r)+" - "+IntToStr(c);
: }
: }
:
: pmPenMode=sgrd->Canvas->Pen->Mode;
: clPenColor=sgrd->Canvas->Pen->Color;
: sgrd->Options=sgrd->Options>>goColSizing;
:
:
: OriginalProc=sgrd->WindowProc; // 프로그램이 시작되면서 원래 WndProc를 따로 저장해두고..
: sgrd->WindowProc=SGridMessageProc; //내가 만든 WndProc함수를 TracBar에 설정해줍니다.
:
:
: }
: //---------------------------------------------------------------------------
:
: //TarckBar 원래의 WinProc 저장할 변수
: void __fastcall TForm1::sgrdMouseDown(TObject *Sender, TMouseButton Button,
: TShiftState Shift, int X, int Y)
: {
: if(sgrd->Cursor==crHSplit)
: {
: bSize=true;
: FsPoint.x=X;
: FsPoint.y=0;
: LaPoint.x=X;
: LaPoint.y=sgrd->RowCount*(sgrd->DefaultRowHeight+sgrd->GridLineWidth);
:
: sgrd->Canvas->Pen->Mode=pmNot;
: sgrd->Canvas->Pen->Color=clBlack;
: sgrd->Canvas->MoveTo(FsPoint.x,FsPoint.y);
: sgrd->Canvas->LineTo(LaPoint.x,LaPoint.y);
: sgrd->Canvas->Pen->Mode=pmPenMode;
: sgrd->Canvas->Pen->Color=clPenColor;
:
: }
: }
: //---------------------------------------------------------------------------
: //---------------------------------------------------------------------------
: void __fastcall TForm1::SGridMessageProc(TMessage &msg)
: {
: if(msg.Msg==WM_MOUSEMOVE)
: {
: if(bSize)
: {
: int X;
:
: // msg.LParamHi; //Y값
: // msg.LParamLo; //X값
: X=msg.LParamLo;
:
: sgrd->Canvas->Pen->Mode=pmNot;
: sgrd->Canvas->Pen->Color=clBlack;
: sgrd->Canvas->MoveTo(FsPoint.x,FsPoint.y);
: sgrd->Canvas->LineTo(LaPoint.x,LaPoint.y);
:
: FsPoint.x=X;
: FsPoint.y=0;
: LaPoint.x=X;
: LaPoint.y=sgrd->RowCount*(sgrd->DefaultRowHeight+sgrd->GridLineWidth);
: sgrd->Canvas->MoveTo(FsPoint.x,FsPoint.y);
: sgrd->Canvas->LineTo(LaPoint.x,LaPoint.y);
: sgrd->Canvas->Pen->Mode=pmPenMode;
: sgrd->Canvas->Pen->Color=clPenColor;
: return; //MouseWheel 이벤트는 모두 return 해버리고
: }
: }
: OriginalProc(msg); //그밖에 메세지는 원래 tracbar의 WndProc함수를 돌려서 동작하도록 합니다.
: }
: //---------------------------------------------------------------------------
: void __fastcall TForm1::sgrdMouseMove(TObject *Sender, TShiftState Shift,
: int X, int Y)
: {
: if(!bSize)
: {
: if(!Shift.Contains(ssLeft))
: {
: int iX=0;
:
: int iCol,iRow;
: Label1->Caption="X:"+IntToStr(X)+" , Y:"+IntToStr(Y);
: sgrd->MouseToCell(X,Y,iCol,iRow);
: TRect rc=sgrd->CellRect(iCol,iRow);
: if(IABS(rc.right,X)<3)
: {
: sgrd->Cursor=crHSplit;
: iColNum=iCol;
: sgrd->Options>>goRangeSelect;
: return;
: }
: else if(IABS(rc.Left,X)<3)
: {
: sgrd->Cursor=crHSplit;
: iColNum=iCol-1;
: sgrd->Options>>goRangeSelect;
: return;
: }
: }
: if(sgrd->Cursor==crHSplit)
: {
: sgrd->Cursor=crDefault;//
: sgrd->Options=sgrd->Options<<goRangeSelect;
: }
: }
: }
: //---------------------------------------------------------------------------
:
:
: void __fastcall TForm1::sgrdMouseUp(TObject *Sender, TMouseButton Button,
: TShiftState Shift, int X, int Y)
: {
:
: sgrd->Invalidate();
: sgrd->Canvas->Pen->Color=clWhite;
: if(bSize)
: {
: TRect rc=sgrd->CellRect(iColNum,0);
:
: if(rc.Left<=X)
: {
: sgrd->ColWidths[iColNum]=X-rc.Left;
: }
: }
: bSize=false;
: sgrd->Cursor=crDefault;
: sgrd->Options=sgrd->Options<<goRangeSelect;
:
: }
: //---------------------------------------------------------------------------
:
: 장성호 님이 쓰신 글 :
: : 전에도 똑같은 질문 올리셨죠?
: :
: : 기본적으로는 TStringGrid * 에서는 안되기 때문에.. 답변을 못해드렸는데...
: :
: : 아래코드는 직접 코딩으로 구현한것입니다.
: : MouseDown , MouseMove , MouseUp 이벤트를 이용했습니다.
: :
: : 급하게 만들어서 문제가 좀 있습니다.
: :
: : [문제들]
: : 1. 스크롤바가 생겼을때 처리 ( 옆으로 옮긴 위치만큼 처리안됨)
: : 2. Paint문제가 좀 있는것 같아요
: : 3. Click할때 Cell이 선택되는 문제...
: :
: : 그대로 가져가셔서 붙인후 테스트 해보세요
: :
: : 위 몇가지 문제만 해결하면 쓸만할 겁니다. (특히 1번문제 반드시 처리해야함)
: :
: : 시간이 없어서 이만..
: : 조만간 시간되면 위에 문제도 해결해서 올려드릴께요
: :
: : 그럼
: :
: :
: :
: :
: : ==========<<샘플>>===========================================================
: : TForm1 *Form1;
: : //---------------------------------------------------------------------------
: : __fastcall TForm1::TForm1(TComponent* Owner)
: : : TForm(Owner)
: : {
: : }
: : //---------------------------------------------------------------------------
: : bool bSize;
: : TPoint FsPoint,LaPoint;
: : int iColNum;
: : TColor clPenColor;
: : TPenMode pmPenMode;
: : void __fastcall TForm1::FormCreate(TObject *Sender)
: : {
: : //
: : for(int r=0;r<sgrd->RowCount;r++)
: : {
: : for(int c=0;c<sgrd->RowCount;c++)
: : {
: : sgrd->Cells[r][c]=IntToStr(r)+" - "+IntToStr(c);
: : }
: : }
: :
: : pmPenMode=sgrd->Canvas->Pen->Mode;
: : clPenColor=sgrd->Canvas->Pen->Color;
: : sgrd->Options=sgrd->Options>>goColSizing;
: : }
: : //---------------------------------------------------------------------------
: : int __fastcall IABS(int a ,int b)
: : {
: : if(a>b)return a-b;
: : else b-a;
: : }
: : //---------------------------------------------------------------------------
: : void __fastcall TForm1::sgrdMouseDown(TObject *Sender, TMouseButton Button,
: : TShiftState Shift, int X, int Y)
: : {
: : if(sgrd->Cursor==crHSplit)
: : {
: : bSize=true;
: : FsPoint.x=X;
: : FsPoint.y=0;
: : LaPoint.x=X;
: : LaPoint.y=sgrd->RowCount*(sgrd->DefaultRowHeight+sgrd->GridLineWidth);
: :
: :
: : sgrd->Canvas->Pen->Mode=pmNot;
: : sgrd->Canvas->Pen->Color=clBlack;
: : sgrd->Canvas->MoveTo(FsPoint.x,FsPoint.y);
: : sgrd->Canvas->LineTo(LaPoint.x,LaPoint.y);
: : sgrd->Canvas->Pen->Mode=pmPenMode;
: : sgrd->Canvas->Pen->Color=clPenColor;
: :
: : }
: : }
: : //---------------------------------------------------------------------------
: :
: : void __fastcall TForm1::sgrdMouseMove(TObject *Sender, TShiftState Shift,
: : int X, int Y)
: : {
: : if(bSize)
: : {
: : sgrd->Canvas->Pen->Mode=pmNot;
: : sgrd->Canvas->Pen->Color=clBlack;
: : sgrd->Canvas->MoveTo(FsPoint.x,FsPoint.y);
: : sgrd->Canvas->LineTo(LaPoint.x,LaPoint.y);
: :
: : FsPoint.x=X;
: : FsPoint.y=0;
: : LaPoint.x=X;
: : LaPoint.y=sgrd->RowCount*(sgrd->DefaultRowHeight+sgrd->GridLineWidth);
: : sgrd->Canvas->MoveTo(FsPoint.x,FsPoint.y);
: : sgrd->Canvas->LineTo(LaPoint.x,LaPoint.y);
: : sgrd->Canvas->Pen->Mode=pmPenMode;
: : sgrd->Canvas->Pen->Color=clPenColor;
: : //enum TPenMode {pmBlack, pmWhite, pmNop, pmNot, pmCopy, pmNotCopy, pmMergePenNot, pmMaskPenNot, pmMergeNotPen, pmMaskNotPen, pmMerge, pmNotMerge, pmMask, pmNotMask, pmXor, pmNotXor};
: :
: :
: : }
: : else
: : {
: : if(!Shift.Contains(ssLeft))
: : {
: : int iX=0;
: : for(int c=0;c<sgrd->RowCount;c++)
: : {
: : iX=iX+sgrd->ColWidths[c]+1;
: : if(IABS(iX,X)<2)
: : {
: : sgrd->Cursor=crHSplit;
: : iColNum=c;
: : sgrd->Options>>goRangeSelect;
: : return;
: : }
: : }
: : }
: : if(sgrd->Cursor==crHSplit)
: : {
: : sgrd->Cursor=crDefault;//
: : sgrd->Options=sgrd->Options<<goRangeSelect;
: : }
: : }
: :
: : }
: : //---------------------------------------------------------------------------
: :
: :
: : void __fastcall TForm1::sgrdMouseUp(TObject *Sender, TMouseButton Button,
: : TShiftState Shift, int X, int Y)
: : {
: :
: : sgrd->Invalidate();
: : sgrd->Canvas->Pen->Color=clWhite;
: : if(bSize)
: : {
: : int iX=0;
: : for(int c=0;c<iColNum;c++)
: : {
: : iX=iX+sgrd->ColWidths[c]+1;
: : }
: :
: : sgrd->ColWidths[iColNum]=X-iX;
: : }
: : bSize=false;
: : sgrd->Cursor=crDefault;
: : sgrd->Options=sgrd->Options<<goRangeSelect;
: :
: : }
: : //---------------------------------------------------------------------------
: :
: :
: :
: : 쥐르미온 님이 쓰신 글 :
: : : 회섹으로 된 고정셀의 경우, 마우스를 셀의 경계선쪽으로 가져가면 열이나 너비를 수정할 수가 있게 되는데요. 일반 셀에서는 그것이 불가능합니다.
: : :
: : : 맨윗줄을 회색의 고정셀로 하지 않고도 너비 수정을 할 수 있었으면 좋겠는데요. 어떻게 해야하죠?
|