C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[46425] Re:Re:Re:StringGrid 열의 너비 수정, 위 답변을 또 조금 수정하여...( 설명 포함 )
장성호 [nasilso] 1357 읽음    2006-09-02 23:13
또 다시 조금 수정...

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;
: :
: : }
: : //---------------------------------------------------------------------------
: :
: :
: :
: : 쥐르미온 님이 쓰신 글 :
: : : 회섹으로 된 고정셀의 경우, 마우스를 셀의 경계선쪽으로 가져가면 열이나 너비를 수정할 수가 있게 되는데요. 일반 셀에서는 그것이 불가능합니다.
: : :
: : : 맨윗줄을 회색의 고정셀로 하지 않고도 너비 수정을 할 수 있었으면 좋겠는데요. 어떻게 해야하죠?

+ -

관련 글 리스트
46405 StringGrid 열의 너비 수정이 안되네요. ㅠ_ㅠ 고수님들, 답변 좀 부탁드립니다. 쥐르미온 912 2006/09/01
46414     Re:StringGrid 열의 너비 수정이 안되네요. ㅠ_ㅠ 고수님들, 답변 좀 부탁드립니다. 장성호 1038 2006/09/01
46417         Re:Re:StringGrid 열의 너비 수정... 위 답변을 조금 수정하여... 장성호 1059 2006/09/02
46425             Re:Re:Re:StringGrid 열의 너비 수정, 위 답변을 또 조금 수정하여...( 설명 포함 ) 장성호 1357 2006/09/02
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.