본문 바로가기

프로그램언어/C++

대화상자3

모달리스 대화상자

모달리스는 대화상자는 부모 윈도우를 선택할 수 있으며, 그 대표적인 예로는 찾기대화상자 이다.

 

CreateDialog() 함수 :  모달리스 대화상자 생성

HWND CreateDialog(
    HINSTANCE      hInstance,        // 대화상자 인스턴스 핸들
    LPCTSTR           lpTemplate,     //  대화상자 ID
    HWND             hWndParent,    //  이 대화상자를 소유하는 오너 윈도우의 핸들이다
    DLGPROC         lpDialogFunc    //  대화상자로 전달되는 메시지를 처리하는 메시지 처리 함수의 포인터를 지정
);

 

BOOL ShowWindow() 함수 : 모달리스 대화상자를 보이거나 숨기기

BOOL ShowWindow(
    HWND        hWnd,            // 대상 윈도우 핸들
    int              nCmdShow     // 지정하고자 하는 보이기 상태이며 다음 값중 하나를 지정
);

 

설명
SW_FORCEMINIMIZE

2000 이후에만 쓸 수 있는 플레그이다. 윈도우를 소유한 스레드가 블록된 상태에서도 윈도우를 최소화시킨다.

SW_HIDE

윈도우를 숨긴다.

SW_MAXIMIZE

윈도우를 최대화시킨다.

SW_MINIMIZE

윈도우를 최소화시키며 다음 Z순서를 가지는 윈도우가 활성화된다.

SW_RESTORE 최대, 최소화된 윈도우를 이전 위치로 복구한다.
SW_SHOW

윈도우를 활성화하며 보인다.

SW_SHOWDEFAULT

STARTUPINFO 구조체가 지정하는 보이기 상태로 만든다.

SW_SHOWMAXIMIZED

윈도우를 최대화된 상태로 활성화한다.

SW_SHOWMINIMIZED

윈도우를 최소화한 상태로 활성화한다.

SW_SHOWMINNOACTIVE

윈도우를 최소화 상태로 보이며 활성화 상태는 변경되지 않는다.

SW_SHOWNA

윈도우를 헌재 상태로 보이며 활성화 상태는 변경되지 않는다.

SW_SHOWNOACTIVATE

최근 크기와 위치에 윈도우를 보이며 활성화 상태는 변경되지 않는다.

SW_SHOWNORMAL

윈도우를 보이며 활성화한다. 만약 윈도우가 최소화되어 있거나 최대화되어 있다면 윈도우를 원래 크기대로 복구한다. 윈도우를 처음 화면에 보일 때는 이 플래그를 사용해야 한다.

 

DestroyWindow() 함수 : 모달리스 대화상자 종료

BOOL DestroyWindow( HWND hWnd );

 

IsWindow() 함수 : 매개변수로 주어진 윈도우 핸들 값이 유효한지를 검사하는 함수

BOOL IsWindow(HWND hWnd);

 

오른쪽버튼을 클릭하여 모달리스 대화상자를 띄어보자.

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
    HWND hDlg = NULL;
    switch (iMsg)
    {
    case WM_CREATE:
         break;
    case WM_RBUTTONDOWN:
        if (!IsWindow(hDlg))     // hDlg 변수가 윈도우 핸들 값이 유효한지 검사
        {  
             hDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DlgProc);
             ShowWindow(hDlg, SW_SHOW);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }  
    return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

