블로그 이미지
인생의무한루프
인생에 무한루프.....

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

Tag

Recent Post

Archive

Recent Comment

Recent Trackback

2008. 12. 16. 23:10 Appication/VC++_Control

버튼과 그룹 ( MFC Check & Radio 예제 )

첵크와 라디오는 상당히 많이 사용되지만 그 직관적인 인터페이스 만큼 사용도 단순하다.
지금까지 사용해오면서도 특별하게 다뤄본 기억이 없을만큼... 흠..

먼가 응용할만한 자료가 없을까 검색 하다보니, 코드프로젝트에 첵크그룹박스라는 자료가 있었다.
이를 응용하여 간단한 참고자료를 만들어 보았다.

\
위 화면은 별로 볼건 없지만 다음과 같은 기능을 제공한다.
1. 첵크박스를 선택하면 해당 그루박스 내부의 컨트롤들이 자동으로 Enable/Disable토글된다.
2. 첵크박스 그룹은 해당 첵크박스의 동작에 영향을 받는다.
3. 라디오버튼은 여러 그룹중에 선택되어진 하나만 활성화 되고, 나머지는 자동으로 Disable된다.
    즉, 라디오의 특성처럼 하나의 그룹만 선택가능하다.


그림 처럼 첵크는 여러그룹이 선택가능하지만 라디오는 오직 한 그룹만 선택가능하다.

그럼 핵심 함수부를 살펴보자.
이 함수는 해당 버튼(첵크 or 라디오)과 그를 둘러싼 그룹박스 아이디, 그리고 부모 윈도우를
인자로 가지는 함수이다.
기능은 해당 버튼의 상태에 따라 그룹박스 내부 컨트롤을 Enable 혹은 Disable 시킨다.

void CheckGroup(INT CheckID, INT GroupID, CWnd* pWndParent)
{
    // 일단 버튼의 첵크 상태를 읽어온다.
    // 이게 첵크던 라디오던 상관없다. 다 CButton을 상속한 컨트롤이기 때문이다.
    BOOL bCheck = pWndParent->IsDlgButtonChecked(CheckID);
   
    // 영역의 사각정보를 저장할 임시 변수들
    CRect rcGroup, rcChild;
   
    // 그룹박스의 영역 정보를 읽어온다.
    pWndParent->GetDlgItem(GroupID)->GetWindowRect(rcGroup);
   
    // 현재 다이알로그의 차일드 윈도우중 첫번째 것을 가져온다.
    CWnd* pWnd = pWndParent->GetWindow(GW_CHILD);
    while (pWnd)
    {
        // 해당 그룹과, 버튼을 제외한 차일드 윈도우.
        if(pWnd->GetDlgCtrlID() != CheckID && pWnd->GetDlgCtrlID() != GroupID)
        {
            // 차일드 윈도우의 영역 정보를 읽어온다.
            pWnd->GetWindowRect(rcChild);
   
            // 만약 차일드 윈도우가 그룹박스 내부에 존재하면, bCheck 상태에 따라
            // 인에이블 정보를 토글한다.

            if (rcChild.IntersectRect(rcGroup, rcChild))
                pWnd->EnableWindow(bCheck);
        }
        pWnd = pWnd->GetWindow(GW_HWNDNEXT);
    }
}

그리고, 아래 4개의 멤버 함수는 각각의 첵크 박스와 라디오 버튼을 눌렀을 때
인자를 어떻게 전달했는지를 보여준다.
void CSssDlg::OnCheckUser()
{
    CheckGroup(IDC_CHECK1, IDC_STATIC1, this);
}

void CSssDlg::OnCheckSub()
{
    CheckGroup(IDC_CHECK2, IDC_STATIC5, this);
}

void CSssDlg::OnRadioUser()
{
    CheckGroup(IDC_RADIO1, IDC_STATIC9, this);
    CheckGroup(IDC_RADIO2, IDC_STATIC13, this);
}

void CSssDlg::OnRadioSub()
{
    CheckGroup(IDC_RADIO1, IDC_STATIC9, this);
    CheckGroup(IDC_RADIO2, IDC_STATIC13, this);
}

