Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Программирование для IBM OS/2

© Александр Фролов, Григорий Фролов
Том 25, М.: Диалог-МИФИ, 1993, 286 стр.

[Назад] [Содеожание] [Дальше]

8.1. Кнопки

Работая в среде Workplace Shell с приложениями Presentation Manager, вы имели дело с кнопками и переключателями. Последние бывают квадратной либо круглой формы. Переключатели создаются на базе того же самого предопределенного класса окна, что и кнопки прямоугольной формы с надписанным на них текстом или нарисованным графическим изображением.

Для создания кнопки или переключателя (а так же других органов управления) используется функция WinCreateWindow . Кнопка создается на базе предопределенного класса окна WC_BUTTON , например, следующим образом:

hWndButton = WinCreateWindow (hWnd, WC_BUTTON ,
  "Кнопка", WS_VISIBLE  | BS_PUSHBUTTON,
  0, 0, 0, 0,
  hWnd, HWND_TOP , BTN1_ID, NULL, NULL);

Заметим, что здесь используется именно функция WinCreateWindow , а не функция WinCreateStdWindow , при помощи которой мы создаем главное окно приложения. Эта функция может быть использована для создания дочернего окна на базе зарегистрированного вами класса.

Функция WinCreateWindow

Приведем прототип функции WinCreateWindow , предназначенной для создания окон (и, в частности, окон органов управления):

HWND WinCreateWindow (
  HWND hwndParent,       // родительское окно
  PSZ pszClass,          // имя класса
  PSZ pszName,           // заголовок окна
  ULONG flStyle,         // стиль класса окна
  LONG x,                // координата по оси X
  LONG y,                // координата по оси Y
  LONG cx,               // ширина
  LONG cy,               // высота
  HWND hwndOwner,        // окно-владелец
  HWND hwndInsertBehind, // окно-брат, за которым 
                         // отображается окно
  ULONG id,              // идентификатор окна
  PVOID pCtlData,        // управляющие данные
  PVOID pPresParams);    // параметры отображения

В качестве параметра hwndParent вы должны указать идентификатор дочернего окна.

Параметр pszClass определяет имя класса, на базе которого создается окно. Для кнопки здесь необходимо указать имя WC_BUTTON .

Параметр pszName задает текст для окна. Если создается кнопка, то это тот самый текст, который будет написан на кнопке.

С помощью параметра flStyle можно указать стиль класса окна, определяющий поведение и внешний вид окон, создаваемых на базе этого класса. Этот параметр мы опишем немного позже.

Расположение окна и его размеры определяется параметрами x (координата по оси X), y (координата по оси Y), cx (ширина), cy (высота).

Параметр hwndOwner определяет идентификатор окна-владельца, которое будет получать извещающие сообщения от создаваемого дочернего окна. Если вы создаете кнопку, то сообщения, возникающие при ее нажатии, будут передаваться именно в это окно.

Через параметр hwndInsertBehind передается идентификатор братского (или сестринского, что одно и то же) окна, за которым будет нарисовано создаваемое окно. Вы можете также указать константы HWND_TOP или HWND_BOTTOM . В первом случае создаваемое окно окажется наверху, во втором - за всеми остальными братскими окнами.

Идентификатор, передаваемый через параметр id, играет важную роль при обработке сообщений, поступающих в окно, владеющее создаваемым дочерним окном. Анализируя этот идентификатор, функция окна может определить, от какого окна поступило сообщение. Поэтому если окно создает несколько дочерних окон, каждое из них должно иметь свой идентификатор.

При помощи параметра pCtlData (указатель) вы можете передать данные функции создаваемого дочернего окна. Этот указатель будет передан в параметре mp1 сообщения WM_CREATE , поступающего в функцию дочернего окна при его создании.

Аналогично, данные, передаваемые через параметр pPresParams, также попадают в функцию дочернего окна через параметр mp2 сообщения WM_CREATE . Для того чтобы понять, как использовать параметр pPresParams, опишем подробнее параметры сообщения WM_CREATE.

Сообщение WM_CREATE

Как вы уже знаете, сообщение WM_CREATE передается функции окна при его создании. Параметр mp1 этого сообщения содержит значение параметра pCtlData, переданного в функцию WinCreateWindow .

