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

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

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

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

8.5. Полоса просмотра

Полосы просмотра (Scrollbar ) используются в приложениях Presentation Manager для просмотра текста или изображения, которое не помещается в окне. Полосы просмотра бывают горизонтальные или вертикальные. Обычно они располагаются, соответственно, в нижней и правой части окна, хотя вы можете создать окно полосы просмотра в любом месте любого окна вашего приложения.

Полоса просмотра представляет собой орган управления, созданный на базе предопределенного класса WC_SCROLLBAR .

Для создания полосы просмотра вы можете воспользоваться функцией WinCreateWindow, как это мы делали для создания кнопок и переключателей в предыдущих приложениях. Однако если вам необходимо создать полосы просмотра в нижней или левой части окна, то это можно сделать проще: достаточно при создании окна указать функции WinCreateStdWindow флаги FCF_VERTSCROLL (вертикальная полоса проосмотра) и FCF_HORZSCROLL (горизонтальная полоса просмотра).

Горизонтальная и вертикальная полоса просмотра посылает в функцию родительского окна сообщения WM_HSCROLL и WM_VSCROLL , соответственно. Через параметр mp1 этих сообщений передается идентификатор полосы просмотра, через младшее слово параметра mp1 - текущая позиция движка полосы просмотра, а через старшее слово этого же параметра - код операции, выполненной пользователем над полосой просмотра (сдвиг в ту или иную сторону, перемещение ползунка мышью и т. д.).

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

Рис. 8.4. Вертикальная полоса просмотра

Если вы устанавливаете курсор мыши на верхнюю кнопку полосы просмотра (со стрелкой, направленной вверх) и нажимаете левую клавишу мыши, документ сдвигается в окне вниз на одну строку. Если вы выполняете аналогичную операцию с нижней кнопкой полосы просмотра, документ сдвигается на одну строку вверх. Положение движка при этом изменяется соответствующим образом.

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

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

Понятие "страница" и "строка" подходят в основном для текстовых документов. Для описания процесса свертки документов других типов можно использовать другие термины, однако следует заметить, что в любом случае полоса просмотра обеспечивает два типа позиционирования - грубое и точное. Грубое позиционирование выполняется при помощи движка или областей полосы просмотра, расположенных между движком и кнопками со стрелками, точное позиционирование выполняется кнопками, расположенными на концах полосы просмотра. Следует заметить, что понятия "грубое позиционирование" и "точное позиционирование" отражают факт наличия двух типов позиционирования. Вся логика, обеспечивающая свертку окна, выполняется вашим приложением при обработке сообщений, поступающих от полосы просмотра (в том числе, степень чувствительности каждого типа позиционирования).

Горизонтальная полоса просмотра состоит из тех же объектов, что и вертикальная. Она обеспечивает свертку документа в горизонтальном направлении.

Создание полосы просмотра

Как мы уже говорили, существует два способа создания полос просмотра в окне приложения.

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

Использование класса WC_SCROLLBAR

Для создания полосы просмотра с помощью функции WinCreateWindow вы должны в первом параметре функции указать класс окна WC_SCROLLBAR:

#define IDC_SCROLLBAR 100
HWND hWndScroll;
hWndScroll = WinCreateWindow (hWnd, WC_BUTTON ,
  NULL,  // текст указывать не нужно
  WS_VISIBLE  | SBS_VERT,
  0, 0, 0, 0,
  hWnd, HWND_TOP , IDC_SCROLLBAR, NULL, NULL);

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

Четвертый параметр, определяющий стиль окна, наряду с константой WS_VISIBLE должен содержать определение стиля полосы просмотра. Существует четыре стиля для полосы просмотра. Соответствующие символические константы имеют префикс имени SBS_ (например, SBS_HORZ ).

Одиннадцатый параметр функции WinCreateWindow должен задавать идентификатор полосы просмотра.

Стили полосы просмотра

При создании полосы просмотра функцией WinCreateWindow вы можете указать следующие стили:

Стиль Описание
SBS_HORZ Создается горизонтальная полоса просмотра
SBS_VERT Создается вертикальная полоса просмотра
SBS_AUTOTRACK При перемещении движка полосы просмотра, созданной с использованием стиля SBS_AUTOTRACK, перемещается полное изображение движка. Если же этот стиль не указан, перемещается только изображение прямоугольного контура движка, а сам движок будет нарисован в новой позиции только после завершения пользователем операции перемещения
SBS_THUMBSIZE Этот стиль используется для вычисления размера движка

Определение полос просмотра при создании окна

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

Для того чтобы у окна появились вертикальная и горизонтальная полосы просмотра, при создании окна функцией WinCreateStdWindow необходимо указать флаги FCF_VERTSCROLL и FCF_HORZSCROLL (соответственно, для создания вертикальной и горизонтальной полосы просмотра):

HWND hWndFrame;
ULONG flFrameFlags =
  FCF_SYSMENU    | FCF_TITLEBAR      | FCF_MINMAX   |
  FCF_SIZEBORDER | FCF_SHELLPOSITION | FCF_TASKLIST |
  FCF_ICON       | FCF_VERTSCROLL   | FCF_HORZSCROLL ;
