sw2007/03/20 17:10
다이얼로그에 메뉴올리기

1. 일반 다이얼로그 상에서 Menu 리소스를 추가한다.
사용자 삽입 이미지
























2. 메뉴를 구성한다.
사용자 삽입 이미지






















3. 다이얼로그 프로퍼티에서 Menu를 추가해준다.
사용자 삽입 이미지






















4. 기타 이벤트에 관한사항을 처리한다.
Posted by redef
TAG C, Control

댓글을 달아 주세요

sw2007/03/05 13:27
사용자 삽입 이미지










Introduction

커스텀 컨트롤을 만드는 .NET 프레임워크의 짧고 간단한 데모입니다.
여기서 커스텀 컨트롤을 만들어서 윈도우 어플리케이션에서 컨트롤을 테스트 할것입니다.
컨트롤의 몇가지의 커스텀 프로퍼티를 구현할것입니다, 그래서 c#에서 구현을 어떻게 하는지 배울수 있습니다.

Building the Control

Visual Studio를 열고 새프로젝트를 시작합니다.
프로젝트는 Windows Control Library 템플릿의 기반이어야만 합니다.
ctlCuteButton 으로 프로젝트는 정하고 OK 클릭합니다.

프로젝트가 열리고 난후, 프로젝트에서 UserControl을 삭제합니다.
여기서 필요한게 'User Control'이 아니기 때문에 지워야 합니다.

'Project'메뉴에서 Project->Add User Control...로 가서 Custom Control 템플릿을 선택합니다.
이 예에서 우리가 필요한것이 'Custom Control' 입니다.
그것을 cuteButton으로 해야합니다.
OK 클릭합니다.
새로운 커스텀 컨트롤을 프로젝트에 추가하였습니다.

첫번째로 해야 할일은 cuteButton의 베이스 클래스를 바꿔야 합니다:

아래 줄을 :

public class cuteButton : System.Windows.Forms.Control

이와 같이:

public class cuteButton : System.Windows.Forms.Button

이제 컨트롤은 System.Windows.Forms.Button 클래스 기반입니다.

컨트롤을 위한 커스텀 프로퍼티들은 만들것입니다,
cuteButton 클래스에 다음 코드를 삽입합니다.

private Color m_color1 = Color.LightGreen; //first color
private Color m_color2 = Color.DarkBlue; // second color
private int m_color1Transparent = 64; // transparency degree
// (applies to the 1st color)
private int m_color2Transparent = 64; // transparency degree
// (applies to the 2nd color)

public Color cuteColor1
{
get { return m_color1; }
set { m_color1 = value; Invalidate(); }
}

public Color cuteColor2
{
get { return m_color2; }
set { m_color2 = value; Invalidate(); }
}

public int cuteTransparent1
{
get { return m_color1Transparent; }
set { m_color1Transparent = value; Invalidate(); }
}

public int cuteTransparent2
{
get { return m_color2Transparent; }
set { m_color2Transparent = value; Invalidate(); }
}

Invalidate() 메소드는 뷰나 모든 컨트롤의 내부에서 디자인을 리프레쉬 하곤합니다.
그리고 마지막으로 컨트롤을 컨파일 하기전에 Paint 이벤트를 오버라이드 해야한다.

다음처럼 :

// Calling the base class OnPaint
base.OnPaint(pe);
// Create two semi-transparent colors
Color c1 = Color.FromArgb(m_color1Transparent , m_color1);
Color c2 = Color.FromArgb(m_color2Transparent , m_color2);
Brush b = new System.Drawing.Drawing2D.LinearGradientBrush(ClientRectangle,
c1, c2, 10);
pe.Graphics.FillRectangle (b, ClientRectangle);
b.Dispose();

Ctrl + Shift + B 를 눌러 컨트롤을 컴파일 할수 있습니다.

여기 완전한 cuteButton.cs 파일의 내용이 있습니다

코드 전체:

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;