В параметр mp2 при этом записывается указатель на следующую структуру:

typedef struct _CREATESTRUCT 
{
 PVOID   pPresParams;  // параметры отображения
 PVOID   pCtlData;     // управляющие данные
 ULONG   id;           // идентификатор окна
 HWND    hwndInsertBehind;  // окно-брат, за которым
                            // отображается окно
 HWND    hwndOwner;    // окно-владелец
 LONG    cy;           // высота окна
 LONG    cx;           // ширина окна
 LONG    y;            // координата по оси Y
 LONG    x;            // координата по оси X
 ULONG   flStyle;      // стиль окна
 PSZ     pszText;      // заголовок окна
 PSZ     pszClassName; // имя класса
 HWND    hwndParent;   // родительское окно
} CREATESTRUCT;
typedef CREATESTRUCT *PCREATESTRUCT;

Нетрудно заметить, что поля этой структуры повторяют аналогичные параметры функции WinCreateWindow . Анализируя поля структуры CREATESTRUCT, обработчик сообщения WM_CREATE может проверить параметры создаваемого окна.

Если эти параметры верны, обработчик может вернуть значение FALSE, что разрешает создание окна. Если же один или несколько параметров имеют неправильное знчение, функция окна может вернуть значение TRUE. Окно при этом создано не будет, а функция WinCreateWindow вернет значение NULLHANDLE.

Стили кнопок

Параметр flStyle определяет стиль класса окна, влияющий на поведение и внешний вид окон, создаваемых на базе этого класса. Для кнопок и переключателей помимо стилей с префиксом WS_, описанных в начале нашей книги, можно указывать следующие стили (некоторые стили можно комбинировать при помощи логической операции ИЛИ, о чем будет сказано дополнительно):

Стиль Описание
BS_PUSHBUTTON Кнопка в виде прямоугольника с текстом. Когда пользователь нажимает эту кнопку, родительское окно получает извещающее сообщение
BS_DEFAULT Кнопка с толстой рамкой. В диалоговых панелях вместо этой кнопки пользователь может нажать клавишу <Enter>. Этот стиль можно использовать вместе со стилями BS_PUSHBUTTON и BS_USERBUTTON
BS_CHECKBOX Переключатель квадратной формы, который может находиться в одном из двух состояний: включенном (внутри квадрата отображается галочка) или выключенном (без галочки). Справа от квадрата находится подпись (текст заголовка)
BS_AUTOCHECKBOX Аналогично предыдущему, но внешний вид при переключении изменяется автоматически
BS_RADIOBUTTON Аналогично BS_CHECKBOX, но переключатель имеет круглую форму. Во включенном состоянии внутри круга отображается жирная точка
BS_AUTORADIOBUTTON Аналогично предыдущему, но внешний вид при переключении изменяется автоматически. Обычно используется в диалоговых панелях в составе группы аналогичных переключателей, при этом во время включения одного из переключателей остальные автоматически выключаются
BS_AUTOSIZE Размер кнопки, создаваемой с этим стилем, изменяется автоматически таким образом, чтобы надпись всегда помещалась на ней целиком. При создании окна с этим стилем функции WinCreateWindow в качестве параметров cx или cy можно указывать значение -1
BS_3STATE Прямоугольная кнопка с автоматическим переключением, которая может находиться в трех состояниях: внутри квадрата отображается маленький черный квадратик (включен), черный квадратик не отображается (выключен), переключатель отображается серым цветом (переключатель не активен)
BS_AUTO3STATE Аналогично предыдущему, но изображение изменяется автоматически при переключении
BS_BITMAP Вместо текста на поверхности кнопки рисуется растровое изображение. Этот стиль можно использовать только вместе со стилем BS_PUSHBUTTON
BS_HELP Когда пользователь нажимает кнопку с этим стилем, родительское окно вместо сообщения WM_COMMAND получает сообщение с кодом WM_HELP . Этот стиль можно использовать вместе со стилем BS_PUSHBUTTON
BS_ICON Вместо текста на поверхности кнопки рисуется пиктограмма. Этот стиль можно использовать только вместе со стилем BS_PUSHBUTTON
BS_MINIICON Аналогично предыдущему, но на поверхности кнопки можно размещать пиктограммы уменьшенного размера
BS_NOBORDER Кнопка не имеет рамки. Этот стиль можно использовать только вместе со стилем BS_PUSHBUTTON
BS_NOCURSORSELECT Круглая кнопка, которая не выбирается после получения фокуса ввода в результате использования клавиш перемещения курсора или табуляции (стиль используется в диалоговых панелях) . Этот стиль можно использовать только вместе со стилем BS_AUTORADIOBUTTON
BS_NOPOINTERFOCUS Круглая кнопка, которая не выбирается щелчком мыши. В результате курсор останется в том поле, в котором требуется ввести информацию (стиль используется в диалоговых панелях). Этот стиль можно комбинировать со всеми другими стилями
BS_SYSCOMMAND Вместо сообщения WM_COMMAND кнопка с этим стилем посылает родительскому окну извещающее сообщение WM_SYSCOMMAND . Этот стиль можно использовать только вместе со стилем BS_PUSHBUTTON
BS_TEXT На поверхности кнопки может отображаться текст вместе с пиктограммой (обычной или уменьшенной), или с растровым изображением. Этот стиль можно использовать вместе со стилем BS_PUSHBUTTON. Кроме того, необходимо указать стили BS_BITMAP, BS_ICON или BS_MINIICON
BS_USERBUTTON Внешний вид кнопки определяется приложением

