
Поcобие_БЕЛОВ_Графический_интерфейс_API
.pdf21
1.6. Вспомогательные функции создания окон
Windows API содержит множество функций, связанных с созданием окон. Это функции поиска, определения состояния, перемещения окон, а также обмена сообщениями с пользователем.
1.6.1. Функции поиска и определения состояния окон
Часто требуется определить, существует ли окно для некоторого дескриптора. На этот вопрос отвечает функция IsWindow:
BOOL IsWindow( HWND hwnd).
Если окно с дескриптором hwnd существует, функция возвращает ненулевое значение, иначе – нуль.
Если необходимо определить, имеет ли заданное окно фокус ввода, вызывают функцию IsWindowEnabled:
BOOL IsWindowEnabled( HWND hwnd).
Если окно hwnd активно, функция возвращает ненулевое значение, иначе – нуль.
Для передачи или отнятия фокуса ввода у окна вызывают функцию EnableWindow:
BOOL EnableWindow( HWND hwnd, BOOL bEnable).
При bEnable=TRUE фокус ввода передают окну hwnd, иначе блокируют это окно.
Если окно ранее было неактивно, возвращаемое значение отлично от нуля. Если окно было активно, возвращаемое значение – нуль.
Фокус ввода окну hwnd передают с помощью функции SetFocus: SetFocus(hwnd).
Следующая функция возвращает ненулевое значение, если окно hwnd свернуто в пиктограмму: BOOL IsIconic(HWND hwnd).
Функция FindWindow у операционной системы запрашивает дескриптор окна (не дочернего) класса lpClassName с заголовком lpWindowName. Эта функция объявлена следующим образом:
HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName).
Если параметр lpWindowName – NULL, то заголовок искомого окна может быть любым. Если lpClassName – NULL, искомое окно может принадлежать к любому классу. Рекомендуется указывать данные как можно более подробно. Если такое окно определено,
22
функция возвращает его дескриптор, иначе – NULL.
1.6.2. Функции перемещения окон
Для перемещения и изменения размеров окна hwnd вызывают функцию MoveWindow. Ей передают новые координаты окна.
Функция MoveWindow объявлена следующим образом:
BOOL MoveWindow(
HWND hwnd, |
|
||
int |
x, |
//Новая координата левого края окна |
|
int |
У. |
//Новая координата верхнего края окна |
|
int |
nWidth, |
//Новая ширина окна |
|
int |
nHeight, |
//Новая высота окна |
BOOL bRepaint //Флажок перекрашивания окна
);
Если bRepaint=TRUE, окно перерисовывается немедленно после перемещения и перерисовываются те части экрана, на которых отразилось перемещение окна, иначе окно перерисовывает себя только после обработки всех поступивших к моменту перемещения сообщений. При успешном выполнении функция возвращает ненулевое значение, иначе – нуль.
Функция SetWindowPos изменяет координаты окна hwnd на экране и его расположение по отношению к другим окнам:
BOOL SetWindowPos( HWND hwnd,
HWND hWndInsertAfter, //Дескриптор порядка размещения
int x, int у, int ex, int су,
UINT uFlags
);
При успешном выполнении функция возвращает ненулевое значение. Параметр hWndInsertAfter может быть дескриптором предшествующего окна или равным одному из следующих значений:

