winlib.f  Оконная библиотека: окна

WinLib - Окна и общая функциональность
WinCtl - Элементы управления
WinCC - Новые элементы управления
Список исправлений и дополнений

1. Предисловие
2. Общая организация библиотеки
3. Окна
       Создание и уничтожение окон
       Стандартные окна
       Свойства, общие для всех окон
       Свойства, специфичные для перекрывающихся окон
       Операции над окнами
4. Сообщения
       Посылка сообщений
       Обработка сообщений
5. Меню
       Описание меню
       Работа с меню
6. Быстрые клавиши
7. Окна сообщений
8. Шрифты
9. Разное
       Цвета
       Прочее

1. Предисловие

Благодаря усилиям многих программистов, СП-Форт стал стабильной и удобной системой разработки 32-разрядных приложений. Однако в нем имеется существенный пробел: программы с графическим интерфейсом разрабатывать достаточно неудобно. Можно, конечно, напрямую вызывать Windows API, но это долгий и чреватый ошибками путь. Сам API сделан некрасиво (чего стоит один вызов создания окна с 12 (!) аргументами) и имеет сильный уклон в сторону языка Си. Настоящая библиотека ставит своей целью если и не до конца скрыть вызов системных функций (в полном объеме, не ограничив существенно свободу программиста, сделать это нельзя), то хотя бы замаскировать самые одиозные места.

Поскольку я не люблю объектно-ориентированное программирование, считая его уместным лишь в некоторых специализированных задачах, постольку и библиотека далека по своим концепциям от MFC. Во время написания я вдохновлялся идеями графической среды Tcl/Tk и своей предыдущей работой Blank.

Так как библиотека получилась достаточно большой, она разделена на три отдельных уровня, чтобы уменьшить размер программ, для которых не нужна полная функциональность. В первую часть (WinLib) входит базовая работа с окнами: создание, уничтожение, обработка сообщений, меню, быстрые клавиши. Вторая часть (WinCtl) содержит средства создания элементов управления и их автоматическое размещение в окне; третья часть (WinCC) - работу с общими элементами управления (то есть, новыми, введенными в Windows 95 и выше).

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


2. Общая организация библиотеки

Библиотека в большой степени базируется на специальных структурах-таблицах. Окна и элементы управления представляются такими таблицами - по большому счету, списками свойств. Часть свойств могут быть прочитаны и записаны, некоторые - только записаны. Свойство -prop читается словом -prop@ и записывается словом -prop!.

Таблицы являются пассивными элементами - все операции над ними выполняют процедуры-слова. В дальнейшем тексте такие таблицы для упрощения будут называться просто окнами и обозначаться в стековой нотации как win. Не путайте их с системными дескрипторами окон (hwnd).

В библиотеке используются в основном value-переменные. Поэтому в описании под словом "переменные" будут подразумеваться именно они, если не будет оговорено иное. Они будут указываться без стековой нотации.

Инициализацию библиотеки проводит слово WINDOWS.... После него объявляются окна и производится запуск системы выборки сообщений словом ...WINDOWS. Управление вернется после закрытия главного окна программы.

3. Окна

Создание и уничтожение окон

create-window ( winparent -- win/0 )

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

dialog-window ( winparent -- win/0 )

Создает стандартное диалоговое окно - немасштабируемое, только с кнопкой "закрыть".

tool-window ( winparent -- win/0 )

Создает стандартное окно-палитру - с узким заголовком, без кнопок.

create-window-with-styles ( winparent style exstyle -- win/0 )

Создает окно любого вида. Передаются стиль окна (константы WS_xxx) и расширенный стиль окна (WS_Ex_xxx).

destroy-window ( win -- )

Уничтожает указанное окно. Перед уничтожением окну посылается сообщение wm_destroy.

Cтандартные окна

winmain

