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

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[909] [Controls] GraphicControl 마우스로 움직이기 2
장성호 [nasilso] 11944 읽음    2009-07-30 12:13
바로 아래 팁에서
GraphicControl   마우스로 움직이기는 방법을 소개했습니다.
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=908

그런데 그 방법에는 문제점이 좀  있습니다.


GraphicControl 마우스로 움직이기 1의 문제점
   GraphicControl   마우스로 움직이기 1의 문제점은
   GraphicControl을 run-time에 마우스로 움직이는것 기능외에
   다른 기능을  MouseDown / MouseMove이벤트에  코딩을 하여 만들어야 할경우
  
   Control을 움직이는 코드랑 , 다른 기능의 코드가 하나의 이벤트 핸들러 함수 안에 있어야 하니
   코드가 헷갈리고 가독성도 떨어지고........

   전혀 다른 목적의 기능이 같은 함수안에 있게 되죠

   예를 들어
      TImage 위에 마우스로 그림을 그릴경우 MouseDown / MouseMove / MouseUp이벤트를 이용해야 합니다.
      그런 기능과 함께 TImage를 선택하여 이동하는 기능도 넣어야 한다면...
       위와같은 문제점이 발생하게 되겠죠...


기능 중복 해결방법1
   위 문제의 해결방법으로 첫번째는
   GraphicControl을 움직이는 용도의  MouseDown / MouseMove  함수를 따로 만들어두고
   움직임이 필요할때 동적으로 EventHandler를 변경해주는 방식으로 가능합니다.