23
Значение параметра
HWND_BOTTOM
HWND_NOTOPMOST
HWND_TOP
HWND_TOPMOST
Пояснение
Помещает окно ниже других окон
Помещает временное или дочернее окно выше временных и дочерних, но ниже перекрывающихся окон
Помещает окно выше всех окон
То же, что HWND_NOTOPMOST, но окно сохраняет позицию после потери активности
Параметр uFlags может быть комбинацией значений из таблицы:
Значение параметра |
Пояснение |
SWP_DRAWFRAME |
Вокруг окна рисовать заданную в классе окна |
|
рамку |
SWP_FRAMECHANGED |
Функции окна посылать сообщение об изменении |
|
размеров, даже если размер окна не изменяется |
|
|
SWP_HIDEWINDOW |
Скрыть окно |
SWP_NOACTIVATE |
Отменить активность окна |
SWP_NOCOPYBITS |
Стереть содержимое рабочей области |
SWP_NOMOVE |
Сохранить текущую позицию |
SWP_NOOWNERZORDER |
Не изменять расположение окна относительно |
или |
других окон |
SWP_NOREPOSITION |
|
|
|
SWP_NOREDRAW |
Не перерисовывать содержимое окна |
SWP_NOSENDCHANGING |
Не сообщать об изменении позиции |
SWP_NOSIZE |
Сохранить текущий размер |
SWP_NOZORDER |
Не менять расположение окна |
SWP_SHOWWINDOW |
Показать окно |
При одновременной работе нескольких приложений одно из них можно вывести на передний план и передать его окну фокус ввода.
Для этого используют функцию SetForegroundWindow. Она помещает поток, который создал заданное окно, на передний план и активизирует это окно. Синтаксис этой функции:
BOOL SetForegroundWindow (HWND hwnd );
При успешном перемещении функция возвращает ненулевое значение, иначе – нуль.
Для перемещения окна необходимо знать системные метрики экрана и окна. Их получают с помощью функции GetSystemMetrics. Она возвращает метрики и текущие установки конфигурации системы. Метрики системы – это габариты (ширина и высота) отображаемых элементов операционной системы Windows. Все
24
габариты возвращаются в пикселях.
Функция GetSystemMetrics объявлена следующим образом: int GetSystemMetrics (int nIndex).
Параметр nIndex указывает на возвращаемую метрику системы или установку конфигурации. Ниже приводится таблица некоторых имен для этого параметра:
Значение параметра |
Возвращаемая характеристика |
SM_CXMIN |
Минимальная ширина окна |
SM_CYMIN |
Минимальная высота окна |
SM_CXSCREEN |
Ширина экрана |
SM_CYSCREEN |
Высота экрана |
SM_CYCAPTION |
Высота заголовка |
SM_CYMENU |
Высота полосы меню |
Так, следующий оператор определяет ширину экрана: intw=GetSystemMetrics(SM_CXSCREEN).
Следующая функция позволяет получить координаты обрамляющего окно hwnd прямоугольника:
BOOL GetWindowRect( HWND hwnd, LPRECT lpRect);
Параметр lpRect указывает на структуру типа RECT:
typedef struct{ |
|
|
LONG |
left; |
//Левый край |
LONG |
top; |
//Верхний край |
LONG |
right; |
//Правый край |
LONG |
bottom; //Нижний край |
} RECT;
Координаты прямоугольника отсчитываются от левого верхнего угла экрана в пикселях. При успешном выполнении функция возвращает ненулевое значение. Следующий фрагмент демонстрирует получение экранных координат прямоугольника окна:
RECT rc; GetWindowRect(hwnd, &гс);
Функция GetClientRect возвращает координаты прямоугольника, обрамляющего рабочую область окна:
BOOL GetClientRect( HWND hwnd, LPRECT lpRect).
При этом прямоугольник смещен в левый верхний угол экрана, т.е. rc.left=rc.top=0, а значения полей right и bottom равны соответственно ширине и высоте рабочей области.
25
1.6.3. Сообщения приложения для пользователя
Для вывода текстовых сообщений и получения ответа пользователя применяют окно сообщения. Функция MessageBox создает, отображает, обеспечивает работу и закрывает окно
сообщения: |
|
|
|
int WINAPI MessageBox ( |
|
|
|
HWND |
hwnd, |
//Дескриптор родительского окна |
|
LPCTSTR |
lpText, |
//Адрес текста сообщения |
|
LPCTSTR |
lpCaption, |
//Адрес заголовка окна |
|
UINT |
uType |
|
//Стиль окна сообщения |
); |
|
|
|
Если hwnd=NULL, то окно сообщения не имеет родительского окна. При lpCaption = NULL в заголовке по умолчанию выводится строка «Ошибка». Параметр uType задают в виде комбинации флажков, определяющих содержание и поведение окна сообщения.
Следующие флаги определяют список кнопок окна сообщения:
Значение флага |
Список имен кнопок |
MB_ABORTRETRYIGNORE |
«Стоп», «Повтор», «Пропустить» |
МВ_ОК |
ОК |
MB_OKCANCEL |
ОК, «Отмена» |
MB_RETRYCANCEL |
«Повтор», «Отмена» |
MB_YESNO |
«Да», «Нет» |
MB_YESNOCANCEL |
«Да», «Нет» , «Отмена» |
Жирным шрифтом выделены кнопки по умолчанию. По умолчанию активна первая кнопка. Следующие флаги могут назначить одну из кнопок активной по умолчанию:
Значение флага |
Номер кнопки |
Флаг |
Номер кнопки |
MB_DEFBUTTON1 |
Первая |
MB_DEFBUTTON3 |
Третья |
MB_DEFBUTTON2 |
Вторая |
MB_DEFBUTTON4 |
Четвертая |
Следующие флаги включают одну иконку в окно сообщения:
Значение флага |
Вид иконки |
MB_ICONEXCLAMATION, MB_ICONWARNING |
Восклицательный знак |
|
|
MB_ICONINFORMATION, MB_ICONASTERISK |
Символ "i" |
|
|
MB_ICONQUESTION |
Знак вопроса |
MB_ICONSTOP, MB_ICONERROR, |
Знак остановки |
MB_ICONHAND |
|
|
|
26
Следующие флаги определяют стиль окна сообщения:
Значение флага |
Пояснение |
MB_APPLMODAL |
Это стиль по умолчанию. Окно hwnd переводится в |
|
неактивное состояние на время работы окна |
|
сообщения, но можно активизировать другие |
|
приложения или окна, не дочерние по отношению к |
|
hwnd |
|
|
MB_SYSTEMMODAL |
На время работы окна сообщения все другие |
|
приложения в неактивном состоянии |
|
|
MB_TASKMODAL |
Этот стиль подобен MB_APPLMODAL, но если |
|
родительское окно не указано (hwnd= NULL), |
|
блокируются все перекрывающиеся окна этого |
|
приложения |
|
|
MB_HELP |
Добавляет кнопку «Справка» в окне сообщения |
MB_RIGHT |
Текст выравнивается по правому краю |
MB_RTLREADING |
Отображает символы сообщения и текста заголовка |
|
в направлении справа налево |
|
|
MB_SETFOREGROUND |
Окно сообщения выдвигается на передний план |
Приложение может обработать ответ пользователя на сообщение, анализируя возвращаемое функцией MessageBox значение. При ошибке возвращается нуль, иначе функция MessageBox возвращает константу, соответствующую нажатой кнопке. Ниже перечислены имена констант, соответствующие кнопкам окна сообщения:
Имена констант |
Нажатая кнопка |
Имена констант |
Нажатая кнопка |
IDABORT |
«Стоп» |
IDОК |
ОК |
IDCANCEL |
«Отмена» |
IDRETRY |
«Повтор» |
IDIGNORE |
«Пропустить» |
IDYES |
«Да» |
IDNO |
«Нет» |
|
|
Если окно сообщения содержит кнопку «Отмена», то значение IDCANCEL может быть возвращено и при нажатии клавиши Esc.
Операционная система Windows предусматривает возможность выдачи и звуковых «сообщений». Так, при вызове функции MessageBeep компьютер проигрывает «звук» из множества зарегистрированных в системе «звуков». Синтаксис этой функции:
BOOL MessageBeep( UINT uType);
Параметр uType этой функции определяет звуковой тип и принимает одно из следующих значений:
|
27 |
|
|
Значение параметра |
Обозначение параметра в файле win.ini |
|
|
OxFFFFFFFF или -1 |
Стандартный звуковой сигнал |
|
|
MB_ICONASTERISK |
SystemAsterisk |
MB_ICONEXCLAMATION |
SystemExclamation |
|
|
MB_ICONHAND |
SystemHand |
|
|
MB_ICONQUESTION |
SystemQuestion |
МВ_ОК или 0 |
SystemDefault |
|
|
При успешном выполнении функция возвращает ненулевое значение, иначе – нуль. После передачи сообщения о формировании звука, функция MessageBeep прекращает работу. Далее выполняются последующие операторы приложения, и одновременно проигрывается указанный звук.
Если требуется обратить внимание пользователя на определенное окно, то можно несколько раз изменить подсветку окна или его пиктограммы. Для этого используют функцию FlashWindow, которая за один вызов один раз изменяет подсветку указанного окна:
BOOL FlashWindow(
HWND hwnd, //Дескриптор подсвечиваемого окна BOOL blnvert //Параметр подсветки
);
Если параметр bInvert=TRUE, то окно меняет подсветку. Если bInvert=FALSE, то окно только возвращается к исходному состоянию.
При подсветки неактивное окно может принять внешний вид активного окна, но не получит фокуса ввода.
Если окно было активно до вызова FlashWindow, возвращается ненулевое значение. Если окно не было активно, возвращается 0.
Пример. После нажатия левой клавиши мыши над окном hwnd пять раз изменить подсветку неактивного окна OwnedHwnd.
Следующий фрагмент описывает версию решения этой задачи:
case WM_LBUTTONDOWN: { FlashWindow(OwnedHwnd, TRUE); for (int i=0; i<9; i++)
{ for (long j=0;j<1e7;j++); FlashWindow(OwnedHwnd, TRUE);
}
return 0; }
После нажатия левой клавиши мыши окно OwnedHwnd примет
28
вид активного окна: FlashWindow(OwnedHwnd, TRUE);
При i=0 выполняется некая «работа», обозначенная циклом for (long j=0;j<1e7;j++).
Эта работа сводится к простой задержке времени. После этой паузы окно OwnedHwnd примет вид неактивного окна. При i=l после паузы окно OwnedHwnd примет вид активного окна, а при i=2 после паузы окно OwnedHwnd примет вид неактивного окна... Таким образом, окно OwnedHwnd пять раз изменяет свой внешний вид.
1.7. Примеры создания окон
Рассмотрим два примера создания окон.
В первом примере в тело главной функции добавляется фрагмент, который проверяет наличие активного экземпляра приложения и выполняет соответствующие действия. При этом тело функции окна, в которое обычно добавляется текст разработчика, содержит только минимально необходимый набор операторов.
Во втором примере главная функция содержит только присущий подавляющему большинству приложений набор описаний, а функция окна содержит операторы, которые добавляются для решения поставленной задачи.
Тексты (листинги 1.2 и 1.3) приложений содержат одни и те же наборы типовых функций. Отличие лишь в их содержании.
1.7.1. Проверка наличия предыдущего экземпляра
Задача. Окно приложения стиля временного окна с кнопкой минимизации и с фоном цвета рабочего стола Windows занимает весь экран. При попытке запустить второй экземпляр на передний план переместить окно первого экземпляра и завершить работу.
Анализ задачи. (Полный текст приложения приведен в листинге
1.2.)
Для поиска других экземпляров приложения воспользуемся функцией FindWindow:
HWNDhwnd=FindWindow(szMainClass,szTitle).
Она возвращает дескриптор окна класса szMainClass с заголовком szTitle. Если такого окна нет, то это первый экземпляр приложения и дескриптору hwnd присваивается NULL, иначе, возвращается дескриптор определенного окна.
29
Функция FindWindow проверяет только совпадение имени класса и заголовка, т.е. если работает экземпляр другого приложения с окном класса с таким же именем szMainClass и заголовком szTitle, то функция вернет дескриптор окна другого приложения.
Если «предыдущий экземпляр приложения» обнаружен, выводим сообщение:
MessageBox(hwnd,
"Можно запускать только одну копию приложения!!!\n\n"
"Перемещаю на передний план первый экземпляр", szTitle, MB_OK | MB_ICONSTOP);
До перемещения окна на передний план проверяем состояние этого окна и, если оно свернуто, восстанавливаем его предыдущее состояние:
if (IsIconic( hwnd)) ShowWindow( hwnd, SW_RESTORE);
Перемещаем окно первого экземпляра приложения на передний план:
SetForegroundWindow(hwnd);
Затем второй экземпляр приложения завершает работу.
Если предыдущий экземпляр приложения не определен, регистрируем класс окна:
if (!RegClass(WndProc,szMainClass,COLOR_DESKTOP)) return FALSE;
Цвет фона окна приложения определяем по прил. 1, табл. 1.4 – COLOR_DESKTOP.
Для создания максимально распахнутого окна приложения определяем ширину и высоту экрана в пикселях:
int w=GetSystemMetrics(SM_CXSCREEN); int h=GetSystemMetrics(SM_CYSCREEN).
Создаем окно:
hwnd = CreateWindow(szMainClass, szTitle, WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE, 0, 0, w, h, 0, 0, hInstance, NULL);
Стиль временного окна с кнопкой минимизации и заголовком определяем по прил. 1, табл. 1.5 – WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX | WS_VISIBLE.
Далее активизируем цикл обработки и диспетчеризации сообщений:
30 while(GetMessage(&msg, 0,0,0)) DispatchMessage(&msg);
Это приложение не предусматривает обработки сообщений с клавиатуры, поэтому в цикле отсутствует вызов функции трансляции клавиатурных сообщений.
Любые действия над окном передают функции окна:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg)
{ case WM_DESTROY: { PostQuitMessage(0); return 0;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam).
}
Листинг 1.2. Запрет запуска второго экземпляра приложения.
#include <windows.h> //Объявления функций BOOL RegClass(WNDPROC, LPCTSTR, UINT);
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,
|
LPARAM); |
HINSTANCE hInstance; |
|
char |
szMainClass[ ] = "MainClass"; |
char |
szTitle[]= "Пример 1.2"; |
//Главная функция приложения
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow) {
MSG msg; hInstance=hInst;
HWND hwnd=FindWindow(szMainClass,szTitle); if (hwnd)
{
MessageBox(hwnd, "Можно запускать только один экземпляр приложения.", "Перемещаю на передний план первый экземпляр", szTitle, MB_OK | MB_ICONSTOP); //Если окно свернуто, восстанавливаем
if (IsIconic( hwnd)) ShowWindow(hwnd, SW_RESTORE); SetForegroundWindow(hwnd); return 0;
}
if (!RegClass(WndProc,szMainClass,COLOR_DESKTOP))