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

C++빌더 강좌/문서
C++Builder Programming Tutorial&Docments
[181] 까짓 TWinControl의 자식이 아닌 컨트롤도 마우스로 움직여 보자
Nibble [gameover] 15930 읽음    2009-01-19 17:13
앞서 김태선님이 올리신 예제를 뒤늦게 보고 재미삼아 작성해 보았습니다.

아이디어>
각 컨트롤들이 클릭될때 PanelDragContainer를 컨트롤의 위치로 가져와 크기도 맞춘 다음
해당 컨트롤을 PanelDragContainer 위로 올려두어 드래깅 메시지를 타게 한 후
드래그 종료시 PanelDragContainer 위의 컨트롤을 내려놓고 PanelDragContainer를 다시 숨기게 되면
윈도우 핸들이 없는 컨트롤도 드래그 할 수 있을 것이다.

특징>
TControl 을 상속받은 어떤 컨트롤도 끌고다닐 수 있습니다 :)

구현>
우선 Form 에 PanelDragContainer라는 녀석을 숨겨둡니다.
그리고 Form 의 멤버로 두 개의 함수를 추가하는데요,
    void __fastcall DragInitializer(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
    void __fastcall DragFinalizer(tagMSG &Msg, bool &Handled);
DragInitializer는 Label 과 같은 윈도우 핸들이 없는 컨트롤이 드래그 가능하게끔 해 주며
각 컨트롤의 OnMouseDown 에 물려두시면 되고,
DragFinalizer는 ReleaseCapture 후 컨트롤에 넘겨지지 않는 마우스 메시지를 잡아내
드래그 종료시의 처리를 하도록 Application->OnMessage에 물려두게됩니다.

void __fastcall TForm1::DragInitializer(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y){
    TControl* childControl  = dynamic_cast(Sender);
    if (childControl){
        PanelDragContainer->Parent      = childControl->Parent;
        PanelDragContainer->Left        = childControl->Left;
        PanelDragContainer->Top         = childControl->Top;
        PanelDragContainer->Width       = childControl->Width;
        PanelDragContainer->Height      = childControl->Height;
        childControl->Parent            = PanelDragContainer;
        childControl->Left              = 0;
        childControl->Top               = 0;
        PanelDragContainer->Visible     = true;
        ReleaseCapture();
        SendMessage(PanelDragContainer->Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
    }
}


void __fastcall TForm1::DragFinalizer(tagMSG &Msg, bool &Handled){
    switch(Msg.message){
    case WM_MOUSEFIRST:
        if (PanelDragContainer->ControlCount){
            TControl* childControl      = PanelDragContainer->Controls[0];
            childControl->Left          = PanelDragContainer->Left;
            childControl->Top           = PanelDragContainer->Top;
            childControl->Parent        = PanelDragContainer->Parent;
            PanelDragContainer->Visible = false;
        }
        break;
    }
}


class TForm1 : public TForm
{
__published:	// IDE-managed Components
    TPanel *PanelDragContainer;
    TLabel *Label1;
    TLabel *Label2;
    TLabel *Label3;
    TLabel *Label4;
private:	// User declarations
    void __fastcall DragFinalizer(tagMSG &Msg, bool &Handled);
    void __fastcall DragInitializer(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y);
public:		// User declarations
    __fastcall TForm1(TComponent* Owner);
};


아래에 보이는것 처럼 PanelDrag는 숨겨두었고, DoubleBuffered 속성을 켜서 깜박이지 않게 해 두었습니다.
또한, DragFinalizer를 Application->OnMessage에 연결시켜 뒀죠.
그 다음부터는 드래그 가능하게 할 컨트롤들의 OnMouseDown 에 DragInitializer를 연결해 두면 됩니다.
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner){
    PanelDragContainer->DoubleBuffered  = true;
    PanelDragContainer->Visible         = false;
    Application->OnMessage              = DragFinalizer;

    Label1->OnMouseDown                 = DragInitializer;
    Label2->OnMouseDown                 = DragInitializer;
    Label3->OnMouseDown                 = DragInitializer;
    Label4->OnMouseDown                 = DragInitializer;
}


p.s. 마우스로 끄는 동안 창의 내용을 표시하는 옵션이 꺼져있다면, 당연하게도 드래그되는 모습이 보이지
않습니다.
SendMessage(PanelDragContainer->Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
방식을 쓰는이상은 어쩔 수 없죠 :)
장성호 [nasilso]   2009-01-19 21:35 X
재미있네요. 좋은 아이디어인것 같습니다.

그런데.. DragInitializer 함수의 SendMessage 바로 뒤에 다시 Control을 원상태로 Parent를 변경하고
Panel을 visible=false하는 코드를 넣어도 될듯 한데요..

그리고
당연한것 같기도 하지만
Drag하면 control의 ZOrder가 바뀌어 버릴것 같네요..
Parent가 같은 control이 여러개 있을경우 뒷쪽에 있던것이 앞으로 올듯...

그럼..
Nibble [gameover]   2009-01-20 14:06 X
대부분의 Layer기반 편집기능이, 선택된 녀석은 앞으로 오게 마련이죠 :) 필요하면 Z-order를 Hold하는 처리를 해 주면되겠지만, 어디까지나 예제 코드구요.

SendMessage 이후의 처리는 좋은 생각이네요. SendMessage 라서 가능한 방법인데 미처 생각하지 못했습니다.

void __fastcall TForm1::DragInitializer(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y){
    TControl* childControl  = dynamic_cast<TControl*>(Sender);
    if (childControl){
        PanelDragContainer->Parent      = childControl->Parent;
        PanelDragContainer->Left        = childControl->Left;
        PanelDragContainer->Top         = childControl->Top;
        PanelDragContainer->Width       = childControl->Width;
        PanelDragContainer->Height      = childControl->Height;
        childControl->Parent            = PanelDragContainer;
        childControl->Left              = 0;
        childControl->Top               = 0;
        PanelDragContainer->Visible     = true;
        ReleaseCapture();
        SendMessage(PanelDragContainer->Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
        PanelDragContainer->Visible     = false;
        childControl->Left              = PanelDragContainer->Left;
        childControl->Top               = PanelDragContainer->Top;
        childControl->Parent            = PanelDragContainer->Parent;
    }
}

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner){
    PanelDragContainer->DoubleBuffered  = true;
    PanelDragContainer->Visible         = false;
    DoubleBuffered                      = true;

    Label1->OnMouseDown                 = DragInitializer;
    Label2->OnMouseDown                 = DragInitializer;
    Label3->OnMouseDown                 = DragInitializer;
    Label4->OnMouseDown                 = DragInitializer;
}

하나로 끝나는군요 :)
Nibble [gameover]   2009-01-21 03:37 X
Panel 을 DragInitializer 안에서 동적 생성해버리는게 더 편할지도 모르겠습니다 :(

+ -

관련 글 리스트
181 까짓 TWinControl의 자식이 아닌 컨트롤도 마우스로 움직여 보자 Nibble 15930 2009/01/19
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.