namespace ctlCuteButton
{
///
/// Summary description for cuteButton.
///

public class cuteButton : System.Windows.Forms.Button
{
private Color m_color1 = Color.LightGreen; // first color
private Color m_color2 = Color.DarkBlue; // second color
private int m_color1Transparent = 64; // transparency degree
// (applies to the 1st color)
private int m_color2Transparent = 64; // transparency degree
// (applies to the 2nd color)

public Color cuteColor1
{
get { return m_color1; }
set { m_color1 = value; Invalidate(); }
}

public Color cuteColor2
{
get { return m_color2; }
set { m_color2 = value; Invalidate(); }
}

public int cuteTransparent1
{
get { return m_color1Transparent; }
set { m_color1Transparent = value; Invalidate(); }
}

public int cuteTransparent2
{
get { return m_color2Transparent; }
set { m_color2Transparent = value; Invalidate(); }
}


public cuteButton()
{
}


protected override void OnPaint(PaintEventArgs pe)
{
// Calling the base class OnPaint
base.OnPaint(pe);
// Create two semi-transparent colors
Color c1 = Color.FromArgb
(m_color1Transparent , m_color1);
Color c2 = Color.FromArgb
(m_color2Transparent , m_color2);
Brush b = new System.Drawing.Drawing2D.LinearGradientBrush
(ClientRectangle, c1, c2, 10);
pe.Graphics.FillRectangle (b, ClientRectangle);
b.Dispose();
}
}
}

Testing the Control

VS.NET을 새로 오픈합니다.
Windows Application 템플릿 프로젝트를 만듭니다.

새로운 Windows Form 프로젝트에서 toolbox에 컴파일한 커스텀 컨트롤을 추가할수 있습니다.
toolbox에서 마우스 오른쪽을 클릭해서 Customize Toolbox를 선택하고 .NET Framework Components 탭에서 Browse를 클릭하고 컨트롤 라이브러리 DLL위치를 선택합니다.
Toolbox에 cuteButton 컴포넌트가 나타날것입니다.
프로퍼티를 바꿀수 있습니다.(cuteColor1, cuteColor2, cuteTransparent1, cuteTransparent2)
Posted by redef
TAG c#, Control

댓글을 달아 주세요

sw2007/03/05 13:23

CHoverButton 을 CBitmapButton을 상속받아 생성한다.

WM_DRAWITEM이 아닌 DrawItem을 Overriding 한다.

CDC *mydc = CDC::FromHandle(lpDrawItemStruct->hDC);

CDC *pMemDC = new CDC;
pMemDC->CreateCompatibleDC(mydc);

CBitmap *pOldBitmap;
pOldBitmap = pMemDC->SelectObject(&mybitmap); //사용하는 클래스에서 Load한 비트맵을 올린다.

CPoint point(0, 0);

if(lpDrawItemStruct->itemState & ODS_SELECTED)
{
   mydc->BitBlt(0, 0, m_ButtonSize.cx, m_ButtonSize.cy, pMemDC, m_ButtonSize.cx, 0, SRCCOPY);
}
else
{

   if(m_bHover)
   {
      mydc->BitBlt(0, 0, m_ButtonSize.cx, m_ButtonSize.cy, pMemDC, m_ButtonSize.cx * 2, 0, SRCCOPY);
   }
   else
   {
      mydc->BitBlt(0, 0, m_ButtonSize.cx, m_Button.cy, pMemDC, 0, 0, SRCCOPY);
   }
}

pMemDC->SelectObject(pOldBitmap);
delete pMemDC;


위와 같이 소스를 작성한다.

m_bHover를 생성자에서 FALSE로 초기화 한다.

mybitmap과 m_ButtonSize는 LoadBitmap(…) 에서 초기화 한다.

BOOL CHoverButton::LoadBitmap(UINT bitmapid) 의 멤버 함수를 선언한다. 호출하는 클래스에서 사용하고자 하는 클래스의 아이디값을 넘겨주면서 호출한다.

mybitmap.Attach(::LoadImage(::AfxGetInstanceHandle(), MAKEINTRESOURCE(bitmapid), IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS));
BITMAP bitmapbits;
mybitmap.GetBitmap(&bitmapbits);
m_ButtonSize.cy = bitmapbits.bmHeight;
//비트맵이 3가지 상태의 그림으로 되어 있으므로
m_ButtonSize.cx = bitmapbits.bmWidth/3;
SetWindowPos(NULL, 0, 0, m_ButtonSize.cx, m_ButtonSize.cy,
SWP_NOMOVE | SWP_NOOWNERZORDER);
return TRUE;


위와 같이 작성한다.

PretranslateMessage를 Overriding 한다.

InitToolTip();
m_ToolTip.RelayEvent(pMsg);
return CButton::PreTranslateMessage(pMsg);


툴팁을 초기화한다.

InitToolTip() 멤버함수를 생성한다.

if(m_ToolTip.m_hWnd == NULL)
{
   //ToolTip 컨트롤 생성
   m_ToolTip.Create(this);
   m_ToolTip.Activate(FALSE);
}

생성된 툴팁이 없을경우 툴팁을 생성한다.

클래스 위자드를 이용하여 WM_MOUSEMOVE 이벤트핸들러 함수를 생성한다.