Переменная, в которой хранится главное окно программы. Занести его туда вы должны самостоятельно, сразу после создания главного окна. Окно winmain обладает следующими свойствами: а) оно служит родителем модальных диалоговых окон и окон сообщений; б) к нему подключается меню программы; в) при его закрытии заканчивается цикл выборки сообщений окна и управление передается за слово ...WINDOWS для завершения программы.

current-window

Последнее созданное окно.

Свойства, общие для всех окон

-hwnd

Системный дескриптор окна. Часто требуется для прямого вызова функций Windows, не предусмотренных в библиотеке.

-style

Стиль окна. Свойство можно читать и записывать.
Многие стили окна фиксируются системой при его создании и в дальнейшем их изменить нельзя.

-color

Цвет текста окна. См. раздел Цвета.

-bgcolor

Цвет фона окна. См. раздел Цвета.

-bgbrush

Кисть для закрашивания фона окна. Если ваше окно просто закрашивается каким-нибудь цветом, это свойство лучше не трогать. Оно полезно, если вы хотите какой-нибудь необыкновенный эффект типа полосатого окна или окна с фоном. Делается это примерно так: \ уничтожаем стандартную кисть
w -bgbrush@ DeleteObject DROP
\ заносим новую
blue >bgr W: hs_horizontal CreateHatchBrush w -bgbrush!

-xsize, -ysize

Размеры окна. Для перекрывающихся окон здесь указывается размер лишь клиентской части окна. Эти свойства можно только читать. Для изменения размеров пользуйтесь словами winresize или ctlresize.

-parent

Родитель окна, если таковой имеется.

-text

Текст, присвоенный окну. Для перекрывающихся окон - это текст заголовка, для элементов управления - обычно текст надписи. Максимальный размер этого текста - 255 байтов. Чтение текста производится в буфер следующим образом: -text@ ( a win -- ). Кстати, длину текста можно узнать заранее с помощью слова -text# ( ctl -- n)

-dialog

Флаг. Если он установлен, в окне будут работать стандартные клавиши перемещения по элементам диалога (Tab, Shift+Tab, стрелки).

Свойства, специфичные для перекрывающихся окон

-icon, -smicon

Большая и маленькая иконки, присвоенные окну. По умолчанию ставятся иконки 1 и 2 из ресурсов исполняемого файла.

-painter

Процедура отрисовки окна. При вызове в переменной windc хранится контекст устройства рисования, в переменной paint-rect - координаты прямоугольника, подлежащего отрисовке. Фон окна в этой процедуре рисовать не нужно - к моменту вызова он уже закрашен нужным цветом или кистью.

-wndproc

Список (MESSAGES:...MESSAGES;) обработчиков сообщений окна. Вызывается после системной обработки. Можно пользоваться следующими переменными: thiswin - окно, к которому пришло сообщение, hwnd - дескриптор этого окна, wparam, lparam - параметры сообщения.

-pre

Список (MESSAGES:...MESSAGES;) обработчиков сообщений окна. Вызывается перед системными обработчиками. Рекомендуется использовать только при крайней необходимости, отдавая предпочтение -wndproc, поскольку можно легко нарушить стандартную обработку.

-hscroll, -vscroll

Список обработчиков сообщений от полос прокрутки окна. Полосы прокрутки окна могут быть включены функцией ShowScrollBar.

-userdata

Пользовательские данные, связанные с окном. Библиотека это поле никак не использует.

Операции над окнами

winshow ( win -- )

Показать окно.

winhide ( win -- )

Спрятать окно.

winminimize ( win -- )

Свернуть окно.

winmaximize ( win -- )

Развернуть окно до максимального размера.

winrestore ( win -- )

Восстановить размер окна.

windisable ( win -- )

Запретить работу окна. Запрещенное окно не принимает ввод от пользователя.

winenable ( win -- )

Разрешить работу окна.

winfocus ( win -- )

Установить на окно фокус ввода.

winmove ( x y win -- )

Переместить окно в указанную точку. Координаты измеряются в пикселях от левого верхнего угла экрана - для окон верхнего уровня - или клиентской области родительского окна.

winresize ( w h win -- )