//Image위에 마우스로 Line을 그리는 이벤트 핸들러
TPoint LineStPt,LineMovePt;
void __fastcall TForm1::Image1MouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
    if(Shift.Contains(ssLeft))
    {
        LineStPt=Point(X,Y);
        LineMovePt=LineStPt;
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image1MouseMove(TObject *Sender, TShiftState Shift,
      int X, int Y)
{
    if(Shift.Contains(ssLeft))
    {
        Image1->Canvas->Pen->Mode=pmNotXor;
        Image1->Canvas->MoveTo(LineStPt.x,LineStPt.y);
        Image1->Canvas->LineTo(LineMovePt.x,LineMovePt.y);
        LineMovePt=Point(X,Y);
        Image1->Canvas->MoveTo(LineStPt.x,LineStPt.y);
        Image1->Canvas->LineTo(LineMovePt.x,LineMovePt.y);
    }

}
//---------------------------------------------------------------------------
void __fastcall TForm1::Image1MouseUp(TObject *Sender, TMouseButton Button,
      TShiftState Shift, int X, int Y)
{
    //
    if(Button==mbLeft)
    {
        Image1->Canvas->Pen->Mode=pmNotXor;
        Image1->Canvas->MoveTo(LineStPt.x,LineStPt.y);
        Image1->Canvas->LineTo(LineMovePt.x,LineMovePt.y);
        Image1->Canvas->Pen->Mode=pmCopy;
        Image1->Canvas->MoveTo(LineStPt.x,LineStPt.y);
        Image1->Canvas->LineTo(X,Y);
    }
}
//---------------------------------------------------------------------------

//GraphicControl을 마우스로 이동시키고자 할때..
TPoint PrePt,CurPt;
void __fastcall TForm1::GraphicControlMouseDown(TObject *Sender,
      TMouseButton Button, TShiftState Shift, int X, int Y)
{
    if(Shift.Contains(ssLeft))
    {
        GetCursorPos(&PrePt);  //현재 마우스 좌표를 저장
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::GraphicControlMouseMove(TObject *Sender, TShiftState Shift,
      int X, int Y)
{
    if(Shift.Contains(ssLeft))
    {
        TGraphicControl *GCtrl=(TGraphicControl *)Sender;

      GetCursorPos(&CurPt); //마우스 움직인 후의 현재 마우스 가져옴
      //이전 좌표와 비교해서 Image의 위치를 이동시켜줌

      GCtrl->Left=GCtrl->Left+(CurPt.x-PrePt.x);
      GCtrl->Top=GCtrl->Top+(CurPt.y-PrePt.y);
      PrePt=CurPt; // 현재 좌표를 이전좌표로 기억해둠

    }
}
//---------------------------------------------------------------------------
//Image를 마우스로 클릭해 이동하도록  이벤트 설정
void __fastcall TForm1::B_MoveImageClick(TObject *Sender)
{
    Image1->OnMouseDown=GraphicControlMouseDown;
    Image1->OnMouseMove=GraphicControlMouseMove;
    Image1->OnMouseUp=NULL;
}
//---------------------------------------------------------------------------
//Image위에 마우스로 선(Line)을 그리도록 이벤트 설정
void __fastcall TForm1::B_DrawImageClick(TObject *Sender)
{
    Image1->OnMouseDown=Image1MouseDown;
    Image1->OnMouseMove=Image1MouseMove;
    Image1->OnMouseUp=Image1MouseUp;
}
//---------------------------------------------------------------------------


위 코드에서 "B_MoveImage" 버튼을  클릭하면  Image를 Mouse로 선택하여 이동할수 있게 되구
"B_DrawImage" 버튼을 클릭하면 Image위에 Mouse로 선을 그릴수 있게 됩니다.


기능 중복 해결방법2
   위와같이 이벤트 핸들러를 변경하여서  
   서로다른 기능이 같은 함수에 중복 코딩되는것을 피하였는데요
   이벤트 핸들러를 변경하지 않고 하는 방법도 있습니다.
  
   이벤트 핸들러를 변경하지도 않고
   같은 OnMouseMove 함수안에 Line그리는 코드와 Image를 이동하는 코드를 같이 넣지도 않고..
   어떻게 하면 될까요?
  

  음 그것은 GraphicControl에 있는 WndProc를 이용하면 됩니다.
  GraphicControl은 Handle이 없으면서 왠 WndProc가 있나 의문이 드시는 분이 있을지 모르겠습니다만..
 
  실제로는 GraphicControl의 Parent에서 메세지를 받아서 그것을 GraphicControl의 WndProc로 넘겨주는것입니다.

  여튼 모든 GraphicControl에는 WndProc가 있구
  WndProc 에서 OnMouseDown / OnMouseMove이벤트 핸들러를 호출해주므로 WndProc를 sub-classing하여
  위 기능을 구현할수 있습니다.

   다음 코드는 TLabel을 교체식으로 WndProc를 sub-classing하여서
   새로만들었습니다.
 
//TForm1클래스 앞에 TLabel클래스를 재정의 

//TLabel클래스를 Stdctrl의 TLabel을 상속받아 재정의 
class TLabel : public Stdctrls::TLabel 
{ 
private: 
    bool FCtrlMove; 
    TPoint FPrePt,FCurPt; 
public: 
    void __fastcall StartLabelMove(TShiftState Shift); 
    void __fastcall StopLabelMove(); 
    void __fastcall WndProc(TMessage &Message); 
}; 

//전처리문으로 TLabel을 바로위에 선언한놈으로 설정해줌 
#define TLabel ::TLabel 

class TForm1 : public TForm 
{ 
__published:  // IDE-managed Components 
  TButton *Button1; 
  TPanel *Panel1; 
  TButton *Button2; 
  TLabel *Label1; 
  TLabel *Label2; 
  void __fastcall Button1Click(TObject *Sender); 
  void __fastcall Button2Click(TObject *Sender); 
  void __fastcall Label1MouseDown(TObject *Sender, TMouseButton Button, 
          TShiftState Shift, int X, int Y); 
private:  // User declarations 
public:    // User declarations 
  __fastcall TForm1(TComponent* Owner); 
}; 
  

   
Header에는 위와같이하구..
교체식으로 새로만든 TLabel의 WndProc에서
run-time에  Control을 마우스로 움직이는 기능을 구현합니다.

void __fastcall TLabel::StartLabelMove(TShiftState Shift) 
{ 
  if(Shift.Contains(ssLeft)) 
   { 
     FCtrlMove=true; 
      FPrePt=Mouse->CursorPos; 
   } 
} 
//--------------------------------------------------------------------------- 
void __fastcall TLabel::StopLabelMove() 
{ 
  FCtrlMove=false; 
} 
//--------------------------------------------------------------------------- 
void __fastcall TLabel::WndProc(TMessage &Message) 
{ 
  if((Message.Msg == WM_MOUSEMOVE) && FCtrlMove ) 
  { 
      FCurPt=Mouse->CursorPos; 
      this->Left = this->Left+(FCurPt.x-FPrePt.x); 
      this->Top  = this->Top+(FCurPt.y - FPrePt.y); 
      FPrePt=FCurPt; 
      Dispatch(&Message); 
  } 
  else if (Message.Msg == WM_LBUTTONUP) 
  { 
    FCtrlMove = false; 
    Dispatch(&Message); 
  } 
  else 
  { 
      TCustomLabel::WndProc(Message); 
  } 
} 
//--------------------------------------------------------------------------- 


실제 사용은 다음과 같이 간단히 한줄만...
void __fastcall TForm1::Label1MouseDown(TObject *Sender, 
      TMouseButton Button, TShiftState Shift, int X, int Y) 
{ 
  Label1->StartLabelMove(Shift); 
} 
//---------------------------------------------------------------------------    


TLabel뿐만 아니라 다른 GraphicControl도 모두 가능하구요
델파이도 똑같은 윈리로 가능합니다.

그럼...

+ -

관련 글 리스트
909 [Controls] GraphicControl 마우스로 움직이기 2 장성호 11944 2009/07/30
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.