본문 바로가기
프로그래밍/API

API-대화상자

by 리뷰하는 (게임)프로그래머_리프TV 2010. 4. 24.


대화상자라 함은, 특정 상황에서 윈도우를 하나더 꺼내서 사용하게 만드는 것이다.

크게 2가지로 구분되는데,

모달, 모달리스 이렇게 2가지로 구분된다.

모달의 경우는 창이 띄워지면 메인 윈도우에 접근이 잠시동안 불가능하며,

모달리스의 경우에는 창이 띄워져도 메인 윈도우에 대한 접근이 가능하다는 차이가 있다.

#include <windows.h>
#include "resource.h"

LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass = TEXT("대화상자");
int x;
int y;
TCHAR str[128];

HWND hMDlg;

int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
					 LPSTR lpszCmdParam, int nCmdShow )
{
	HWND hWnd;
	MSG Message;
	WNDCLASS WndClass;
	g_hInst = hInstance;

	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hbrBackground = (HBRUSH)GetStockObject( COLOR_WINDOW+1 );
	WndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
	WndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
	WndClass.hInstance = hInstance;
	WndClass.lpfnWndProc = WndProc;
	WndClass.lpszClassName = lpszClass;
	WndClass.lpszMenuName = MAKEINTRESOURCE( IDR_MENU1 );
	WndClass.style = CS_HREDRAW | CS_VREDRAW;
	RegisterClass( &WndClass );

	hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, (HMENU)NULL, hInstance, NULL );
	ShowWindow( hWnd, nCmdShow );

	while( GetMessage( &Message, NULL, 0, 0 ) )
	{
		if( !IsWindow( hMDlg ) || !IsDialogMessage( hMDlg, &Message ) )
		{
			TranslateMessage( &Message );
			DispatchMessage( &Message );
		}
	}
	return (int)Message.wParam;
}

// 모달용 함수
BOOL CALLBACK InfoDlgProc( HWND hDig, UINT iMessage, WPARAM wParam, LPARAM lParam )
{
	switch( iMessage )
	{
	case WM_INITDIALOG:
		SetDlgItemText( hDig, IDC_EDIT3, str );
		SetDlgItemInt( hDig, IDC_EDIT1, x, FALSE );
		SetDlgItemInt( hDig, IDC_EDIT2, y, FALSE );
		SetDlgItemInt( hDig, IDC_EDIT4, x+y, FALSE );
		return TRUE;
	case WM_COMMAND:
		switch( LOWORD( wParam ) )
		{
		case IDOK:
			GetDlgItemText( hDig, IDC_EDIT3, str, 128 );
			x = GetDlgItemInt( hDig, IDC_EDIT1, NULL, FALSE );
			y = GetDlgItemInt( hDig, IDC_EDIT2, NULL, FALSE );
			EndDialog( hDig, IDOK );
			return TRUE;
		case IDCANCEL:
			EndDialog( hDig, IDCANCEL );
			return TRUE;
		}
		break;
	}
	return FALSE;
}

// 모달리스용 함수
BOOL CALLBACK MlessDlgProc( HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam )
{
	switch( iMessage )
	{
	case WM_INITDIALOG:
		SetDlgItemText( hDlg, IDC_EDIT3, str );
		SetDlgItemInt( hDlg, IDC_EDIT1, x, FALSE );
		SetDlgItemInt( hDlg, IDC_EDIT2, y, FALSE );
		SetDlgItemInt( hDlg, IDC_EDIT4, x+y, FALSE );
		return TRUE;
	case WM_COMMAND:
		switch( LOWORD( wParam ) )
		{
		case IDOK:
			GetDlgItemText( hDlg, IDC_EDIT3, str, 128 );
			x = GetDlgItemInt( hDlg, IDC_EDIT1, NULL, FALSE );
			y = GetDlgItemInt( hDlg, IDC_EDIT2, NULL, FALSE );
			InvalidateRect( hWndMain, NULL, TRUE );
			SetDlgItemInt( hDlg, IDC_EDIT4, x+y, FALSE );
			return TRUE;
		case IDCANCEL:
		case IDCLOSE:
			DestroyWindow( hMDlg );
			EndDialog( hDlg, IDCANCEL );
			hMDlg = NULL;
			return TRUE;
		}
		break;
	}
	return FALSE;
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam )
{
	HDC hdc;
	PAINTSTRUCT ps;

	switch( iMessage )
	{
	case WM_CREATE:
		hWndMain = hWnd;
		x = 100;
		y = 100;
		lstrcpy( str, TEXT("String"));
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint( hWnd, &ps );
		TextOut( hdc, x, y, str, lstrlen(str) );
		EndPaint( hWnd, &ps );
		return 0;
	case WM_COMMAND:
		switch( LOWORD(wParam) )
		{
		case ID_40002:
			// 모달리스
			if( !IsWindow( hMDlg ) )
			{
				hMDlg = CreateDialog( g_hInst, MAKEINTRESOURCE( IDD_DIALOG1 ),
					hWnd, MlessDlgProc );
				ShowWindow( hMDlg, SW_SHOW );
			}
			break;
		case ID_40001:
			// 모달
			if( DialogBox( g_hInst, MAKEINTRESOURCE( IDD_DIALOG1 ),
				hWnd, InfoDlgProc ) == IDOK )
				InvalidateRect( hWnd, NULL, TRUE );
			break;
		}
		return 0;
	}
	return( DefWindowProc( hWnd, iMessage, wParam, lParam));
}​