hWndFrame = WinCreateStdWindow (HWND_DESKTOP,
  WS_VISIBLE,
  &flFrameFlags, szWndClass, szAppTitle,
  0, 0, ID_APP_FRAMEWND, &hWndClient);

Сообщения от полосы просмотра

Горизонтальные полосы просмотра, определенные для окна (одним из описанных выше способов) посылают в окно сообщение WM_HSCROLL , а все вертикальные - WM_VSCROLL .

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

Опишем параметры сообщений WM_HSCROLL и WM_VSCROLL.

Как мы уже говорили, через параметр mp1 этих сообщений передается идентификатор полосы просмотра, через младшее слово параметра mp1 - текущая позиция движка полосы просмотра, а через старшее слово этого же параметра - код операции, выполненной пользователем над полосой просмотра. Вы можете извлечь перечисленные выше параметры следующим образом:

usidentifier = (USHORT) mp1;      // идентификатор окна
sslider      = SHORT1FROMMP(mp2); // позиция движка
uscmd        = SHORT2FROMMP(mp2); // код операции

Если значение позиции движка равно нулю, то это означает, что либо пользователь так и не переместил движок, либо в случае команды SB_SLIDERPOSITION (которая будет описана ниже) пользователь отпустил клавишу мыши, когда курсор находился вне области полосы просмотра.

Ниже мы перечислим коды команд, которые могут поступать от полос просмотра.

Код комады Описание
SB_LINELEFT Пользователь сделал щелчок мышью по левой кнопке горизонтальной полосы просмотра. Значение позиции полосы просмотра уменьшается на единицу
SB_LINERIGHT Аналогично предыдущему, но по правой кнопке. Значение позиции полосы просмотра увеличивается на единицу
SB_PAGELEFT Пользователь сделал щелчок по полосе просмотра слева от движка
SB_PAGERIGHT Аналогично предыдущему, но щелчок сделан справа от движка
SB_LINEUP Пользователь сделал щелчок мышью по верхней кнопке горизонтальной полосы просмотра. Значение позиции полосы просмотра уменьшается на единицу
SB_LINEDOWN Аналогично предыдущему, но щелчок сделан по нижней кнопке полосы просмотра. Значение позиции полосы просмотра увеличивается на единицу
SB_SLIDERPOSITION Движок установлен в конечную позицию
SB_SLIDERTRACK Сообщение с этим кодом непрерывно поступает в процессе перемещения движка полосы просмотра при помощи мыши
SB_ENDSCROLL Сообщение с кодом SB_ENDSCROLL посылается в том случае, если пользователь завершил перемещение движка полосы просмотра

Обычно в приложениях Presentation Manager организуется управление полосами просмотра при помощи клавиатуры. Для управления движком полосы просмотра при этом используются клавиши перемещения курсора и клавиши <PgUp>, <PgDn>, <Home> и <End>. Как правило, с помощью клавиш <Home> и <End> вы можете перейти, соответственно, в начало и в конец документа.

Так как действия, выполняемые при работе с движком, одинаковы для полосы просмотра и дублирующих ее клавиш, имеет смысл предусмотреть единый обработчик сообщений от полосы просмотра. Для добавления клавиатурного интерфейса обработчик клавиатурного сообщения WM_CHAR может посылать в функцию окна сообщения полосы просмотра. Например, если обработчик сообщения WM_CHAR обнаружил, что вы нажали клавишу <PgUp>, он может послать в функцию окна сообщение WM_VSCROLL с кодом, равным SB_PAGEUP. Результат будет в точности такой же, как будто для свертки документа на одну страницу вверх вы воспользовались полосой просмотра, а не клавиатурой.

Такой подход позволяет локализовать всю логику свертки в обработчике сообщений полосы просмотра. При этом сильно упрощается процедура подключения клавиатурного интерфейса - обработчик клавиатурного сообщения WM_CHAR должен послать в функцию окна сообщение полосы просмотра, соответствующее коду нажатой клавиши. Но ему не надо дублировать действия обработчиков сообщений WM_VSCROLL и WM_HSCROLL.

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

Клавиша Код извещения
Перемещение курсора вверх SB_LINEUP или SB_LINELEFT (эти значения равны)
- // - влево SB_LINEUP или SB_LINELEFT
- // - вниз SB_LINEDOWN или SB_LINERIGHT
- // - вправо SB_LINEDOWN или SB_LINERIGHT
<Page Up> SB_PAGEUP или SB_PAGELEFT
<Page Down> SB_PAGEDOWN или SB_PAGERIGHT

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

Клавиша Код извещения
Перемещение курсора вверх SB_LINEUP
- // - влево SB_LINELEFT
- // - вниз SB_LINEDOWN
- // - вправо SB_LINERIGHT
<Page Up> SB_PAGEUP
<Page Down> SB_PAGEDOWN
<Home> SB_SLIDERTRACK (установлена минимальная позиция)
<End> SB_SLIDERTRACK (установлена максимальная позиция)
<Ctrl + Home> SB_SLIDERTRACK (установлена минимальная позиция)
<Ctrl + End> SB_SLIDERTRACK (установлена максимальная позиция)
<Ctrl + Up> SB_SLIDERTRACK (установлена минимальная позиция). Используется для вертикальной полосы просмотра
<Ctrl + Down> SB_SLIDERTRACK (установлена максимальная позиция). Используется для вертикальной полосы просмотра
<F7> SB_PAGEUP
<F8> SB_PAGEDOWN
<Ctrl + Page Up> SB_PAGELEFT
<Ctrl + Page Down> SB_PAGERIGHT