BOOL CALLBACK DlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

    static HWND hList;

    static int selection;

    TCHAR name[20];

 

    switch (iMsg)

    {

    case WM_INITDIALOG:

        hList = GetDlgItem(hDlg, IDC_LIST_NAME);

        return 1;

    case WM_COMMAND:

         switch (LOWORD(wParam))

        {

        case IDC_BUTTON_INSERT:

            GetDlgItemText(hDlg, IDC_EDIT_NAME, name, 20);

            if (_tcscmp(name, _T("")))

                SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)name);

            return 0;

        case IDC_BUTTON_DELETE:

            SendMessage(hList, LB_DELETESTRING, selection, 0);

            return 0;

        case IDC_LIST_NAME:

            if (HIWORD(wParam) == LBN_SELCHANGE)

                selection = (int)SendMessage(hList, LB_GETCURSEL, 0, 0);

            break;

        case IDCANCEL:

            EndDialog(hDlg, 0);

            return 0;

        }

        break;

    }

    return 0;

}

실행 결과]

 

공용 컨트롤

공용 컨트롤을 사용하기 위해서는 공용 컨트롤의 헤더와 라이브러리가 필요한다. 헤더는 commctrl.h로 코드상의 해더 선언부에 #include <commctrl.h>를 선언해야 한다.

라이브러리의 포함은 프로젝트의 [속성] - [구성 속성] - [링커] - [입력]에 들어가면 오른쪽 패널의 [추가 종속성]에 comctl32.lib를 입력하고 [확인] 버튼을 누른다.

 

리스트 컨트롤

칼럼 만들기 : LVCOLUMN 구조체

typedef struct _LVCOLUMN {
    UIN             mask;                // 마스크
    int               fmt;                  // 칼럼 정렬 플래그
    int               cx;                   // 칼럼의 가로 크기
    LPTSTR         pszText;            // 칼럼 텍스트
    int               cchTextMax;      // 칼럼 텍스트의 최대 길이
    int               iSubItem;          // 칼럼 번호
} LVCOLUMN, *LPLVCOLUMN;

mask 값은 fmt나 cx, pszText, iSubItem 등의 정보를 참조할 것인지 결정하는 플래그이다.

대표적으로 다음 네 가지가 많이 사용된다.

내용
LVCF_FMT fmt 값을 유효화 한다.
LVCF_SUBITEM iSubItem 값을 유효화 한다.
LVCF_TEXT pszText 값을 유효화 한다.
LVCF_WIDTH cx 값을 유효화 한다.

 

fmt의 경우는 칼럼의 텍스를 어떻게 정렬 시키느냐의 플래그로써 대표적으로 다음 세가지가 주로 사용된다.

내용
LVCFMT_LEFT 칼럼 텍스트를 왼쪽 정렬
LVCFMT_RIGHT 칼럼 텍스트를 오른쪽 정렬
LVCFMT_CENTER 칼럼 텍스트를 가운데 정렬

 

칼럼 만들기 예

LVCOLUMN lvCol;           // 구조체 타입의 변수 선언
memset(&lvCol, 0, sizeof(LVCOLUMN));         // lvCol의 모든 필드를 0으로 초기화

lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
// mask의 fmt, cx, pszText, iSubItem 필드에 값을 저장하기 위해 플래그 설정

lvCol.fmt = LVCFMT_LEFT;             // 칼럼을 왼쪽정렬

lvCol.cx = 90;                             // 칼럼의 폭을 90픽셀로 설정
lvCol.pszText = _T("칼럼 이름");      // 칼럼의 이름을 "칼럼 이름"으로 지정

lvCol.iSubItem = i;                      // 칼럼의 인덱스 번호를 지정

SendMessage(hList, LVM_INSERTCOLUMN, (WPARAM)i, (LPARAM)&lvCol);
// 리스트 컨트롤에 LVM_INSERTCOLUMN 메시지와 함께 lvCol의 내용을 보내면 칼럼이 추가된다.

 

memset()함수 : 어떤 메모리의 시작점부터 연속된 범위를 툭정 값으로 모두 지정하고 싶을 때 사용하는 함수

void * memset ( 
    void*            ptr,      // 메모리의 시작 포인터(시작 주소)
    int               value,   // 메모리에 채우고자하는 값 (unsigned char로 변환되어 저장)
    size_t            num    // 메모리의 크기
);

 

