Win32 api программирование
Скачать 0.78 Mb.
|
2.3. Приложение с главным окном и меню /* Файл resource.h */ // //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by 1111.rc 47 // #define IDD_DIALOGBAR 103 #define IDC_BUTTON1 1002 #define IDC_STATIC_1 1003 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1004 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif Если открыть файл описания ресурсов 1111.rc в текстовом режи- ме, то можно увидеть следующее определение шаблона диалогового окна: //////////// // Microsoft Visual C++ generated resource script. // #include "resource.h" //... /////////////////////////////////////////////////////////// // // Dialog // IDD_DIALOGBAR DIALOGEX 0, 0, 153, 62 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "СПб ГУ ИТМО" FONT 10, "Lucida Console", 700, 0, 0xCC BEGIN PUSHBUTTON "Ok",IDOK,105,42,41,14,BS_CENTER CTEXT "ЛИТМО\n КАФЕДРА ПКС\n2009", IDC_STATIC,44,14,63,26,WS_TABSTOP END /////////////////////////////////////////////////////////// /* Файл 1111.cpp */ /*Операторы препроцессора*/ /* #define UNICODE #ifdef UNICODE #define _UNICODE #endif */ #define STRICT #include #include /* Файл tchar.h состоит из макросов, которые ссылаются на UNICODE данные и функции, если определен макрос UNICODE, и на ANSI данные и функции, если этот макрос не определен, кроме того он полностью заменяет файл string.h */ #include 48 #include "resource.h" /* Идентификаторы пунктов меню приведены для наглядности, лучше всего их повестить в файл resource.h */ #define ID_FILE_TEST 40001 #define ID_FILE_EXIT 40002 #define ID_HELP_ABOUT 40003 /*Прототип оконной функции*/ LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); /*Прототип функции модального диалога*/ INT_PTR CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM); /* Прототип функция обратного вызова обработки сообщений от таймера */ VOID CALLBACK TimerProc(HWND,UINT,UINT_PTR,DWORD); /* Прототип функции получения текущего времени и преобразование его в символы */ void OutTimeDate(HWND); /*Дескрипторы всплывающих меню и дескриптор главного меню*/ HMENU hFileMenu,hHelpMenu,hMenu; /*Будет создан логический шрифт*/ HFONT hFont,hOldFont; /*Массив для формирования строки - текущие дата и время*/ TCHAR szCurrentTime[40]; int nTime=5;//Однократный интервал 5с int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow) { /*Произвольный заголовок окна*/ TCHAR szTitle[]=_TEXT("ИТМО"); /*Произвольное имя класса*/ TCHAR szWindowClass[]=_TEXT("QWERTY"); /* Структурная переменная msg типа MSG для получения сообщений */ MSG msg; /* Структурная переменная wcex типа WNDCLASSEX для задания характеристик окна */ WNDCLASSEX wcex; HWND hWnd; //Дескриптор главного окна /*Проверяем, было ли это проложение запущено ранее*/ if(hWnd=FindWindow(szWindowClass,NULL)) { /*Проверяем, было ли это окно свернуто в пиктограмму*/ if(IsIconic(hWnd)) ShowWindow(hWnd,SW_RESTORE); /*Выдвигаем окно приложения на передний план*/ SetForegroundWindow(hWnd); return FALSE; 49 } /*Обнуление всех членов структуры wcex*/ memset(&wcex,0,sizeof(WNDCLASSEX)); /*Регистрируем класс главного окна*/ wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; /*Определяем оконную процедуру для главного окна*/ wcex.lpfnWndProc = (WNDPROC)WndProc; //wcex.cbClsExtra = 0; //wcex.cbWndExtra = 0; wcex.hInstance = hInstance;//Дескриптор приложения /* Стандартная пиктограмма, которую можно загрузить функцией LoadImage() */ wcex.hIcon = (HICON)LoadImage(hInstance, IDI_APPLICATION, IMAGE_ICON,32,32,0); /*Стандартный курсор мыши*/ wcex.hCursor = LoadCursor(NULL, IDC_ARROW); /* Кисть фона и ее цвет можно определить выражениями: wcex.hbrBackground=(HBRUSH)(COLOR_APPWORKSPACE+1); wcex.hbrBackground=(HBRUSH)GetStockObject(LTGRAY_BRUSH); или с помощью макроса GetStockBrush(), в этом случае необходимо подключить файл windowsx.h */ wcex.hbrBackground=GetStockBrush(LTGRAY_BRUSH); //wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MSG_1); /*Имя класса главного окна*/ wcex.lpszClassName = szWindowClass; wcex.hIconSm = NULL; if(!RegisterClassEx(&wcex)) return FALSE; /*Создаем главное окно и делаем его видимым*/ hWnd = CreateWindowEx(WS_EX_WINDOWEDGE,szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,0,CW_USEDEFAULT,0, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; /* Исследуем адресное пространство приложения. Выведем содержимое сегментных регистров команд, данных и стека, а также смещение главной функции и строки с именем класса */ TCHAR szAsm[80]; USHORT regCS,regDS,regES,regSS; __asm{ mov regCS,CS mov regDS,DS mov regES,ES mov regSS,SS } wsprintf((LPTSTR)szAsm,_T("CS=%X,DS=%X\nES=%X,SS=%X\n WinMain=%X\nszWindowClass=%X"), regCS,regDS,regES,regSS); 50 MessageBox(NULL,(LPCTSTR)szAsm,_T("Регистры"), MB_ICONINFORMATION); /* Создаем пустое всплывающее меню самого низкого уровня hFileMenu=CreatePopupMenu()и добавляем в него конечный элемент "Test" */ AppendMenu((hFileMenu=CreatePopupMenu()), MF_ENABLED | MFT_STRING, ID_FILE_TEST,_TEXT("&Test")); /* Добавляем в созданное меню конечный элемент "Exit" */ AppendMenu(hFileMenu,MF_GRAYED | MFT_STRING, ID_FILE_EXIT,_TEXT("&Exit")); /* Создаем пустое всплывающее меню самого низкого уровня hHelpMenu=CreatePopupMenu()и добавляем в него конечный элемент "About" */ AppendMenu((hHelpMenu=CreatePopupMenu()), MF_ENABLED|MFT_STRING, ID_HELP_ABOUT,_TEXT("&About")); /* Создаем меню верхнего уровня - главное меню hMenu=CreateMenu()и присоединяем созданное подменю"File" к главному меню" */ AppendMenu((hMenu=CreateMenu()), MF_ENABLED | MF_POPUP, (UINT_PTR)hFileMenu, _TEXT("&File")); /* Присоединяем созданное подменю "Help" к главному Меню */ AppendMenu(hMenu,MF_ENABLED|MF_POPUP, (UINT_PTR)hHelpMenu,_TEXT("&Help")); / *Добавляем в конец главного меню конечный пункт "QUIT" */ AppendMenu(hMenu,MF_GRAYED,(UINT_PTR)11, _TEXT("Quit")); /*Присоединяем созданное меню к окну приложения*/ SetMenu(hWnd,hMenu); /*Делаем окно видимым на экране*/ ShowWindow(hWnd, SW_SHOWNORMAL); /* Функция UpdateWindow() вызывает передачу сообщения WM_PAINT непосредственно оконной процедуре, а функция InvalidateRect() вызывает постановку сообщения WM_PAINT в очередь приложения, а там оно обрабатывается с самым низким приоритетом */ UpdateWindow(hWnd); /*Отображаем меню*/ DrawMenuBar(hWnd); /*Цикл обработки сообщений*/ while (GetMessage(&msg, NULL, 0, 0)) { 51 TranslateMessage(&msg); DispatchMessage(&msg); } /*Код возврата*/ return (int)msg.wParam; } /*Оконная функция главного окна*/ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { /*Горизонтальный размер главного окна*/ int xSize=500; /*Верикальный размер главного окна*/ int ySize=300; /* PAINTSTRUCT - структура с характеристиками рабочей области (заполняется функцией BeginPaint) */ PAINTSTRUCT ps; /* TEXTMETRIC - структура для получения характеристик шрифта */ TEXTMETRIC tm; /* LOGFONT - структура для для создания логических шрифтов */ LOGFONT lf; /* RECT–структура,определящая прямоугольник */ RECT rect; LPMINMAXINFO lpmmi; Static HFONT hFont,hOldFont; /*Дескриптор контекста устройства*/ HDC hDc; /* Ширина width и высота height клиентской области окна в пикселях */ UINT width, height; /*Имя для шрифта*/ LPTSTR lpszFace=_TEXT("Times New Roman Cur"); switch (message) { /*Переход по значению кода сообщения(msg)*/ case WM_CREATE: /*Только здесь можно произвести модификацию Класса окна. Например, SetClassLong(hWnd,GCL_HBRBACKGROUND, (LONG)CreateSolidBrush(RGB(200,160,255)); Значение дескриптора экземпляра приложения определяется,вызовом одной из следующих функций: hInst=GetModuleHandle(NULL); hInst=(HINSTANCE)GetClassLong(hWnd,GCL_HMODULE); */ /*Обнуление всех членов структуры lf*/ memset(&lf,0,sizeof(lf)); 52 /*Устанавливаем размер шрифта*/ lf.lfHeight=30; /*Копируем в структуру имя шрифта*/ lstrcpy(lf.lfFaceName,lpszFace); /*Создаем шрифт*/ hFont=CreateFontIndirect(&lf); /*Первый немедленный вывод текущего времени*/ OutTimeDate(hWnd); /* Функция SetTimer создает системный таймер с периодом 1с */ SetTimer(hWnd,1,1000,(TIMERPROC)NULL); return TRUE; case WM_TIMER: /* Функция OutTimeDate запрашивает у системы текущие значения даты и времени, а затем организует их обработку в главном окне приложения. */ OutTimeDate(hWnd); break; case WM_KEYDOWN: /*Обрабатываем сообщение-нажатие клавиши.*/ switch(wParam) { case VK_ESCAPE: /* Посылаем сообщение WM_CLOSE окну (hWnd), после того, как оконная процедура обработает это сооб- щение, система передаст управление инструкции следующей за SendMessage */ SendMessage(hWnd,WM_CLOSE,0,0); break; } break; case WM_COMMAND: switch(LOWORD(wParam)) //switch(wParam) { case ID_FILE_TEST: /* Изменяем статус пункта меню ID_FILE_EXIT */ EnableMenuItem(hFileMenu,ID_FILE_EXIT, MF_BYCOMMAND|MF_ENABLED); /*Ставим отметку (галочка) на пункте меню ID_FILE_TEST*/ CheckMenuItem(hFileMenu,ID_FILE_TEST, MF_BYCOMMAND|MF_CHECKED); /*Изменяем статус пункта главного меню "QUIT"*/ EnableMenuItem(GetMenu(hWnd), (UINT_PTR)11,MF_BYCOMMAND|MF_ENABLED); /* Так как изменился статус пункта главного меню, вызываем функцию DrawMenuBar для повторного отображения изменившейся полосы меню */ DrawMenuBar(hWnd); 53 /*Устанавливаем таймер на nTime секунд*/ SetTimer(hWnd,2,nTime*1000, (TIMERPROC)TimerProc); break; case ID_FILE_EXIT: /* Без запроса на закрытие окна - функция PostQuitMessage посылает сообщение WM_QUIT */ PostQuitMessage(0); /* С запросом на закрытие, т.е. окно еще не разруше- но SendMessage(hWnd,WM_CLOSE,0,0); */ break; case ID_HELP_ABOUT: /* Функция DialogBox создает и выводит на экран мо- дальное диалоговое окно по шаблону IDD_ABOUTBOX, и не возвращает управление в WndProc пока окно диало- ка не бедет закрыто. */ DialogBox(GetModuleHandle()NULL, MAKEINTRESOURCE(IDD_DIALOGBAR), hWnd, (DLGPROC)AboutProc); break; case (UINT)11: /* Без запроса на закрытие окна - функция PostQuitMessage посылает сообщение WM_QUIT */ PostQuitMessage(0); break; } break; case WM_PAINT: /*Получаем контекст устройства*/ hDc = BeginPaint(hWnd, &ps); /*Определяем размеры клиентской области окна*/ GetClientRect(hWnd,&rect); /*Выбираем в контест созданный шрифт*/ hOldFont=SelectFont(hDc,hFont); /*Получим метрики текста(если это необходимо)*/ GetTextMetrics(hDc,&tm); /* Функция SetBkMode устанавливает текущий режим фона. TRANSPARENT - в этом режиме вывода текста цвет фона гра- фического элемента игнорируется, т.е. символ выводится на существующем фоне */ SetBkMode(hDc,TRANSPARENT); /* Функция SetTextColor устанавливает цвет текста для кон- текста устройства, по умолчанию применяется черный цвет. Цвет текста синий! */ SetTextColor(hDc,RGB(0,0,128)); DrawText(hDc,szCurrentTime,-1,&rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER); /*Освобождаем контекст устройства*/ 54 EndPaint(hWnd, &ps); break; case WM_CLOSE: /* Сообщение WM_CLOSE появляется при щелчке на кнопке закрытия окна - здесь предназначено для вывода преду- преждающего сообщения */ if(MessageBox(hWnd,_T("Вы уверены?"), _T("Предупреждение!"), MB_YESNO | MB_ICONQUESTION)==IDYES) { /* Функция DestroyWindow разрушает указанное в ее па- раметре окно, т.е. она посылает окну сообщение WM_DESTROY. Затем вызывается функция PostQuitMessage, которая посылает сообщение WM_QUIT */ DestroyWindow(hWnd); } break; case WM_SIZE: /* Ширина width и высота height клиентской области окна в пикселях */ width=LOWORD(lParam); height=HIWORD(lParam); //... break; case WM_LBUTTONDOWN: /*Нажата клавиша Shift ?*/ if(wParam & MK_SHIFT) { MessageBox(hWnd,_T("Нажата клавиша\nShift"), _T("Bad boys"), MB_OK|MB_ICONEXCLAMATION); } break; case WM_GETMINMAXINFO: lpmmi=(LPMINMAXINFO)lParam; /* Минимальный и максимальный размеры окна совпадают */ lpmmi->ptMinTrackSize.x=xSize; lpmmi->ptMinTrackSize.y=ySize; lpmmi->ptMaxTrackSize.x=xSize; lpmmi->ptMaxTrackSize.y=ySize; break; case WM_DESTROY: /* Функция DeleteObject удаляет логический объект. К удаляе- мым объектам относятся перья, растровые изображения, кис- ти, области, палитры и шрифты */ /*Удаляем созданный шрифт*/ DeleteObject(hFont); /*Функция KillTimer удаляет таймер*/ 55 KillTimer(hWnd,1); /* PostQuitMessage() выполняет только одно действие - ставит в очередь сообщение WM_QUIT. Параметр у этой функции - код возврата, который помещается в wParam */ PostQuitMessage(0); break; default: /*Обработка прочих сообщений по умолчанию*/ return DefWindowProc(hWnd, message, wParam, lParam); } return 0L; } /*Оконная функция диалогового окна*/ INT_PTR CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: /* Для обрабатываемых сообщений процедура всегда возвращает TRUE */ return (INT_PTR)TRUE; case WM_COMMAND: if(LOWORD(wParam)==IDOK || LOWORD(wParam)== IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } /* Для не обрабатываемых сообщений процедура всегда возвращает FALSE */ return (INT_PTR)FALSE; } /* Фунуция получения текущего времени и преобразование его в символы */ void OutTimeDate(HWND hWnd) { LPTSTR szDay[]={_T("Вск."),_T("Пнд."),_T("Втр."), _T("Ср."),_T("Чтв."), _T("Птн."),_T("Суб.") }; LPTSTR szMonth[]={_T(""),_T("Янв."),_T("Февр."), _T("Март"),_T("Апр."), _T("Май"),_T("Июнь"), _T("Июль"),_T("Авг."), 56 _T("Сент."),_T("Окт."), _T("Нояб."),_T("Дек.") }; TCHAR szT[20]; SYSTEMTIME SystemTime; /* Функция GetLocalTime осуществляет выборку местного време- ни, на которое настроен компьютер, т.е. функция заполняет структуру типа SYSTEMTIME в числовом виде. */ GetLocalTime(&SystemTime); /*День недели*/ lstrcpy(szCurrentTime, szDay[SystemTime.wDayOfWeek]); /*Разделяющий пробел*/ lstrcat((LPTSTR)szCurrentTime,_T(" ")); /*Месяц*/ lstrcat((LPTSTR)szCurrentTime, szMonth[SystemTime.wMonth]); /*Разделяющий пробел*/ lstrcat((LPTSTR)szCurrentTime,_T(" ")); /*Дату переводим в символы*/ wsprintf((LPTSTR)szT,_T("%d"), SystemTime.wDay); lstrcat((LPTSTR)szCurrentTime,(LPTSTR)szT); /*Разделяющий пробел*/ lstrcat((LPTSTR)szCurrentTime,_T(" ")); /*Год переводим в символы*/ wsprintf((LPTSTR)szT,_T("%d"), SystemTime.wYear); lstrcat((LPTSTR)szCurrentTime,(LPTSTR)szT); lstrcat((LPTSTR)szCurrentTime,_T("---")); /*Часы переводим в символы*/ wsprintf((LPTSTR)szT,_T("%d"), SystemTime.wHour); lstrcat((LPTSTR)szCurrentTime,(LPTSTR)szT); /*Разделяющее двоеточие*/ lstrcat((LPTSTR)szCurrentTime,_T(":")); /*Минуты переводим в символы*/ wsprintf((LPTSTR)szT,_T("%d"), SystemTime.wMinute); lstrcat((LPTSTR)szCurrentTime,(LPTSTR)szT); /*Разделяющее двоеточие*/ lstrcat((LPTSTR)szCurrentTime,_T(":")); /*Секунды переводим в символы*/ wsprintf((LPTSTR)szT,_T("%d"), SystemTime.wSecond); lstrcat((LPTSTR)szCurrentTime,(LPTSTR)szT); /*Перерисовка окна*/ InvalidateRect(hWnd,NULL,TRUE); } /*Функция обратного вызова обработки сообщений от таймера*/ VOID CALLBACK TimerProc(HWND hWnd,UINT uMsg, UINT_PTR idEvent,DWORD dwTime) { TCHAR szTimer[100]; KillTimer(hWnd,2); wsprintf(szTimer, _T("С момента выбора\nпункта меню Test\nпрошло %d c!"), 57 nTime); MessageBox(NULL,(LPCTSTR)szTimer, _T("Предупреждение"),MB_ICONHAND); } Результат работы программы приведен на рис. 3. Рис. 3. Окно приложения с главным меню 3. ЭЛЕМЕНТЫ УПРАВЛЕНИЯ ОБЩЕГО ПОЛЬЗОВАНИЯ Рассмотрим элементы управления главного окна: • Toolbar (панель инструментов) – состоит из кнопок быстрого дос- тупа; • Statusbar (строка состояния) – информационная строка, которая размещается в нижней части окна приложения. Большинство элементов управления общего пользования реализо- вано в виде окна соответствующего предопределенного класса и управ- ляются специфичными для данного класса сообщениями. Элементы управления посылают уведомляющие сообщения родительскому окну, информируя его о происходящих событиях. Чтобы использовать в приложении элементы управления общего пользования, необходимо вначале вызвать функцию 58 InitCommonControlsEx(), которая регистрирует оконные классы элементов управления. Описание функции находится в файле commctrl.h. Поэтому необходимо в начало исходного файла включить следующую директиву: #include Кроме того, следует указать компоновщику расположение библио- течного файла comctl32.lib. Функция имеет прототип: BOOL InitCommonControlsEx( LPINITCOMMONCONTROLSEX lpInitCtrls); Параметр lpInitCtrls – адрес структурной переменной типа INITCOMMONCONTROLSEX, которая содержит информацию о том, какие классы элементов управления должны быть зарегистрированы. Структура имеет вид: typedef struct tagINITCOMMONCONTROLSEX { DWORD dwSize; //размер структуры в байтах DWORD dwICC; //флаги загрузки классов из DLL } INITCOMMONCONTROLSEX, *LPINITCOMMONCONTROLSEX; Второй параметр dwICC структуры может содержать один или не- сколько следующих флагов (полный список флагов в MSDN): • ICC_BAR_CLASSES – toolbar, status bar, slider, tooltip; • ICC_PROGRESS_CLASS – progress bar; • ICC_TREEVIEW_CLASSES – tree view. Создание органов управления Toolbar и Statusbar выполняет- ся приложением при обработке функцией главного окна сообщения WM_CREATE. |