
Лабораторная работа № 10. Организация графического пользовательского интерфейса в Windows приложениях в Win32 api
-
Изучение общей структуры Win32 приложений, написанных в среде разработки Visual C++.
-
Приобретение начальных навыков по программированию графического интерфейса Windows в среде разработки Visual C++.
-
Овладение справочной системой среды Visual C++.
Краткие теоретические сведения
В операционных системах семейства Windows взаимодействие пользователя и программы строится на основе архитектуры, управляемой событиями (сообщениями). Основной объект, с которым взаимодействует пользователь – это окно (элементы управления сами являются окнами определенного класса). С окном связана оконная функция. Оконная функция вызывается самой операционной системой (функция обратного вызова), а не пользовательской программой. Оконная функция обрабатывает сообщения, направляемые окну. Когда программа для Windows начинает выполняться, Windows строит для программы очередь сообщений. В этой очереди хранятся сообщения для любых типов окон, которые могли бы быть созданы программой. Небольшая часть программы, которая называется циклом обработки сообщений, выбирает эти сообщения из очереди и перенаправляет их соответствующей оконной процедуре. Другие сообщения отправляются непосредственно оконной процедуре, минуя очередь сообщений. Окна всегда создаются на основе «класса окна». Класс окна определяет оконную процедуру, обрабатывающую поступающие окну сообщения. Использование класса окна позволяет создавать множество окон на основе одного и того же класса окна и, следовательно, использовать одну и ту же оконную функцию. В Windows имеется множество различных сообщений. Каждое сообщение идентифицируется номером, но для удобства всем номерам присвоены константы, имена которых начинаются с WM_.
Простейшая программа для Windows имеет следующий код:
//Файл StdAfx.h
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
//Файл StdAfx.cpp
#include "stdafx.h"
//Файл SimpleProg1.cpp
#include "stdafx.h"
#include <tchar.h>
//прототип оконной функции
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst; //Для сохранения дескриптора приложения
//Главная функция
int APIENTRY _tWinMain (HINSTANCE hThisInst, //дескриптор экземпляра
HINSTANCE hPrevInst, //=0
LPTSTR lpszArgs, //хвост командной строки, 0
int iWinMode) //вид окна при запуске
{
TCHAR szAppName[]=_TEXT(”Имя класса”);
HWND hwnd; // дескриптор окна
MSG msg; // сообщение
WNDCLASSEX wndclass; // структура класса окна
hInst = hThisInst; //сохранить дескриптор приложения
//Определить класс окна
wndclass.cbSize = sizeof(wndclass);
wndclass.hInstance = hThisInst; //дескриптор данного приложения
wndclass.lpszClassName= szAppName; //имя класса окна
wndclass.lpfnWndProc=WndProc; //функция окна
wndclass.style =0; //стиль по умолчанию
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //стд. значок
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //стд. курсор
wndclass.lpszMenuName = NULL; //без меню
wndclass.cbClsExtra=0; //без дополнительной
wndclass.cbWndExtra=0;//информации
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); //стд. значок
if (!RegisterClassEx(&wndclass)) return 0; //зарегистрировать класс окна
//создать окно
hwnd = CreateWindow (szAppName, //имя класса
_TEXT(“Заголовок окна”), //заголовок окна
WS_OVERLAPPEDWINDOW, //стиль окна
CW_USEDEFAULT, //х- координата окна
CW_USEDEFAULT, //y- координата окна
CW_USEDEFAULT, //ширина окна
CW_USEDEFAULT, //высота окна
HWND_DESKTOP, //нет родительского окна
NULL, //нет меню
hThisInst, //дескриптор приложения
NULL); //без дополнительных аргументов
ShowWindow(hwnd, iWinMode); //Показать окно
UpdateWindow (hwnd); //вывести в окно содержимое
while (GetMessage(&msg, NULL, 0,0)) //цикл обработки сообщений
{
TranslateMessage (&msg); //Послать символьное сообщение клавиатуры
DispatchMessage(&msg); //вернуть управление Windows
}
return msg.wParam;
}
// Оконная функция
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndButton;
switch (iMsg)
{
case WM_CREATE:
hwndButton=CreateWindow(_TEXT(“BUTTON”),_TEXT(”Ok”), BS_DEFPUSHBUTTON|WS_CHILD|WS_VISIBLE, 100, 100, 60, 30, hwnd, (HMENU)1,hInst, NULL);
return 0;
case WM_COMMAND:
MessageBox(hwnd, _TEXT(“Нажата клавиша Ok”),_TEXT(”Сообщение”), MB_OK);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
//остальные сообщения обрабатывает функция окна по умолчанию
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Код, подобный приведенному выше, является скелетом любой программы в Window с графическим интерфейсом.
В основе архитектуры, управляемой событиями лежат вызовы следующих функций:
-
RegisterClassEx – зарегистрировать класс окна;
-
CreateWindow – создать окно;
-
ShowWindow – показать окно;
-
UpdateWindow – отобразить содержимое окна;
-
GetMessage – получить сообщение из очереди;
-
TranslateMessage – передает сообщение обратно операционной системе для преобразования какого-либо сообщения клавиатуры;
-
DispatchMessage – передает сообщение обратно операционной системе;
-
PostQuitMessage (0) – ставит сообщение WM_QUIT в очередь сообщений программы.
Насчитывается несколько сотен функций графического интерфейса пользователя (GUI). Чаще всего используются следующие категории GUI: управление окнами, управление меню, управление диалоговыми окнами, управление рисованием и черчением, управление текстом, управление растровыми изображениями, курсорами и значками, управление цветами и палитрой, управлении буфером обмена, управление вводом.
В частности, для выполнения рисования и вывода текста используются следующие функции: BeginPaint, EndPaint, GetDC, ReleaseDC, GetClientRect, LineTo, MoveToEx, Polyline, PolylineTo, Rectangle, RoundRect, Ellipse, InvalidateRect, DrawText. Функция BeginPaint возвращает контекст устройства, который должен использоваться во всех остальных функциях. Рисование выполняется обычно по сообщению WM_PAINT.
По умолчанию используются черные сплошные перья. Перо – это логический объект GDI. Для создания нового пера следует использовать функцию CreatePen. Вызов ее выглядит так HPEN hpen = CreatePen(iPenStyle, iWidth, rgbColor). Параметр iPenStyle определяет, какого типа линии будут отображаться: сплошная, точечная или пунктирная. Этот параметр может принимать одно значение из следующего списка, приведенных в заголовочном файле Windows: PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT, PS_NULL, PS_INSIDEFRAME.
Для стилей PS_SOLID, PS_NULL и PS_INSIDEFRAME параметр iWidth — ширина пера. Ширина iWidth равная 0, заставляет Windows использовать перо шириной в один пиксель. Стандартные перья имеют ширину в 1 пиксель. Если вы зададите точечный или пунктирный стиль линии с физической шириной больше 1, Windows, тем не менее, будут использовать сплошное перо. Цвет можно создать функцией RGB(i_red, i_green, i_blue).
Созданное перо hPen необходимо поместить в контекст устройства hdc вызовом функции SelectObject(hdc, hPen). После использования пера его следует удалить из контекста устройства вызовом функции: DeleteObject(hPen).
Для вывода текста используются функции DrawText, TextOut.
Функция DrawText рисует форматированный текст в прямоугольнике. Вызов функции имеет вид DrawText(hdc, lpString, nCount, lpRect, uFormat), где hdc – описатель контекст устройства, lpString – указатель на рисуемую строку (тип LPCTSTR), nCount – длина строки в символах (тип int, для нуль терминированных строк задается значение -1), uFormat – метод форматирования текста (тип UINT). Некоторые из флагов форматирования: DT_TOP - выравнивание по верхнему краю прямоугольника, DT_BOTTOM – выравнивание по нижнему краю прямоугольника, DT_VCENTER – выравнивание по центру по вертикали, DT_LEFT – выравнивание по левому краю прямоугольника, DT_RIGHT – выравнивание по правому краю прямоугольника, DT_CENTER – выравнивание по центру по горизонтали, DT_SINGLELINE – отображение текста в одну линию.
Функция TextOut выводит строку символов в определенное местоположение рабочей области. Вызов функции имеет вид TextOut(hdc, x, y, psString, iLength), где hdc – описатель контекста устройства, параметры x и y определяют начальную позицию строки символов в рамках рабочей области, psString – указатель на строку символов (тип LPCTSTR), iLength – длина строки в символах (тип int). По умолчанию координаты вывода x и y задают левый верхний угол строки текста.
Выравнивание выводимого текста можно задать с помощью функции SetTextAlign. Вызов имеет вид SetTextAlign(hdc, fMode), где hdc – описатель контекста устройства, fMode – флаг выравнивания текста (тип UINT). Некоторые из флагов выравнивания текста: TA_BASELINE – координаты вывода задают базовую линию текста, TA_TOP – координаты вывода задают верхний угол строки текста, TA_BOTTOM – координаты вывода задают нижний угол строки текста, TA_CENTER – координаты вывода задают центр по горизонтали ограничивающего строку прямоугольника, TA_LEFT – координаты вывода задают левый край строки текста, TA_RIGHT – координаты вывода задают правый край строки текста.
Цвет выводимого текста можно задать с помощью функции SetTextColor. Вызов функции имеет вид SetTextColor(hdc, crColor), где hdc – описатель контекста устройства, crColor – цвет текста (тип COLORREF). Цвет можно задать вызовом функции RGB.
Создать шрифт с требуемыми параметрами можно с помощью функций CreateFont и CreateFontIndirect. Они возвращают описатель шрифта (тип HFONT), который нужно поместить в контекст устройства.
Прототип функции CreateFont:
HFONT CreateFont(
int nHeight, // логическая высота шрифта
int nWidth, // логический средний размер шрифта
int nEscapement, // угол наклона строки текста к горизонтальной оси в десятых долях градуса
int nOrientation, // угол наклона каждого символа к горизонтальной оси в десятых долях градуса
int fnWeight, // жирность шрифта (от 0 до 1000) (400 – нормальный, 700 – жирный)font weight
DWORD fdwItalic, // ненулевое значение создает наклонный шрифт
DWORD fdwUnderline, // ненулевое значение создает подчеркнутый шрифт
DWORD fdwStrikeOut, // ненулевое значение создает перечеркнутый шрифт
DWORD fdwCharSet, // определяет множество символов шрифта, обычно задается макросом, например, DEFAULT_CHARSET
DWORD fdwOutputPrecision, // точность отображения шрифта, например, OUT_DEFAULT_PRECIS
DWORD fdwClipPrecision, // определяет, как будут отсекаться символы, не попавшие в видимую область вывода, например, CLIP_DEFAULT_PRECIS
DWORD fdwQuality, // качество шрифта: DEFAULT_QUALITY, DRAFT_QUALITY, PROOF_QUALITY
DWORD fdwPitchAndFamily, // тип и семейство шрифта. Значение формируется операцией логического сложения для выбранного типа и семейства. Тип шрифта: DEFAULT_PITCH, FIXED_PITCH, VARIABLE_PITCH. Семейство шрифта: FF_DECORATIVE, FF_DONTCARE, FF_MODERN, FF_ROMAN, FF_SCRIPT, FF_SWISS.
LPCTSTR lpszFace // указатель на строку, содержащее имя шрифта (до 32 символов), например, Arial.
).
Подробное описание принимаемых параметров функцией CreateFont, а также описание функции CreateFontIndirect см. в SDK.
Получить текущие параметры шрифта можно вызовом функции GetTextMetrics. Вызов функции имеет вид GetTextMetrics(hdc, lptm), где hdc – описатель контекста устройства, lptm – адрес структуры метрических параметров текста (тип LPTEXTMETRIC). Структура TEXTMETRIC определена следующим образом:
typedef struct tagTEXTMETRIC { // tm
LONG tmHeight;
LONG tmAscent;
LONG tmDescent;
LONG tmInternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth;
LONG tmMaxCharWidth;
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
BCHAR tmFirstChar;
BCHAR tmLastChar;
BCHAR tmDefaultChar;
BCHAR tmBreakChar;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
} TEXTMETRIC;
Подробное описание ее полей см. в SDK.
Поля ввода являются окнами класса “edit”. Для управления текстом в них служат функции SetWindowText, GetWindowText, GetWindowTextLengh. Поля ввода посылают уведомления (сообщения): EN_SETFOCUS – получен фокус ввода, EN_KILLFOCUS – потерян фокус ввода, EN_CHANGE – содержимое поля ввода будет изменяться, EN_UPDATE – содержимое окна изменилось и др.
При изменении размеров окна генерируется сообщение WM_SIZE. Размеры окон при этом передаются в нижнем и верхнем словах параметра сообщения lParam.
Для создания Win32 приложения в среде Visual Studio нужно выполнить следующую последовательность действий.
-
Запустить приложение Visual C++ 6.0.
-
Командой File New создать проект.
-
В открывшемся диалоговом окне выбрать тип проекта Win32 Application.
-
Дать имя проекту, выбрать месторасположение проекта и нажать кнопку Ok.
-
В следующем диалоговом окне выбрать пункт A Simple 32 Application или A typical “Hello World!” application и нажать на кнопку Finish, в следующем диалоговом окне нажать кнопку Ok.
-
Перейти на вкладку FileView панели управления проектом и раскрыть в ней папку Source Files. В файл Имя_проекта.cpp ввести необходимый код.
-
При необходимости добавить в проект дополнительные файлы и ввести в них необходимый код.
-
Сохранить проект и построить исполняемый файл, выполнив команду Build Build SimpleProg1.exe (F7).
-
Запустить исполняемый файл, выполнив команду Build Execute SimpleProg1.exe (Ctrl+F5).