칼럼이 만들어지면 리스트 컨트롤의 각 항목에 데이터를 입력해야 하는데 데이터를 입력하려면 LVITEM구조체가 필요하다.

칼럼에 항목에 데이터 입력 : LVITEM 구조체

typedef struct _LVITEM {

    UINT mask;           //  마스크용 플래그

    int iItem;              //항목의 인덱스번호 지정
   
int iSubItem;         // 행의 몇 번째 서브 아이템 인덱스 번호 지정
   
UINT state;           // 항목의 현재 상태값 지정
   
UINT stateMask;    // 상태값의 마스크용 플래그 지정
   
LPTSTR pszText;     // 항목에 출력할 문자열
   
int cchTextMax;      //텍스트의 길이 
   
int iImage;            //이미지의 인덱스 번호 지정
   
LPARAM lParam;    // 저장할 파라미터

} LVITEM, *LPLVITEM;

mask 플래그

내용
LVIF_STATE state 필드
LVIF_TEXT pszText 필드
LVIF_IMAGE iImage 필드
LVIF_PARAM lParam 필드

 

리스트 컨트롤에 새로운 항목(행)을 추가히기

int ListView_InsertItem (
    HWND     hWnd,                    // 목록보기 컨트롤에 대한 핸들
    const       LPLVITEM pitem       // 목록보기 항목의 속성을 지정 하는 LVITEM 구조에 대한 포인터로 iItem에 새로운 항목이 삽입
);

 

리스트 컨트롤의 특정 항목에 텍스트 출력하기

VOID ListView_SetItemText (
    HWND      hWnd,         // 목록보기 컨트롤에 대한 핸들
    int            i,                // 목록보기 항목의 0부터 시작하는 인덱스
    int            iSubItem,     // 하위 항목은 1부터 시작하는 인덱스로 항목 레이블을 설정하려면 iSubItem 을 0으로 설정
    LPCTSTR    pszText        // 새 텍스트를 포함하는 null로 끝나는 문자열에 대한 포인터
);

 

WM_NOTIFY 메시지는 일반적으로 자식윈도우(컨트롤등)가 자신에게 일어난 여러가지 상황을 부모윈도우(대화상자)에게 전달할때 사용하는 메시지이다.

WM_NOTIFY 메시지의 정보는 lParam에 저장되고 lParam의 정보를 보려면 NMHDR타입에 대한 포인터형인 LPNMHDR 타입으로 형 변환하거나 NMLISTVIEW 구조체의 포인터형인 LPNMLISTVIEW 타입으로 형 변환을 해야 한다.

LPNMHDR로 형 변환을 한 경우에는 변화가 일어난 컨트롤의 윈도우 핸들 값과 변화 내용을 알 수 있다.

LPNMLISTVIEW로 형 변환을 하면 리스트 컨트롤의 어떤 항목에 변화가 있는지 알 수 있다.

 

LPNMHDR 구조체

typedef struct tagNMHDR {
    HWND      hwndFrom;         // 변화가 발생해 메시지를 보내는 컨트롤의 원도우 핸들 값을 저장
    UINT_PTR  idFrom;              // 메시지를 보낸 컨트롤의 ID
    UINT        code;                 // 컨트롤에 발생한 변화 내용을 담고 있다.
} NMHDR;

리스트 컨트롤에서 발생하는 코드

LVN_ITEMCHANGING 리스트 컨트롤의 항목에 변화 발생
LVN_KEYDOWN 리스트 컨트롤에서 키보드를 누름
LVN_INSERTITEM 리스트 컨트롤에 새 항목이 추가됨
LVN_DELETEITEM 리스트 컨트롤의 항목 하나가 삭제됨
LVN_COLUMNCLICK 리스트 컨트롤의 특정 칼럼이 선택됨

 

LPNMLISTVIEW 구조체