화면 구성에 비하여 상당히 깔끔하고, 단촐한 코드로 구성되어 사용하기도 쉬울것이다.

처음에는 위에서 처럼 처리하는것이 아니라, Tab Order 와 Group 속성을 이용하면
해당 그룹을 묶어서 처리할 수 있지 않을까 하는 생각을 가져보기도 했었는데..
아쉽게도 Group 속성에 대한 이해가 모자라 일반적인 꽁수로 해결을 보았다.

첵크와 라디오를 어떻게 응용해 볼 수 있을까?




Posted by 까막백(홈페이지 이동)
posted by 인생의무한루프
2008. 12. 16. 11:45 Appication/VC++_Control

스태틱 컨트롤 시작하기 ( MFC Static 예제 )

의미.
화면상에 간단하게 문자열을 보여주는 것으로 부터... 비트맵 및 아이콘을 폼에 보여주는 것등의 기초 기능을 담당하고 있다.

기본기능.
1. 필요한 곳에 간단한 문자열등을 보여준다. (에디팅은 않된다.)
2. 비트맵과 아이콘과 같은 것들을 간단한 작업으로 화면에 보여줄 수 있다.
3. 간단한 도형의 출력을 도와준다.
4. 메타 파일을 보여줄 수 있다.

설명이 좀 이상하네??? 스태틱인데 왠 이미지???
리소스 창에서는 Text 컨트롤(스태틱 컨트롤)과 Picture 컨트롤로 분리되어 있지만 모두 CStatic으로 구현된
것들이다. 이를 ActiveX 로 만들면서 대표적인 기능으로 분리해 놓았을 뿐 모두 CStatic로 구현 가능하다.

리소스 편집창에서 오른쪽의 빨강 똥그라미가 Text 컨트롤, 파랑 똥그라미가 Picture 컨트롤이다. 모두 CStatic에서 제공하는 기능이지만, 문자열과 그림이라는 기준으로 분리되어 다루기 쉽게 해놓았다.


왼쪽의 [난 Text 컨트롤] 이라고 표현되어 있는 모든 것이 Text 컨트롤에 각각의 속성을 부여하여 여러가지 형태로 표현된 것이고,오른쪽에 보여지는 것이 Picture 컨트롤을 이용하여 속성을 부여해본 것들이다.

앞으로 하나의 CStatic 컨트롤을  Text와 Picture 두가지 관점에서 논할것이여, 가끔 짬뽕이 될 수도 있다 --;

컨트롤이 제공하는 속성을 살펴보자. 우선 Text 관점에서 먼저 본다.
프로퍼티의 General 탭의 설명은 생략한다. 중복되는 넘이므로 [에디트 컨트롤 기초편을 참조한다.]

1. Align Test - 문자열을 수평 왼쪽, 가운데, 오른쪽으로 정렬한다.
2. Center Verically - 문자열을 수직 가운데로 정렬한다.
3. No prefix - 윈도우 컴포넌트의 문자열중에 '&' 는 다음 문자에 _ 선을 그어준다. 이 기능을 제거한다.

그림을 보면 위에꺼는 디폴트, 아래껏은 No Prefix 옵션을 준 것이다.
4. No warp - 문자열의 길이가 컨트롤 너비보다 크면 자동으로 줄바꿈하여 다음줄에 그려진다. 이 기능을 끈다.

그림을 보면 아래쪽이 No Warp 옵션을 사용한 것이다.
5. simple  - 말 그대로 모든 속성을 포기하고, 기초 속성만을 사용함을 표시한다.
6. Notify - 내부 노티파이 이벤트를 부모에게 알려준다.
7. Sunken - 테두리 속성중에 가라 앉은 듯한 효과를 준다. 첫번째 그림중 왼쪽 5번째.
8. Border - 테두리 속성중에 검은색 사각 테두리. 첫번째 그림중 왼쪽 4번째.


