Win32 샘플 3 - 쓰레드 기반의 해도 로드 및 진행 UI
전자해도 파일은 셀 단위로 구분되어 있으며 국가마다 전체 셀의 개수는 모두 다르다. 그래서 어플리케이션 실행 시 수백에서 수천여개의 셀 파일을 로드하기 위해서는 상당한 시간이 소요되는데 그 동안 화면에 아무 것도 표시되지 않으면 데이터가 정상적으로 로드되고 있는 지 아닌 지 잘 모를 것이다.
본 예제에서는 전자해도 데이터를 로드하는 동안 프로그레스 바를 사용하여 아래의 그림과 같이 로딩 상태를 표시하는 예를 보여주도록 한다.
로딩 중에도 취소 버튼을 누르면 로딩은 중단되며, 현재까지 로딩된 셀은 메모리에 그대로 남아 있다.
보관된 원본 이미지가 없어 표시할 수 없습니다. 위 코드와 설명을 참고해 주십시오.
win32_sample03_01.png[그림 3-1] 전자해도 로딩 상황 표시
로딩 다어얼로그
여기서는 여러 개의 해도 데이터 목록을 가지고 있는 카탈로그 파일을 읽도록 한다. 아래와 같이 loadMap() 함수를 추가하고 InitInstance() 함수에서 호출하도록 한다. 이 코드만으로 전자해도 데이터 로딩 상태의 표시는 완료된다. 나머지는 해도의 이동/확대/축소 예제와 동일하다.
void loadMap()
{
hencLoad( _T( "SHP\\CNTRY92.SENC" ) );
CLoadENC loadEnc;
loadEnc.setMessage( EMI_CAPTION, _T( "Loading. . ." ) );
hencLoadFileListFromCatalogFile( _T( "SENC\\CATALOG.SENC" ), loadEnc.m_listFn );
dlgProgress( GetDesktopWindow(), &loadEnc );
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
if( 0 > hencInit() ) {
MessageBox( GetDesktopWindow(), _T( "hnsEnc 초기화 실패" ), _T( "오류" ), MB_OK );
return FALSE;
}
TCHAR szBaseDir[1024];
getPgmDir( GetModuleHandle( NULL ), szBaseDir, 1000 );
SetCurrentDirectory( szBaseDir );
loadMap();
HWND hWnd;
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
카탈로그 파일에 포함된 셀이 모두 로드되었으므로 앞의 예제보다는 더 많은 오브젝트가 표시되고 있다.
보관된 원본 이미지가 없어 표시할 수 없습니다. 위 코드와 설명을 참고해 주십시오.
win32_sample03_02.png[그림 3-2] 많은 수의 셀이 로드된 전자해도 표시 예
Sample.cpp
// Sample.cpp : 응용 프로그램에 대한 진입점을 정의합니다.
//
#include "stdafx.h"
#include "Sample.h"
#define MAX_LOADSTRING 100
// 전역 변수:
HINSTANCE hInst; // 현재 인스턴스입니다.
TCHAR szTitle[MAX_LOADSTRING]; // 제목 표시줄 텍스트입니다.
TCHAR szWindowClass[MAX_LOADSTRING]; // 기본 창 클래스 이름입니다.
// 이 코드 모듈에 들어 있는 함수의 정방향 선언입니다.
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 여기에 코드를 입력합니다.
MSG msg;
HACCEL hAccelTable;
// 전역 문자열을 초기화합니다.
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_SAMPLE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 응용 프로그램 초기화를 수행합니다.
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SAMPLE));
// 기본 메시지 루프입니다.
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
hencDeinit();
return (int) msg.wParam;
}
//
// 함수: MyRegisterClass()
//
// 목적: 창 클래스를 등록합니다.
//
// 설명:
//
// Windows 95에서 추가된 'RegisterClassEx' 함수보다 먼저
// 해당 코드가 Win32 시스템과 호환되도록
// 하려는 경우에만 이 함수를 사용합니다. 이 함수를 호출해야
// 해당 응용 프로그램에 연결된
// '올바른 형식의' 작은 아이콘을 가져올 수 있습니다.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SAMPLE));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_SAMPLE);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
void loadMap()
{
hencLoad( _T( "SHP\\CNTRY92.SENC" ) );
CLoadENC loadEnc;
loadEnc.setMessage( EMI_CAPTION, _T( "Loading. . ." ) );
hencLoadFileListFromCatalogFile( _T( "SENC\\CATALOG.SENC" ), loadEnc.m_listFn );
dlgProgress( GetDesktopWindow(), &loadEnc );
}
//
// 함수: InitInstance(HINSTANCE, int)
//
// 목적: 인스턴스 핸들을 저장하고 주 창을 만듭니다.
//
// 설명:
//
// 이 함수를 통해 인스턴스 핸들을 전역 변수에 저장하고
// 주 프로그램 창을 만든 다음 표시합니다.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
if( 0 > hencInit() ) {
MessageBox( GetDesktopWindow(), _T( "hnsEnc 초기화 실패" ), _T( "오류" ), MB_OK );
return FALSE;
}
TCHAR szBaseDir[1024];
getPgmDir( GetModuleHandle( NULL ), szBaseDir, 1000 );
SetCurrentDirectory( szBaseDir );
loadMap();
HWND hWnd;
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 함수: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 목적: 주 창의 메시지를 처리합니다.
//
// WM_COMMAND - 응용 프로그램 메뉴를 처리합니다.
// WM_PAINT - 주 창을 그립니다.
// WM_DESTROY - 종료 메시지를 게시하고 반환합니다.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message) {
case WM_LBUTTONDOWN :
{
hencSelect( hWnd );
double xLongitude = GET_X_LPARAM(lParam);
double yLatitude = GET_Y_LPARAM(lParam);
hencWinPosToMapPos( xLongitude, yLatitude );
hencSetCenter( xLongitude, yLatitude );
InvalidateRect( hWnd, NULL, FALSE );
}
break;
case WM_MOUSEWHEEL :
{
hencSelect( hWnd );
double dScale = hencGetScale();
int zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
if( zDelta > 0 ) {
dScale /= 1.5;
if( dScale < 500 )
dScale = 500;
}
if( zDelta < 0 ) {
dScale *= 1.5;
if( dScale > 20000000 )
dScale = 20000000;
}
hencSetScale( dScale );
InvalidateRect( hWnd, NULL, FALSE );
}
break;
case WM_CREATE :
hencCreate( hWnd );
hencSelect( hWnd );
hencSetCenter( 132, 37 );
hencSetScale( 1500000 );
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 메뉴 선택을 구문 분석합니다.
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT r;
GetClientRect( hWnd, &r );
hencSelect( hWnd );
hencSetViewport( 0, 0, r.right - r.left, r.bottom - r.top );
hencClearBackground();
hencRender();
hencCopyBuffer();
SetBkMode( hdc, TRANSPARENT );
SetTextColor( hdc, RGB(255,0,255) );
hdcPrintf( hdc, 0, 0, _T( "Center=%f,%f Scale=%f" ), hencGetCenterX(), hencGetCenterY(), hencGetScale() );
EndPaint(hWnd, &ps);
}
break;
case WM_ERASEBKGND :
return TRUE;
case WM_DESTROY:
hencDelete( hWnd );
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// 정보 대화 상자의 메시지 처리기입니다.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}