Инициализация полосы просмотра

Для полосы просмотра определены понятия текущая позиция и диапазон изменения значений позиции. При передвижении движка вдоль полосы просмотра текущая позиция принимает дискретные значения внутри диапазона изменения значений позиции. Если движок находится в самом левом (для горизонтальной полосы просмотра) или самом верхнем (для вертикальной полосы просмотра) положении, текущая позиция равна минимальной. Если же движок находится в самом правом или самом нижнем положении, текущая позиция равна максимальной.

После того как вы создали полосу просмотра одним из описанных выше способов, ее необходимо проинициализировать, указав диапазон изменений значений позиции. И то, и другое можно сделать, передав окну полосы просмотра сообщение SBM_SETSCROLLBAR , например, так:

WinSendMsg(hwndYScroll,
  SBM_SETSCROLLBAR, (MPARAM)0, MPFROM2SHORT(0, YSIZE));
WinSendMsg(hwndXScroll,
  SBM_SETSCROLLBAR, (MPARAM)0, MPFROM2SHORT(0, XSIZE));

Здесь мы устанавливаем текущую позицию и диапазон изменения значений для вертикальной и горизонтальной полосы просмотра с идентификаторами окон hwndYScroll и hwndXScroll, соответственно.

Прежде чем мы подробно опишем параметры сообщения SBM_SETSCROLLBAR , сделаем одно замечание относительно идентификатора окна полосы просмотра, которое должно использоваться при передаче сообщений этому органу управления.

Если полоса просмотра создавалась функцией WinCreateWindow, то для передачи сообщений полосе вы должны использовать идентификатор окна, полученный от этой функции. Если же полоса просмотра создавалась при помощи флагов FCF_VERTSCROLL или FCF_HORZSCROLL , для получения идентификатора этой полосы вам необходимо воспользоваться функциями WinWindowFromID и WinQueryWindow, как это показано ниже:

hwndYScroll = WinWindowFromID(
  WinQueryWindow(hWnd, QW_PARENT), FID_VERTSCROLL),
hwndXScroll = WinWindowFromID(
  WinQueryWindow(hWnd, QW_PARENT), FID_HORZSCROLL),

Полосы просмотра, создаваемые как дочерние для окна Frame Window, имеют идентификаторы FID_VERTSCROLL (вертикальная полоса просмотра) и FID_HORZSCROLL (горизонтальная полоса просмотра). Для получения идентификатора окна этих полос вы должны передать указанные значения в качестве второго параметра функции WinWindowFromID . Что же касается первого параметра этой функции, то через него следует передать идентификатор родительского окна.

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

Итак, опишем параметры сообщения SBM_SETSCROLLBAR , предназначенного для установки позиции и диапазона изменений значений позиции.

Параметр mp1 задает новое значение позиции движка. Это значение должно лежать в пределах от минимального, определяемого младшим словом параметра mp2, и максимального, которое задается старшим словом этого же параметра.

В приведенном выше примере мы устанавливали для вертикальной полосы просмотра диапазон изменения значений от 0 до YSIZE, причем начальное значение было равно нулю. Это соответствует расположению движка в верхней части полосы просмотра.

Управление полосой просмотра

Если вам нужно установить только новую позицию движка, оставив прежним диапазон изменения значений, воспользуйтесь сообщением SBM_SETPOS :

WinSendMsg(hwndYScroll, 
  SBM_SETPOS, (MPARAM)10, (MPARAM)NULL);

Новое значение позиции вы должны передать с параметром mp1 этого сообщения. Параметр mp2 не используется и должен быть равен нулю.

Определение параметров полосы просмотра

Для того чтобы узнать текущее положение движка, окну полосы просмотра необходимо послать сообщение SBM_QUERYPOS , например:

USHORT usSliderPos;
usSliderPos = (USHORT)WinSendMsg(hwndYScroll,
  SBM_QUERYPOS, (MPARAM) NULL, (MPARAM) NULL);

Функция WinSendMsg возвратит искомое значение текущей позиции.

Для определения текущего диапазона изменения позиции окну полосы просмотра необходимо послать сообщение SBM_QUERYRANGE , например, так:

USHORT  usMinimum, usMaximum;
MRESULT mResult;
mResult = WinSendMsg(hwndYScroll, 
  SBM_QUERYRANGE, (MPARAM) NULL, (MPARAM) NULL);
usMinimum = SHORT1FROMMR(mResult); // минимальная позиция
usMaximum = SHORT2FROMMR(mResult); // максимальная позиция

Минимальная и максимальная позиции передаются, соответственно, через младшее и старшее слово, возвращаемое функцией WinSendMsg.

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