1. Client edge -  확장 속성인것만 빼고, 위의 7번과 같다.
2. Static edge - 확장 속성인것만 빼고, 위의 8번과 같다.
3. Modal frame - 다이알로그 처럼 툭 튀어나온것 처럼 보여준다.
4. Transparent - 배경을 그리지 않는다.
5. Accept files - 파일을 드래그 하여 떨구면 이벤트를 발생시킨다.
6. Right aligned text - 문자열을 오른쪽 정렬한다.
7. Right-to-left reading order - 딴 나라를 위하여 오른쪽부터 왼쪽으로 문자열을 오더링한다.

컨트롤이 제공하는 속성을 살펴보자. Picture 관점에서 본다.

1. Type - 컨트롤의 타입을 설정한다.
    Frame - 그냥 비어있는 사각 틀로써 형태를 제공한다.
    Rectangle - 채워진 사각 틀로써 행테를 제공한다.
    Icon - 아이콘을 그려준다.
    Bitmap - 비트맵을 그려준다.
    Enhanced Metafile - 메타 이미지 파일을 그려준다.
2. Image - 위에서 Icon, Bitmap, Enhances Metafile 일경우만 활성화 되고, 현재 리소스 중에서 아이디를 선택할 수 있도록 해준다.
3. Color - 위에서 frame과 Rectangle 속성일 경우 색상을 지정할 수 있도록 해준다.

2번째(Styles)와 3번째(Extended Styles) 속성은 Text 컨트롤과 동일하다.

참고.
Text와 Picture 컨트롤은 다른 컨트롤과 달리 처음에 생성하면 모든 컨트롤의 아이디가 IDC_STATIC 이다. 다른 컨트롤은 뒤에 1, 2 처럼 숫자가 붙는데 좀 특이하다.

이유는 보통 리소스 편집창에서 주는 속성 말고는 코딩으로 먼가를 건드릴 일이 없기 때문에 특별하게 취급된다. 그러므로 코딩에서 저걸 건드릴려면 IDC_STATIC_MYSTATIC과 같이 변경을 가해줘야한다.

IDC_STATIC는 시스템 아이디이기 때문에  GetDlgItem(IDC_STATIC)와 같이 사용할 수 없다.


Posted by 까막백(홈페이지 이동)
posted by 인생의무한루프
2008. 12. 16. 11:44 Appication/VC++_Control

글자색과 배경색 바꾸기 ( MFC Static 예제 )

에디트 컨트롤 편에서와 마찬가지고 WM_CTLCOLOR 라는 이벤트를 이용하여 글자색과 배경색을 변경할 수 있다.


클래스 위저드에서 WM_CTLCOLOR 을 선택한 후에 Add Function 버튼을 눌러 이벤트 핸들러를 추가한다.

저걸 추가하고 나면 화면상에 다음과 같은 코드가 자동으로 추가됩니다.

HBRUSH CSssDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
   
    // TODO: Return a different brush if the default is not desired
    return hbr;
}

1. CDC* pDC - MFC에서 제공하는 디바이스 컨텍스트
2. CWnd* pWnd - 대상이 되는 다이알로그에 올려진 컨트롤 윈도우
3. UINT nCtlColor -  대상이 되는 컨트롤의 구분 타입.

3번의 대상이 되는 컨트롤의 구분 타입은 다음과 같습니다.
이는 winuser.h에 선언되어 있구요.
#define CTLCOLOR_MSGBOX         0
#define CTLCOLOR_EDIT                1
#define CTLCOLOR_LISTBOX          2
#define CTLCOLOR_BTN                3
#define CTLCOLOR_DLG                4
#define CTLCOLOR_SCROLLBAR    5
#define CTLCOLOR_STATIC           6

나는 Text 컨트롤을 대상으로 작업을 하므로 CTLCOLOR_STATIC 를 사용할 것입니다.
그럼 다음과 같은 코드를 추가해 봅니다.

HBRUSH CSssDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
   
    switch(nCtlColor)
    {
    case CTLCOLOR_STATIC:
        {
            pDC->SetTextColor(RGB(255, 0, 0));
            pDC->SetBkColor(RGB(0, 255, 0));
        }
    }
    // TODO: Return a different brush if the default is not desired
    return hbr;
   
}
위와 같이 설정하면 모든 스태틱 컨트롤에 영향을 준다. 실행 결과 화면은 다음과 같다.