if(!m_bTracking)
{
   TRACKMOUSEEVENT tme;
   tme.cbSize = sizeof(tme);
   tme.hwndTrack = m_hWnd;
   tme.dwFlags = TME_LEAVE | TME_HOVER;
   tme.dwHoverTime = 1;
   m_bTracking = _TrackMouseEvent(&tme);
}
CButton::OnMouseMove(nFlags, point);


마우스의 두가지 이벤트를 더 추가한다. 이 부분은 클래스 위자드를 사용하지 않고 직접 코드를 추가한다.

우선 헤더파일에 추가한다.

//{{AFX_MSG(CHoverButton)
afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
//아래의 두가지를 더 추가한다.
afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam);
afx_msg void OnMouseHover(WPARAM wparam, LPARAM lparam);
//}}AFX_MSG


이제는 cpp에 추가를 한다.

BEGIN_MESSAGE_MAP(CHoverButton, CButton)
//{{AFX_MSG_MAP(CHoverButton)
ON_WM_DRAWITEM()
ON_WM_MOUSEMOVE()
//아래 두개의 메세지 핸들러함수를 추가한다.
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
.
.
.

void CHoverButton::OnMouseHover(WPARAM wparam, LPARAM lparam)
{
   m_bHover = TRUE;
   Invalidate();
}

LRESULT CHoverButton::OnMouseLeave(WPARAM wparam, LPARAM lparam)
{
   m_bTracking = FALSE;
   m_bHover = FALSE;
   Invalidate();
   return 0;
}


툴팁에 나타낼 내용을 지정할 멤버함수인 SetToolTipText(…) 를 Overloading 하여 두가지로 생성한다.

void CHoverButton::SetToolTipText(int nId, BOOL bActivate)
{
   CString sText;

   //리소스의 스트링을 로드한다.
   sText.LoadString(nId);
   //만약 스트링 리소스가 비어 있다면
   if(sText.IsEmpty == FALSE)
      SetToolTipText(&sText, bActivate);
}

void CHoverButton::SetToolTipText(CString *spText, BOOL bActivate)
{
   //null 포인터는 접근 할수 없다.
   if(spText == NULL)
      return;

   InitToolTip(); //툴팁을 초기화 한다.

   if(m_ToolTip.GetToolCount() == 0)
   {
       CRect rectBtn;
       GetClientRect(rectBtn);
       m_ToolTip.AddTool(this, (LPCTSTR)*spText, rectBtn, 1);
   }

   m_ToolTip.UpdateTipText((LPCTSTR)*spText, this, 1);
   m_ToolTip.Activate(bActivate);

}


툴팁의 활성화를 조정하는 ActivateTooltip(…)을 생성한다.

//툴팁이 생성된게 아무것도 없으면…
if(m_ToolTip.GetToolCount() == 0)
   return;

//툴팁을 활성화 한다.
m_ToolTip.Activate(bActivate);


와 같이 코드를 작성한다.

사용할때는 사용하고자 하는 클래스의 헤더파일에서
#include “HoverButton.h”
를 해준다.


by Redef( http://www.redef.pe.kr )

Posted by redef
TAG Control, MFC

댓글을 달아 주세요

  1. 손님

    안녕하세요.
    CHoverButton을 다운받아서 해봤는데 잘동작은 하는데요.
    작업관리자로 열어서 보기-열선택-GDI개체수를 체크해놓고 보면 지속적으로 증가합니다.
    결국 10000개를 넘어가면서 프로그램은 죽고, 비주얼 스튜디오에서 CHoverButton의 DrawItem()에 있는
    delete pMemDC; 를 가르키고 있습니다. CHoverButton의 버그인가요?
    코드상으로는 잘 이해가 가질 않아서요. 문제가 없는것 같은데...알려주실 수 있나요?

    2009/03/23 18:03 [ ADDR : EDIT/ DEL : REPLY ]
  2. 손님

    아 오랫만에 다시 왔는데 답글을 주셨네요.
    해당 문제점은 CHoverButton 클래스가 아닌 제가 추가한 다른 부분에서 있었구 해결했습니다.
    VS의 디버거를 너무 믿었네요. 브러시를 생성하고 DeleteObject()를 안하는 실수를 저질렀는데
    애매하게도 VS는 CHoverButton을 가르키고 있더라구요.
    늦게 확인했지만 답글 감사합니다^^

    2009/04/02 01:53 [ ADDR : EDIT/ DEL : REPLY ]
    • 해결을 하셨다니 다행이네요...^^
      오늘도 즐거운 하루 보내세요...

      2009/04/02 09:20 [ ADDR : EDIT/ DEL ]