Установка размеров и расположения кнопки

Начальные размеры и расположение кнопки задаются при ее создании функцией WinCreateWindow . Однако если кнопка расположена не в диалоговой панели, а на поверхности обычного окна приложения, размещение кнопок следует выполнять при обработке сообщения WM_SIZE , например, так:

case WM_SIZE :
{
  WinSetWindowPos (hWndButton, HWND_TOP ,
    10, 10, 200, 50, 
    SWP _SIZE  | SWP_MOVE  | SWP_ZORDER );

  WinInvalidateRect (hWnd, NULL, TRUE);
  return 0;
}

Пользователь может изменять размеры окна, при этом, если не заботиться о стирании содержимого окна, он увидит в нем несколько одинаковых кнопок. Функция WinInvalidateRect в приведенном выше фрагменте кода вызывает перерисовку окна hWnd приложения, создавшего в этом окне кнопку hWndButton.

Извещение от кнопки

Когда пользователь нажмает на кнопку (или изменяет состояние переключателя), окно-владелец кнопки (идентификатор которого был указан в параметрах функции WinCreateWindow ) получает извещающее сообщение.

Код этого сообщения зависит от стиля кнопки. Если не указаны стили BS_SYSCOMMAND или BS_HELP, извещение посылается в виде сообщения WM_COMMAND . Если же указаны перечисленные выше стили, вместо сообщения WM_COMMAND посылаются, соответственно, сообщения WM_SYSCOMMAND или WM_HELP .

Что же касается переключателей, то они посылают извещение в форме сообщения WM_CONTROL , которое мы рассмотрим в разделе "Переключатели".

Через параметр mp1 сообщения WM_COMMAND передается идентификатор органа управления. Однако вспомним, что сообщение WM_COMMAND посылает также меню приложения. Для того чтобы различить источник извещающего сообщения WM_COMMAND, необходимо проанализировать параметр mp2.

Младшее слово параметра mp2 содержит искомый идентификатор источника сообщения и может принимать одно из перечисленных ниже значений:

Значение Описание
CMDSRC_PUSHBUTTON Извещающее сообщение WM_COMMAND посылается кнопкой, идентификатор которой передается через параметр mp1
CMDSRC_MENU Источником сообщения является меню, идентификатор которого передается через параметр mp1
CMDSRC_ACCELERATOR Сообщение пришло от акселератора с командным значением mp1
CMDSRC_FONTDLG Источником сообщения является диалоговая панель для выбора шрифта. Через параметр mp1 передается идентификатор этой диалоговой панели
CMDSRC_FILEDLG Источником сообщения является диалоговая панель для выбора файла. Через параметр mp1 передается идентификатор этой диалоговой панели
CMDSRC_OTHER Прочий источник сообщения