필요한 컨트롤만 색상을 변경하려면 다음과 같은 추가 작업이 필요하다.
좌측 상단의 첫번째 컨트롤의 속성창을 열어서 아이디를  IDC_STATIC_1 이라고 변경한다.
그리고 다음과 같이 코드를 변경한다.
HBRUSH CSssDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
   
    switch(nCtlColor)
    {
    case CTLCOLOR_STATIC:
        {
            if(pWnd->GetDlgCtrlID() == IDC_STATIC_1)
            {
                pDC->SetTextColor(RGB(255, 0, 0));
                pDC->SetBkColor(RGB(0, 255, 0));
            }
        }
    }
    // TODO: Return a different brush if the default is not desired
    return hbr;
}

실행 결과 화면은 다음과 같다.






Posted by 까막백(홈페이지 이동)
posted by 인생의무한루프
2008. 12. 16. 11:41 Appication/VC++_Control

배경을 투명하게 만들어보자. ( MFC Static 예제 )

스태틱 컨트롤중에 Text 기능을 이용하여 배경을 투명하게 만드는 것은 에디트 컨트롤에 비하여
훨씬 쉽다.


위의 샘플이 컨트롤의 배경을 투명하게 만든것인데..

우선 글자가 써진 컨트롤의 아이디를  IDC_STATIC_1 이라고 변경한 후..
코드를 다음과 같이 변경하면 끝이다.

HBRUSH CSssDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
   
    switch(nCtlColor)
    {
    case CTLCOLOR_STATIC:
        {
            if(pWnd->GetDlgCtrlID() == IDC_STATIC_1)
            {
                pDC->SetTextColor(RGB(255, 0, 0));
                pDC->SetBkMode(TRANSPARENT);
                return (HBRUSH)GetStockObject(NULL_BRUSH);;
            }
        }
    }
    // TODO: Return a different brush if the default is not desired
    return hbr;
   
}




Posted by 까막백(홈페이지 이동)
posted by 인생의무한루프
2008. 12. 16. 11:39 Appication/VC++_Control

하이퍼 링크 컨트롤을 만들어보자. ( MFC Static 예제 )

본 예제에서도 이전처럼 새로운 클래스를 추가하거나 하는 작업들은 하지 않고, 모든 작업을 다이알로그에서 처리 가능하도록 하고자 한다.


위의 그림이 샘플 예제이며,
내부에 사용된 기능은 다음과 같다.

1. 폰트를 만들어 언더라인을 긋는다.
2. 하이퍼 링크 컨트롤 위에 마우스가 가면 손가락 모양으로 바뀐다.
3. 클릭하면 링크된 웹사이트가 뜬다.
4. 클릭이 끝나면 한번 클릭된 것으로 인식하고, 글자 색상을 바꾼다.

구현되는 기능은 일반적인 하이퍼 링크 컨트롤의 기능을 100% 지원한다.
단, 툴팁도 추가할 수 있지만.. 현재 강좌 범위를 넘어가므로 나중을 기약하며 생략한다.

준비해야할 것과 추가해야할 코딩..
1. 먼저 폼에 스태틱 컨트롤 중에 Text 컨트롤을 하나 올리고, IDC_STATIC_1 로 설정한다.
2. 컨트롤의 속성중에 Styles 탭에서 Notify를 첵크한다. (중요하다.)
3. 다이알로그의 헤더 파일에 CFont m_font; 멤버를 하나 추가한다.
4. 다이알로그의 헤처 파일에 BOOL m_m_clicked; 멤버를 추가한다.

BOOL CSssDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
   
    // 밑줄이 쫘악 그어진 폰트를 하나 만든다.
    LOGFONT log;
    GetFont()->GetLogFont(&log);
    log.lfUnderline = TRUE;
    m_font.CreateFontIndirect(&log);

    // 만들어진 폰트를 스태틱 컨트롤에 적용한다.
    GetDlgItem(IDC_STATIC_1)->SetFont(&m_font);

    return TRUE;  // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}