typedef struct LPNMLISTVIEW {
    NMHDR        hdr;               // WM_NOTIFY와 함께 변화가 일어난 컨트롤의 원도우 핸들 값과 변화내용의 정보
    int               iItem;             // 리스트 컨트롤의 몇 번째 행의 변화가 있었는지를 알려주는 인덱스 값
    int               iSubItem;        // 리스트 컨트롤의 몇 번째 열에 변화가 있었는지를 알려주는 인덱스 값
    UINT            uNewState;     // 변경된 상태
    UINT            uOldState;      // 변경되기 전의 상태
    UINT            uChanged;      // 변경된 항목을 가르키는 비트 마스크 (LVITEM의 MASK와 같다)
    POINT          ptAction;        // 통지 메세지 발생 시점의 마우스 포인터 위치이며 드래그 메세지에서만 사용
    LPARAM       lParam;          // LPARAM값
} NMLISTVIEW, *LPNMLISTVIEW;

 

리스트 컨트롤의 특정 항목에서 텍스트를 얻어오는 함수

ListView_GetItemText() 함수

void ListView_GetItemText (
    HWND      hwnd,            // 리스트 컨트롤 윈도우 핸들
    int            iIem,             // 특정 항목의 위치(행)
    int            iSubItem,       // 특정 항목의 위치(열)
    LPTSTR      pszText,         // 텍스트 저장 버퍼 주소
    int            cchTextMax    // 버퍼 길이
);

 

리스트 컨트롤의 특정 항목을 삭제하는 함수

BOOL ListView_DeleteItem() 함수

BOOL ListView_DeleteItem(
    HWND     hwnd,      // 리스트 컨틀로 윈도우 핸들
    int           iItem      // 특정 항목의 위치(행)
);

 

리스트 컨트롤에 칼럼만들기

#include <windows.h>

#include <TCHAR.H>

#include <commctrl.h>

#include "resource.h"

...

void MakeColumn(HWND hDlg);

...

 

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

    HWND hDlg = NULL;

    switch (iMsg)

    {

    case WM_CREATE:

        break;

    case WM_RBUTTONDOWN:

        if (!IsWindow(hDlg))

        {

            hDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hwnd, DlgProc);

            ShowWindow(hDlg, SW_SHOW);

         }

         break;

    case WM_DESTROY:

        PostQuitMessage(0);

        break;

    }

    return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

 

BOOL CALLBACK DlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

    switch (iMsg)

    {

    case WM_INITDIALOG:

        MakeColumn(hDlg);

        return 1;

    case WM_COMMAND:

        switch (LOWORD(wParam))

        {

        case IDCLOSE:

            DestroyWindow(hDlg);

            hDlg = NULL;

            return 0;

        case IDCANCEL:

            DestroyWindow(hDlg);

            hDlg = NULL;

            return 0;

        }

        break;

    }

    return 0;

}

 

void MakeColumn(HWND hDlg)

{
    //LPCTSTR name[2] = { _T("이름"), _T("전화번호") }; 

    LPCWSTR name[2] = { _T("이름"), _T("전화번호") };

    LVCOLUMN lvCol = { 0, };

    HWND hList;

    int i;

    hList = GetDlgItem(hDlg, IDC_LIST_MEMBER);

    lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;

    lvCol.fmt = LVCFMT_LEFT;

 

    for (i = 0; i < 2; i++)

    {

        lvCol.cx = 90;

        lvCol.iSubItem = i;

        lvCol.pszText = (LPTSTR)name[i];

        SendMessage(hList, LVM_INSERTCOLUMN, (WPARAM)i, (LPARAM)&lvCol);

    }

}

실행 결과]

 

'프로그램언어 > C++' 카테고리의 다른 글

MID 프로그래밍  (0) 2021.01.03
대화상자4  (0) 2020.12.31
대화상자만들기2  (0) 2020.12.28
대화상자만들기  (0) 2020.12.23
ROP모드로 이미지 마스크 설정  (0) 2020.12.22