Изменить размер окна. Слово работает только для перекрывающихся окон, w и h - размер новой клиентской области окна. Для элементов управления используйте ctlresize.

Для обыкновенных (не диалоговых) окон Windows почему-то не выдерживает размер окна по горизонтали. Можно гарантировать только, что новый размер окна будет не меньше запрошенного. При запросе ширины окна в 100 точек система может установить 104, 106 и даже 112 - в зависимости от фаз Луны. Размер окон с фиксированной границей выдерживается правильно.

wincenter ( win -- )

Расположить окно в центре экрана (для окон верхнего уровня) или в центре родительского окна (для остальных)


4. Сообщения

Посылка сообщений

send ( wparam lparam msg win -- result )

Послать окну сообщение msg с указанными параметрами и вернуть результат.

?send ( win msg -- result )

Послать окну сообщение msg с параметрами 0, 0

wsend ( wparam win msg -- result )

Послать окну сообщение msg с параметрами wparam и lparam=0

lsend ( lparam win msg -- result )

Послать окну сообщение msg с параметрами wparam=0 и lparam

send-to-window ( wparam lparam msg hwnd -- result )

Послать окну с дескриптором hwnd сообщение msg с указанными параметрами и вернуть результат.

Обработка сообщений

Обработчики сообщений группируются в списки обработчиков. Каждый обработчик должен при завершении своей работы вернуть флаг, показывающий, обработал он данное сообщение или нет. Любое перекрывающееся окно может обрабатывать сообщения до обработки библиотекой (свойство окна -pre), после обработки (свойство -wndproc), а также сообщения от полос прокрутки. Все эти сообщения описываются единообразно.

MESSAGES: "name"

Начать список сообщений с именем name.

MESSAGES; ( -- )

Закончить список сообщений.

M: ( ->bl)

Начать обработчик сообщения message (константы WM_xxx).

M; ( result -- )

Завершить обработчик сообщения. Если обработчик оставил на стеке FALSE, сообщение считается необработанным и продолжается поиск следующих обработчиков. Если TRUE - сообщение обработано и Windows возвращается в качестве результата 0 или значение, предварительно установленное словом RETURN.

RETURN ( code -- )

Устанавливает код возврата из обработчика сообщения.


4. Меню

Описание меню

MENU: ( ->bl; -- )

Начать описание меню.

MENU; ( -- )

Закончить описание меню.

MENUITEM ( ->eol; xt -- )

Вставить в меню новый пункт. При выборе этого пункта будет выполнено слово xt.

SUBMENU ( ->bl; menu -- )

Вставить указанное меню как подменю.

LINE ( -- )

Вставить в меню разделительную линию.

CHECKED ( -- )

Текущий пункт меню будет отмечен.

DISABLED ( -- )

Текущий пункт меню будет отключен.