소스 설명
하나씩 천천히 보도록 하자,

HWND hWndMain;
HWND hMDlg;​

일단 전역으로 메인에 대한 핸들을 보관할 hWndMain과, 모달리스용 핸들 hMDlg를 설정해 주었다.

	while( GetMessage( &Message, NULL, 0, 0 ) )
	{
		if( !IsWindow( hMDlg ) || !IsDialogMessage( hMDlg, &Message ) )
		{
			TranslateMessage( &Message );
			DispatchMessage( &Message );
		}
	}​


그리고 GetMessage를 받는 부분에서 추가적인 if문이 사용 되었는데,
IsWindow는 대상 핸들이 현재 유효한지 파악하여 윈도우가 존재하면 TRUE, 그렇지 않으면 FALSE를 리턴한다,
그리고 IsDialogMessage는 대화상자를 위한 메시지인지 검사한다, 만약 그렇다면 대화상자로 메시지를 보내는 일들을 한다.
즉, 아직 모달리스 대화상자가 유효하지 않거나, 현재 입력된 메시지가 대화상자를 위한것이 아니라면,
일반적인 메시지로 파악하여 TranslateMessage와 DispatchMessage를 보내게 된다, 라는 것이다.

그리고 모달용 함수와, 모달리스용 함수가 존재하는데,

	case WM_INITDIALOG:​


는 WM_CREATE와 비슷하게 다이얼로그가 생성되면 최초 한번 초기화를 하는 부분이라고 보면된다,
그리고 모달용 함수와 모달리스용 함수의 차이점은, 모달용은 확인을 누르든, 취소를 누르든,
대화상자를 종료하는,

EndDialog( hDig, IDOK );​


를 사용하고 있다는 것이고,
모달리스용은, 확인 버튼이 눌릴때는 창을 닫고 있지 않고

InvalidateRect( hWndMain, NULL, TRUE );​


를 사용해 Main윈도우의 변경을 요구하고 있다.
또한 취소를 하게 되면,

			DestroyWindow( hMDlg );
			hMDlg = NULL;​


를 해줌으로써, 대화상자를 파괴하고, hMDlg를 NULL로 변경해 준것을 확인 할 수 있다.
그리고 마지막으로 생성을 WndProc에서 해주고 있는데,

			// 모달리스
			if( !IsWindow( hMDlg ) )
			{
				hMDlg = CreateDialog( g_hInst, MAKEINTRESOURCE( IDD_DIALOG1 ),
					hWnd, MlessDlgProc );
				ShowWindow( hMDlg, SW_SHOW );
			}​


좀전과 마찬가지로 아직 hMDlg가 유효하지 않다면,
CreateDialog를 사용해 생성, SHowWindow를 사용해 화면에 보여주고 있다.

			// 모달
			if( DialogBox( g_hInst, MAKEINTRESOURCE( IDD_DIALOG1 ),
				hWnd, InfoDlgProc ) == IDOK )
				InvalidateRect( hWnd, NULL, TRUE );​


모달용도 비슷하지만, CreateDialog가 아닌 단순히 DialogBox를 사용하고 있는 것을 확인 할 수 있다.
메뉴와 다이얼로그 작성


// 실행 화면

프로그램 설명 : 메뉴에서 모달형식, 모달리스형식을 설정해서 다이얼로그를 띄운다.
다이얼로그에서는 x,y의 합을 보고, 메인에 띄워져 있는 string의 x,y좌표와 내용을 변경할 수 있는 기능을 가지고 있다.

'프로그래밍 > API' 카테고리의 다른 글

API-WindowLong  (0) 2010.04.24
API-WNDCLASSEX  (0) 2010.04.24
API-Control(2)  (0) 2010.04.24
API-Control(1)  (0) 2010.04.24
API-BitMap  (0) 2010.04.24