Старшее слово параметра mp2 сообщения WM_COMMAND может содержать значение TRUE или FALSE. В первом случае извещение появилось в результате работы с органом управления при помощи мыши, во втором - при помощи клавиатуры.

Для того чтобы было удобнее разбирать параметры сообщения WM_COMMAND , в файле pmwin.h определена структура CMDMSG, указатель на нее PCMDMSG и макрокоманда COMMANDMSG:

typedef struct _COMMANDMSG
{
  USHORT cmd;    // идентификатор органа управления
  USHORT unused; // не используется
  USHORT source; // источник извещающего сообщения
  USHORT fMouse; // признак использования мыши
} CMDMSG;
typedef CMDMSG *PCMDMSG;

#define COMMANDMSG(pmsg) \
  ((PCMDMSG)((PBYTE)pmsg + sizeof(MPARAM)))

Обработчик сообщения WM_COMMAND обычно имеет такой вид:

case WM_COMMAND :
{
  switch (COMMANDMSG(&msg) -> cmd)
  {
    case BTN1_ID:
    {
       // Обработка извещения от кнопки BTN1_ID
         . . .
       break;
    }
    case BTN2_ID:
    {
       // Обработка извещения от кнопки BTN2_ID
         . . .
       break;
    }
    default:
       break;
  }
  return 0;
}

Если сообщение WM_COMMAND может поступать как от меню, так и от кнопок (или других органов управления), необходимо дополнительно анализировать источник сообщения, например, следующим способом:

if(COMMANDMSG (&msg) -> source == CMDSRC_PUSHBUTTON)
{
  // Сообщение от кнопки
  . . .
}
else if(COMMANDMSG(&msg) -> source == CMDSRC_MENU)
{
  // Сообщение от меню
  . . .
}

Для извлечения параметров кнопки вы можете также использовать макрокоманды SHORT1FROMMP и SHORT2FROMMP :

cmd    = SHORT1FROMMP (mp1);
source = SHORT1FROMMP (mp2);
fMouse = SHORT1FROMMP (mp2);

Сообщения WM_SYSCOMMAND и WM_HELP

Родительское окно может получать извещения от органов управления в форме сообщений WM_SYSCOMMAND или WM_HELP . Первое из этих сообщений приходит, например, когда пользователь нажимает комбинацию клавиш, соответствующую акселератору меню. Сообщение WM_HELP используется приложениями для работы со справочной системой, которую мы опишем в одной из следующих книг "Библиотеки системного программиста", посвященной программированию для IBM OS/2.

Что же касается параметров этих сообщений, то они полностью идентичны параметрам сообщения WM_COMMAND . Поэтому для извлечения этих параметров вы можете использовать описанную ранее макрокоманду COMMANDMSG .

Управление кнопками

Приложение при необходимости может управлять состоянием кнопок, блокируя или разблокируя их, а также изменяя состояние кнопок.

Для блокировки кнопки необходимо использовать функцию WinEnableWindow, которая имеет следующий прототип:

BOOL WinEnableWindow(
  HWND hwnd,         // идентификатор окна
  BOOL fNewEnabled); // новое состояние

Через параметр hwnd вы должны передать этой функции идентификатор окна кнопки. Обращаем внимание, что это идентификатор окна кнопки, который возвращается функцией WinCreateWindow при создании кнопки, а не идентификатор кнопки, передаваемый этой же функции в качестве одного из параметров.

Параметр fNewEnabled определяет новое состояние кнопки. Если он равен TRUE, кнопка разблокируется, а если FALSE - блокируется.

Заблокированную кнопку нельзя нажать ни мышью, ни при помощи клавиатуры (если такая кнопка имеет фокус ввода). Надпись на заблокированной кнопке отображается серым цветом.

Когда состояние кнопки меняется, родительское окно получает сообщение WM_ENABLE. Параметр mp1 этого сообщения указывает новое состояние кнопки и может принимать те же значения, что и описанный только что параметр fNewEnabled функции WinEnableWindow. Параметр mp2 не используется.

Сообщение WM_ENABLE - это извещение родительского окна об изменении состояния кнопки. В ответ на это извещение родительское окно может выполнить какие-либо действия, связанные с тем, что данная кнопка оказалась заблокированной или наоборот, разблокированной.

[Назад] [Содеожание] [Дальше]