MENU: mainmenu
['] file MENUITEM &Файл
LINE
\ в следующем пункте указывается заодно и горячая клавиша. Впрочем,
\ она будет только прописана в соответствующем месте меню. Чтобы по
\ Ctrl+O действительно что-то вызывалось, не забудьте добавить в таблицу
\ горячих клавиш ['] proc ONKEY ctrl+vk_O

['] open MENUITEM &Открыть файл...\tCtrl+O
MENU;

Работа с меню

attach-menubar ( menu win -- )

Присоединить меню к указанному окну.

detach-menubar ( win -- )

Отсоединить от окна меню.

show-menu ( menu x y -- )

Показать раскрывающееся меню menu в точке с указанным экранными координатами. Слово возвращает управление после того, как пользователь выберет какой-нибудь пункт меню или закроет его. show-menu работает только при установленном главном окне (winmain).

default-menu-item ( no menu -- )

Сделать пункт меню с указанным номером пунктом, выбираемым по умолчанию. В этом и следующих словах номера пунктов меню отсчитываются от нуля.

enable-menu-item ( no menu -- )

Включить указанный пункт меню.

disable-menu-item ( no menu -- )

Отключить указанный пункт меню.

check-menu-item ( no menu -- )

Отметить указанный пункт меню.

uncheck-menu-item ( no menu -- )

Убрать отметку с указанного пункта меню.

(un)check-me ( -- ?)

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

check-menu-radio ( firstno lastno no menu -- )

Устанавливает отметку на пункт меню номер no. Отметки со всех остальных пунктов от первого firstno до последнего lastno сбрасываются.


6. Быстрые клавиши

KEYTABLE ( -- )

Начать описание таблицы быстрых клавиш.

KEYTABLE; ( -- )

Закончить описание таблицы быстрых клавиш.

ONKEY ( ->bl; xt -- )

Определить быструю клавишу. При ее нажатии будет вызвано слово xt. Клавиши описываются в виде констант VK_xxx, перед которыми в произвольном порядке могут стоять модификаторы "ctrl+", "alt+", "shift+".

['] f5 ONKEY vk_f5     ['] sp ONKEY ctrl+alt+vk_space

7. Окна сообщений

message-box ( title text flags -- result )

Показать окно сообщения. Title - заголовок окна, text - текст окна (может состоять из нескольких строк, разделяется символом \n", flags - набор констант MB_xxx.

msg ( text -- )

Окно-предупреждение. Заголовок берется из mbox-title.

err ( text -- )

Окно-ошибка. Заголовок берется из mbox-title.

mbox-title

Переменная, в которой хранится адрес строки - заголовка окон сообщений. Если не установлена, в окнах ставится заголовок "Ошибка".


8. Шрифты

create-font ( name size -- font )

Создает шрифт с указанным именем. Размер указывается в типографских пунктах. Необязательные параметры шрифта задаются модификаторами.

delete-font ( font -- )

Уничтожить шрифт. Теоретически, ОС должна уничтожать все графические объекты, включая шрифты, после закрытия программы. Однако имеются подозрения, что Windows 95/98/Me этого не делают, поэтому не забывайте стирать шрифты вручную.

bold ( -- )

Модификатор: определяемый шрифт будет жирным.

italic ( -- )

Модификатор: определяемый шрифт будет курсивным.

underline ( -- )

Модификатор: определяемый шрифт будет подчеркнутым.

strike-out ( -- )

Модификатор: определяемый шрифт будет перечеркнутым.

" Times New Roman Cyr" 12 bold italic create-font TO ff default-font ( font -- )

Устанавливает стандартный шрифт, который с этого момента будет использоваться для всех элементов управления, кроме всплывающих подсказок. Не забудьте уничтожить этот шрифт в конце работы программы (он хранится в переменной def-font). Если вызвать это слово с аргументом 0, для элементов будет использоваться стандартный системный шрифт.

-sysfont ( -- )

Устанавливает последнему определенному элементу системный шрифт.


9. Разное

Цвета

Цвета задаются одной 32-разрядной ячейкой со следующими значениями битов: 0x00rrggbb, где rr, gg, bb - соответственно красная, синяя и зеленая компонента цвета. Определены нижеперечисленные стандартные цвета плюс константа transparent, обозначающая прозрачный цвет:

    red     green     blue     white     black     yellow     violet     cyan

syscolor ( index -- rgb )

Возвращает в формате RGB один из системных цветов, определяемых константами color_xxx.

>bgr ( rgb -- bgr )

Переводит цвет из внутреннего формата Windows (0x00bbggrr) в формат RGB (0x00rrggbb) или наоборот.

rgb ( r g b -- rgb )

Собирает цвет из трех отдельных компонентов.

Прочее

scrеen-x, screen-y ( -- n )

Возвращает размер экрана по горизонтали или по вертикали соответственно.

hdu ( hdu -- pixels)

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

vdu ( hdu -- pixels)

Пересчитывает вертикальные диалоговые единицы в пикселы.

dunits ( hdu vdu -- w h)

Пересчитывает размеры в диалоговых единицах в пикселы.

Пример работы с окнами