TShape은 좋은 컴포인데 단점은 몇가지 모양 밖에 없다는 것입니다.
원하는 도형은 어떻게 그릴까요?
TShape을 상속받아 Paint() 메소드에서 새로운 모양을 그려주면 됩니다.
아래는 소스입니다.
아래 코드는 빌더 2007에서 실험되었습니다. 빌더 6에서 바로 동작하는지는 확인 안했지만 아마도 될 듯합니다.
//---------------------------------------------------------------------------
// 컴포넌트 교체식으로 만든 내 마음대로 도형 그리기.
class TShape : public Extctrls::TShape
{
typedef Extctrls::TShape inherited;
private:
struct TF
{
TPen *FPen;
TBrush *FBrush;
TShapeType FShape;
};
TF* GetF() // private영역의 변수를 제어하기 위해.
{
return (TF*)((UINT)this + sizeof(Controls::TGraphicControl));
}
protected:
virtual void __fastcall Paint(void)
{
if (Tag < 1000)
{
inherited::Paint();
return;
}
TF *F = GetF();
TCanvas *C = Canvas;
int X, Y, W, H, S;
C->Pen = F->FPen;
C->Brush = F->FBrush;
X = C->Pen->Width / 2;
Y = X;
W = Width - C->Pen->Width + 1;
H = Height - C->Pen->Width + 1;
if (C->Pen->Width == 0)
{
W--; H--;
}
if (W < H) S = W; else S = H;
if (Tag >= 2000) // 정사각형 영역에 들어오는 모양이면
{
X += (W - S) / 2;
Y += (H - S) / 2;
W = S;
H = S;
}
TPoint pt[3];
ZeroMemory(pt, sizeof(pt));
switch(Tag % 1000)
{
case 0: // 좌측으로 삼각형
pt[0] = Point(X, Y + H / 2);
pt[1] = Point(X + W - 1, Y);
pt[2] = Point(X + W - 1, Y + H - 1);
C->Polygon(pt, 2);
break;
case 1: // 우측으로 삼각형
pt[0] = Point(X + W - 1, Y + H / 2);
pt[1] = Point(X, Y);
pt[2] = Point(X, Y + H - 1);
C->Polygon(pt, 2);
break;
case 2: // 위로 삼각형
pt[0] = Point(X + W / 2, Y);
pt[1] = Point(X, Y + H - 1);
pt[2] = Point(X + W - 1, Y + H - 1);
C->Polygon(pt, 2);
break;
case 3: // 아래로 삼각형
pt[0] = Point(X + W / 2, Y + H - 1);
pt[1] = Point(X, Y);
pt[2] = Point(X + W - 1, Y);
C->Polygon(pt, 2);
break;
}
}
};
#define TShape ::TShape
//---------------------------------------------------------------------------
Tag 값이 1000미만이면 기존 TShape와 동작이 똑 같습니다.
Tag 값이 1000 ~ 1003 까지 값을 넣으면 삼각형이 원하는 방향으로 그려집니다.
Tag 값을 2000 ~ 2003 까지 값을 넣으면 삼각형이 원하는 방향으로 그려지지만 정사각형 범위안에서 그려집니다.
예제는 삼각형만을 그렸으나, 원하는 모양이 있다면 각자 추가하면 될 것입니다.
하지만 아무래도 예쁜 모양을 위해서는 TImage를 쓰는게 낫겠죠.
위에서 상속받은 클래스의 private영역의 내부 변수 제어를 하는 방법은 눈여겨 볼만한 코드입니다.
그런데 위에서
C->Pen = F->FPen;
C->Brush = F->FBrush;
이렇게 굳이 어렵게 하지 않고 그냥 간단히 프로퍼티에 있으니
C->Pen = Pen;
C->Brush = Brush;
하는 쪽이 더 편리합니다만 위 예제는 예를 보이기 위한 것이라 저렇게 처리 했습니다.
프로퍼티에서 나타나지 않는 내부 변수가 필요할 경우도 있기 때문입니다.
자 그러면 이 컴포넌트를 마우스로 드래그하여 움직여 볼까요?
원래 TWinControl 후손이라면 아주 쉽게 단 2줄로 이동이 가능합니다.
//---------------------------------------------------------------------------
void __fastcall TForm2::Panel1MouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
ReleaseCapture();
SendMessage(Panel1->Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
//---------------------------------------------------------------------------
하지만 TGraphicControl 후손이라 이런 처리가 안됩니다.
이런 TWinControl 핸들을 만들때 처리했던 윈도우 만들기와 관련 처리를 같이 해야하는데
컴포넌트 움직이자고 그 처리를 하기는 좀 무리해 보입니다. 그럴 양이면
그냥 TWinControl 후손 컴포넌트에서 적당한 것을 골라 기능을 수정해서 쓰겠죠.
그래서 아주 쉽게 코딩으로 움직이는 상투적인 방법을 쓰겠습니다.
아래는 TShape을 마우스로 드래그하여 움직이는 예제입니다.
//---------------------------------------------------------------------------
struct
{
bool bDown;
TPoint DownPoint;
} m;
//---------------------------------------------------------------------------
void __fastcall TForm2::Shape2MouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
m.bDown = true;
m.DownPoint = Point(X, Y);
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Shape2MouseMove(TObject *Sender, TShiftState Shift,
int X, int Y)
{
if (m.bDown == false)
return;
if (Point(X, Y) != m.DownPoint) // 빌더6에서는 x, y를 각각 비교해야 합니다.
{
Shape2->Left += X - m.DownPoint.x;
Shape2->Top += Y - m.DownPoint.y;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Shape2MouseUp(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
m.bDown = false;
}
//---------------------------------------------------------------------------
아주 깔끔하고 쉽게 움직입니다.
TShape대산 TImage에 아주 예쁜 화살표 같은 그림을 넣어 움직이는 것이 사실상 더 보기가 좋습니다.
그럴때도 코드는 위와 같습니다.
Transparent = ture; 로 놓으면 그림의 배경이 투명해 지닌까 아주 보기 좋게 되겠죠.
아래는 그림이 위 아래로만 마우스에 끌려 이동하는 예제입니다.
//---------------------------------------------------------------------------
void __fastcall TForm2::Image1MouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
m.bDown = true;
m.DownPoint = Point(X, Y);
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Image1MouseMove(TObject *Sender, TShiftState Shift,
int X, int Y)
{
if (m.bDown == false)
return;
if (Y != m.DownPoint.y) // 그림이 위 아래로만 움직이게 한다.
{
// 필요하면 움직이는 영역제한은 여기서 한다.
Image1->Top += Y - m.DownPoint.y;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Image1MouseUp(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
m.bDown = false;
}
//---------------------------------------------------------------------------
사실 제가 필요해서 만들다가 곁다리로 적은 게시물이라서 갑자기 TGraphicControl 후손
컴포넌트 움직이는 것 까지 내용이 들어가 버렸는데... 대충 이해 바랍니다.
그럼..
|