HBRUSH CSssDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
   
    switch(nCtlColor)
    {
    case CTLCOLOR_STATIC:
        {
            if(pWnd->GetDlgCtrlID() == IDC_STATIC_1)
            {
                // 클릭 한적이 없으면 파랑색으로...
                if(m_clicked == FALSE)
                    pDC->SetTextColor(RGB(0, 0, 255));
                // 한번 클릭하고 나면 보라색 비끄무리하게 바꾼다.
                else
                    pDC->SetTextColor(RGB(255, 100, 100));
               
                // 기왕 하는거 배경은 투명한 형태로 계속 유지하자.. --;
                pDC->SetBkMode(TRANSPARENT);
                return (HBRUSH)GetStockObject(NULL_BRUSH);;
            }
        }
    }
    // TODO: Return a different brush if the default is not desired
    return hbr; 
}

여기 까지는 기존에 강좌에 나온것과 별반 다른작업이 없다. 다음 2가지 과정을 거치고 나면
하이퍼링크 컨트롤로 변신한다. ^^;

클래스 위저드를 열어 WM_SETCURSOR 이벤트를 추가한다.

그러고 나면 다음과 같은 코드가 추가된다.

BOOL CSssDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
   
return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
간단하게 WM_SETCURSOR 이벤트에 대하여 설명해 보면, 다이알로그 위에서 마우스가 움직이는 동안 필요한 커서를 제어할 수 있도록 기능을 제공하는 것이다.
일단 코드를 다음과 같이 변경한다.
BOOL CSssDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    CPoint pt;  
// 마우스 커서 위치를 저장할 객체
    CRect rc;   // 스태틱 컨트롤의 위치를 저장할 객체.

    // 마우스 커서의 위치를 찾아온다.
    GetCursorPos(&pt);
    // 스태틱 컨트롤의 위치를 찾아온다.
    GetDlgItem(IDC_STATIC_1)->GetWindowRect(rc);

    // 만약 마우스가 스태틱 컨트롤 위에 와있으면..
    if(rc.PtInRect(pt))
    {
        // IDC_HAND라는 스탠다드 커서를 읽어와서 커서를 변경시킨다.
        SetCursor(AfxGetApp()->LoadStandardCursor(MAKEINTRESOURCE(IDC_HAND)));

        // 꼭 리턴을 해주어야하는데, 이로써 화면에 바뀐커서가 적용된다.
        // 리턴 해주지 않으면 아무리 커서를 바꾸어도 전혀 변경이 없다.
        // 아래 return CDialog::OnSetCursor(pWnd, nHitTest, message); 에서 커서를
        // 원상 복구 시켜버리기 때문이다.
        return TRUE;
    }
 
 return CDialog::OnSetCursor(pWnd, nHitTest, message);
}

이제 마지막 하나의 기능이 남아있다.
스태틱 컨트롤을 마우스로 클릭하고 나면, 그걸 인식하여 웹페이지를 열어 주어야한다.
아까전에 속성창에서 Notify를 첵크하고 하였던 것이 기억날것이다. 만약 이 속성을 주지 않는다면
아무리 마우스를 컨트롤에 놓고 꼭, 꼭 찍어도 아래의 함수는 동작하지 않는다.

클래스 위저드를 열어서 IDC_STATIC_1의 BN_CLICKED 이벤트를 추가한다.

그러면 해당 이벤트의 핸들러가 추가된다.

그리고 코드를 다음과 같이 입력하면 된다.
void CSssDlg::OnStatic1()
{
    m_clicked = TRUE;
    GetDlgItem(IDC_STATIC_1)->Invalidate();
    ShellExecute(m_hWnd, "open", "http://crowback.tistory.com", NULL, NULL, SW_SHOW);
}

여기서 유용한 함수중에 하나가 ShellExecute라는 함수인데.. 외부 프로그램을 실행시킬때 주로
사용하는 기능이다.

설명은 길지만 전체 추가한 라인수는 대략 30라인 정도밖에는 되지않는 아주 간단한 코드이다.
이렇게 하여 하이퍼링크 하나를 넣기 위하여 새로운 클래스를 추가하는 번거로움을 막을 수 있다.




Posted by 까막백(홈페이지 이동)
posted by 인생의무한루프