| Если вы поклонник Delphi и задача понижения абстракции программирования до уровня системного API стала перед вами впервые, то данная статья поможет сделать первый уверенный шаг в постижении тонкостей этого ремесла. Содержательный пример поможет быстро подойти к сути вопроса. А справочная информация, публикуемая в статье, неизменно пригодиться в будущем.
Одной из наиболее интересных особенностей Delphi является предоставление, наряду с высокоуровневыми функциями VCL, простого доступа к функциям Windows API. Программист в любой момент волен (в зависимости от стоящей перед ним задачи) выбрать для ее решения простые в использовании компоненты либо реализовать алгоритм, требующий компактности и быстродействия при помощи прямых вызовов API. Более того, как правило, можно без прекращения использования компонентов и визуального программирования добавить несколько штрихов при помощи API и добиться предельной точности решения задачи и максимального быстродействия.
Само название операционной системы Windows говорит о том, что основным ее элементом является окно. Для успешного программирования разработчик должен иметь четкое представление о том, что подразумевается в Windows под этим понятием.
Для начинающих программистов неочевидно, что окнами Windows являются не только главные окна, но и большинство элементов управления в них, таких как поля ввода, списки, кнопки и т.п. Фактически любой элемент интерфейса, способный получать фокус ввода, является окном Windows.
Поведение и внешний вид окна определяются его классом. Класс - это внутренняя структура Windows, описывающая шаблон, на основании которого операционная система создает окна.
Каждое окно имеет свой стиль - набор флагов, указывающих операционной системе, какие действия надо предпринимать по умолчанию при возникновении тех или иных событий в окне. Стиль класса в основном определяет моменты, связанные с прорисовкой окна.
Описание стилей основных элементов управления диалоговых окон приведены в таблицах:
| Основные стили окон Windows. |
| WS_BORDER | Создание окна с рамкой. |
| WS_CAPTION | Добавление заголовка к окну с рамкой. |
| WS_CHILD | Создание дочернего окна. Не используется с окнами стиля WS_POPUP. |
| WS_CHILDWINDOW | Создание дочернего окна стиля WS_CHILD. |
| WS_CLIPCHILDREN | Используется при создании родительского окна; запрещает рисование родительского окна в области, занятой любым дочерним окном. |
| WS_CLIPSIBLINGS | Используется только со стилем WS_CHILD. Окна данного стиля исключают области, занятые другими дочерними окнами, из клиентской области дочернего окна при получении данным окном сообщения о перерисовке. В противном случае можно было бы рисовать в клиентской области другого дочернего окна. |
| WS_DISABLED | Создание изначально неактивного окна. |
| WS_DLGFRAME | Создание окна с двойной рамкой без заголовка. |
| WS_EX_ACCEPTFILES | Указывает, что создаваемое окно принимает файлы методом ""drag-and-drop". |
| WS_EX_DLGMODALFRAME | Создание окна с двойной рамкой, в котором может находиться дополнительный заголовок. Этот стиль может использоваться только для значения dwEx- Style. |
| WS_EX_NOPARENTNOTIFY | Указывает, что созданное дочернее окно не будет посылать родительскому окну сообщение WM_PARENTNOTIFY при создании или разрушении дочернего окна. |
| WS_EX_TOPMOST | Указывает, что созданное окно должно располагаться поверх всех окон, не имеющих такого стиля, и оставаться выше остальных даже в неактивном состоянии. |
| WS_EX_TRANSPARENT | Указывает, что созданное окно должно быть про- зрачным. Все окна, расположенные под данным окном, не заслоняются им. |
| WS_GROUP | Используется только в диалоговых окнах. Этот стиль окна указывается для первого элемента управления в группе элементов управления. Пользователь может перемещаться от одного элемента управле- ния к другому с помощью клавиш-стрелок. |
| WS_HSCROLL | Создание окна с горизонтальной полосой прокрутки. |
| WS_MAXIMIZE | Создание окна максимального размера. |
| WS_MAXIMIZEBOX | Создание окна, которое имеет кнопку максимизации. |
| WS_MINIMIZE | Создание окна минимального размера. |
| WS_MINIMIZEBOX | Создание окна, которое имеет кнопку минимизации. |
| WS_OVERLAPPED | Создание перекрывающегося окна. |
| WS_OVERLAPPEDWINDOW | Для создания перекрывающегося окна используются стили WS_OVERLAPPED, WS_THICKFRAME и WS_SYSMENU. |
| WS_POPUP | Создание временного окна. Не используется с окнами стиля WS_CHILD. |
| WS_POPUPWINDOW | Для создания временного окна используются стили WS_BORDER, WS_POPUP и WS_SYSMENU. |
| WS_SYSMENU | Создание окна, которое располагает кнопкой вызова системного меню. При использовании этого стиля для дочернего окна вместо стандартной кнопки вызова системного меню создается кнопка, позволяющая закрыть окно. Стиль WS_SYSMENU используется только для окон, имеющих заголовок. |
| WS_TABSTOP | Используется только в диалоговых окнах. Указывает на произвольное количество элементов управления, между которыми пользователь может перемещаться с помощью клавиши ТаЬ. С помощью последовательных нажатий ТаЬ можно перемещаться между элементами управления со стилем WS_TABSTOP. |
| WS_THICKFRAME | Создание окна с толстой рамкой. Рамка используется для изменения размеров окна. |
| WS_VISIBLE | Создание окна, видимого сразу после создания. Используется для перекрывающихся и временных окон. |
| WS_VSCROLL | Создание окна с вертикальной полосой прокрутки. |
| Дополнительные стили окон. |
| WS_EX_ACCEPTFILES | Указывается, что создаваемое окно принимает файлы методом ""drag-and-drop". |
| WS_EX_DLGMODALFRAME | Создается окно с двойной рамкой. Оно может также создаваться с заголовком, если в параметре dwStyle используется флаг стиля WS_CAPTION. |
| WS_EX_NOPARENTNOTIFY | Создается дочернее окно, при этом родительскому окну при создании или уничтожении дочернего окна не посылается сообщение WM_PARENTNOTIFY. |
| WS_EX_TOPMOST | Создается окно, которое располагается поверх всех окон, не имеющих такого стиля. Оно будет оставаться выше остальных даже в неактивном состоянии. Для добавления и снятия этого атрибута может использоваться функция SetWindowPos(). |
| WS_EX_TRANSPARENT | Созданное окно будет прозрачным. Все окна, расположенные под данным окном, не заслоняются им. Сообщения WM_PAINT получаются окном после обновления остальных окон. |
| WS_EX_CLIENTEDGE | Компонент выглядит трехмерным |
| Стили органа управления Static. |
| SS_BLACKFRAME | Определяет прямоугольник с черной рамкой. |
| SS_BLACKRECT | Определяет залитый черным цветом прямоугольник. |
| SS_CENTER | Выравнивает заданный текст по центру заданного прямоугольника. Выполняется форматирование всего текста. Если текст не помещается на одну строку, то он автоматически переносится на следующую и выравнивается по центру. |
| SS_GRAYFRAME | Определяет прямоугольник с серой рамкой. |
| SS_GRAYRECT | Определяет залитый серым цветом прямоугольник. |
| SS_ICOM | Автоматически масштабирует и выводит пиктограмму в диалоговом окне. |
| SS_LEFT | Действует аналогично SS_CENTER, за исключением того, что текст выравнивается по левому краю. Автоматически выполняется перенос слов на следующую строку и выравнивание текста на следующей строке по левому краю. |
| SS_LEFTNOWORDWRAP | Отключает обработку слов. |
| SS_NOPREFIX | Изменяет обычную интерпретацию амперсанда (&). Как правило, Windows интерпретирует амперсанд в тексте элемента управления как символ-префикс горячей клавиши; он приводит к подчеркиванию следующего символа. Если не нужно чтобы статический элемент управления содержал подчеркнутый текст, то можно использовать стиль SSJMOPREFIX в комбинации (при помощи побитового логического ИЛИ) с другими стилями. |
| SS_RIGHT | Действует аналогично SS_CENTER, за исключением того, что текст выравнивается по правому краю. Автоматически выполняется перенос слов на следующую строку и выравнивание текста на следующей строке по правому краю. |
| SS_SIMPLE | Определяет прямоугольник, в котором выводится одна строка выровненного по левому краю текста. |
| SS_USERITEM | Определяет заданный пользователем элемент. |
| SS_WHITEFRAME | Определяет прямоугольник с белой рамкой. |
| SS_WHITERECT | Определяет залитый белым цветом прямоугольник. |
| Стили органа управления Scrollbar. |
| SBS_BOTTOMALIGN | Используется совместно со стилем SBS_HORZС использованием принятой по умолчанию высоты полосы прокрутки SBSJ30TTOMALIGN выравнивает полосу прокрутки по нижнему краю прямоугольника, определенного х, у, nWidth и nHeight |
| SBS_HORZ | Определяет горизонтальную полосу прокрутки. Высота, ширина и положение полосы прокрутки определяются функцией CreateWindowQ, если не заказан стиль SBSJ30TTOMALIGN или SBS_TOPLIGN. |
| SBS_LEFTALIGN | Используется совместно со стилем SBS_VERT. С использованием принятой по умолчанию высоты полосы прокрутки SBSJ-EFTALIGN совмещает левый край полосы прокрутки с левым краем прямоугольника, определяемого х, у, nWidth и nHeight. |
| SBS_RIGHTALIGN | Используется совместно со стилем SBS_VERT. С использованием принятой по умолчанию высоты полосы прокрутки SBSJ^IGHTALIGN совмещает правый край полосы прокрутки с правым краем прямоугольника, определяемого х, у, nWidth и nHeight. |
| SBS_SIZEBOX | Определяет блок изменения размера. Высота, ширина и положение определяются функцией CreateWindowQ, если не заказан стиль SBS_SIZEBOXBOTTOMRIGHTALIGN или SBS_SIZEBOXTOPLEFTALIGN. |
| SBS_SIZEBOXBOTTOMRIGHTALIGN | Используется совместно со стилем SB_SIZEBOX, С использованием принятой по умолчанию высоты полосы прокрутки SBS_RIGHTALIGN выравнивает полосу прокрутки по правому нижнему краю прямоугольника, определяемого х, у, nWidth и nHeight. |
| SBS_SIZEBOXTOPLEFTALIGN | Используется совместно со стилем SBS_SIZEBOX. С использованием принятой по умолчанию высоты полосы прокрутки SBS_SIZEBOXTOPLEFTALIGN выравнивает полосу прокрутки по левому верхнему краю прямоугольника, определяемого х, у, nWidth и nHeight. |
| SBS_TOPALIGN | С использованием принятой по умолчанию высоты полосы прокрутки SBS_TOPAL1GN выравнивает полосу прокрутки по верхнему краю прямоугольника, определяемого х, у, nWidth и nHeight. |
| SBS_VERT | Определяет вертикальную полосу прокрутки. Высота, ширина и положение полосы прокрутки определяются функцией CreateWin-dow(), если не заказан стиль SBS_RIGHTALIGN или SBS_LEFTALIGN. |
| Стили органа управления Listbox. |
| LBS_DISABLENOSCROLL | Если в списке не содержится достаточного количества элементов, то вывод вертикальной полосы прокрутки блокируется. |
| LBS_EXTENDEDSEL | Допускается выбор нескольких элементов списка при помощи клавиши <Shift> и "мыши" или при помощи специальных клавиш. |
| LBS_HASSTRINGS | Служит для обслуживания памяти и указателей на строки, появляющиеся в нестандартном списке. Стиль LBS_HASSTRINGS позволяет приложению использовать сообщение LB_GETTEXT для получения конкретной строки. |
| LBS_MULTICOLUMN | Задает список из нескольких колонок, между которыми возможна горизонтальная прокрутка. |
| LBS_MUPLTIPLESEL | В списке этого стиля допускается выбор произвольного количества строк, выбранная строка меняется всякий раз, когда пользователь делает обычный или двойной щелчок на строке. |
| LBS_NOINTEGRALHEIGHT | При создании списка его размер определяется равным размеру, который задан приложением. |
| LBS_NOREDRAW | Если задан такой стиль, то при внесении изменений изображение элемента управления класса LISTBOX не изменится |
| LBS_NOTIFY | Если пользователь сделает обычный или двойной щелчок на строке списка этого стиля, то родительское окно получит сообщение. |
| LBS_OWNERDRAWFIXED | За перерисовку содержимого списка этого стиля отвечает окно-владелец; все элементы списка имеют одинаковую высоту. |
| LBS_OWNERDRAWVARIABLE | За перерисовку содержимого списка этого стиля отвечает окно-владелец; в отличие от стиля LBS_OWNERDRAWFIXED, элементы списка могут быть разной высоты. |
| LBS_SORT | Строки в элементе управления класса LISTBOX сортируются в алфавитном порядке. |
| LBS_STANDARD | Строки в элементе управления класса LISTBOX сортируются в алфавитном порядке, когда пользователь делает обычный или двойной щелчок на строке, родительскому окну посылается сообщение. Элемент управления класса LISTBOX обладает вертикальной полосой прокрутки и рамками. |
| LBS_USETABSTOPS | Списку позволяется распознавать и отображать все символы табуляции при выводе строк. По умолчанию одной позиции табуляции соответствуют 32 единицы масштабирования. С помощью функции GetDialogBaseUnitsO приложение может получить величину текущей базовой единицы масштабирования в пикселах. Одна единица диалога по горизонтали равняется одной четвертой текущей базовой единицы масштабирования. Базовые единицы масштабирования вычисляются на основании высоты и ширины текущего системного шрифта. |
| LBS_WANTKEYBOARDINPUT | Если пользователь нажимает клавишу и список этого стиля обладает фокусом ввода, то владелец списка получает сообщения WM_VKEYTOITEM и WM_CHARTOITEM. |
| Стили органа управления Edit. |
| ES_AUTOHSCROLL | Автоматически перемещает текст вправо на 10 символов, когда пользователь начинает вводить данные в конце строки ввода. При нажатии пользователем клавиши <Enter> текст автоматически выводится с начала строки. |
| ES_AUTOVSCROLL | Автоматически перемещает текст вниз на одну страницу, когда пользователь нажимает клавишу <Enter> на последней строке. |
| ES_CENTER | Служит для выравнивания текста по центру. |
| ES_LEFT | Служит для выравнивания текста по левому краю. |
| ES_OWERCASE | При вводе все символы преобразуются в нижний регистр. |
| ES_MULTILINE | Обеспечивает элемент управления - многострочный редактор. При использовании со стилем ES_AUTOVSCROLL в ответ на нажатие клавиши <Enter> осуществляется вертикальная прокрутка текста. Если стиль ES_AUTOVSCROLL не был указан, то при нажатии клавиши <Enter> подается звуковой сигнал; дополнительные строки не выводятся. То же самое относится к использованию стиля ES_AUTOHSCROLL. Если указан этот стиль, то пользователь может не переходить на следующую строку, а сдвигать текст влево. При переходе элемента управления в неактивное состояние текст не остается на той же строке в окне, а создается новая строка. Элементы управления стиля ES_MULTILINE могут включать полосы прокрутки. |
| ES_NOHIDESEL | Перекрывает выполняемую по умолчанию операцию, запрещая прятать выделенный фрагмент, когда элемент управления теряет фокус ввода. |
| ES_OEMCONVERT | Текст, вводимый в элементе управления класса EDIT, преобразуется из кодовой таблицы Windows в кодовую таблицу OEM и наоборот. |
| ES_PASSWORD | Каждый введенный символ выводится как звездочка (*). |
| ES_READONLY | Пользователю не разрешается вводить или редактировать текст. |
| ES_UPPERCASE | Все вводимые символы преобразуются в верхний регистр. |
| ES_RIGHT | Служит для выравнивания текста по правому краю |
| ES_WANTRETURN | При нажатии пользователем клавиши <Enter> вставляется символ возврата каретки. |
| Стили органа управления Combobox. |
| CBS_AUTOHSCROLL | Когда пользователь вводит символ в конце строки, автоматически осуществляется прокрутка текста в элементе управления класса EDIT. |
| CBS_DISABLENOSCROLL | Если в списке не содержится достаточное количество элементов, то вывод вертикальной полосы прокрутки блокируется. |
| CBS_DROPDOWN | Список не будет выводиться до тех пор, пока пользователь не выберет пиктограмму около поля ввода. |
| CBS_DROPDOWNLIST | Заменяет элемент управления класса EDIT статическим элементом текста, в котором выводится выбранная строка в списке. |
| CBS_HASSTRINGS | Позволяет возвратить текст конкретного элемента с помощью GETTEXT. |
| CBS_NOINTEGRALHEIGHT | Указывает, что высота текста несущественна. |
| CBS_OEMCONVERT | Указывает на преобразование OEM. |
| CBS_OWNERDRAWFIXED | За перерисовку содержимого списка этого стиля отвечает окно-владелец; все элементы списка имеют одинаковую высоту. |
| CBS_OWNERDRAWVARIABLE | За перерисовку содержимого списка этого стиля отвечает окно-владелец; в отличие от стиля LBS_OWNERDRAWFIXED, элементы списка могут быть разной высоты. |
| CBS_SIMPLE | Список выводится постоянно. Выбранный в данный момент элемент списка выводится в элементе управления EDIT. |
| CBS_SHORT | Производится автоматическая сортировка строк списка при их вводе. Этот стиль не применим к нестандартным комбинированным спискам. |
| Стили органа управления Button. |
| BS_AUTOCHECKВОХ | Совпадает со стилем BS_CHECKBOX за исключением того, что при выборе кнопка автоматически меняет свое состояние. |
| BS_AUTORADIOBUTTON | Совпадает со стилем BS_RADIOBUTTON за исключением того, что при нажатии кнопки приложению автоматически посылается сообщение BN_CLICKED, снимая отметку с любого другого переключателя в группе. |
| BS_AUTOSSTATE | Совпадает со стилем BS_3STATE за исключением того, что при нажатии кнопка автоматически меняет свое состояние. |
| BS_CHECKBOX | Определяет маленькую прямоугольную кнопку, которую можно выбрать (переключатель). Если кнопка данного стиля выбрана, то она изображается жирно. Любой текст, связанный с кнопкой, выводится с правой стороны. |
| BS_DEFPUSHBUTTON | Определяет маленькую кнопку в форме эллипса с толстой рамкой. Обычно используется для указания принятого по умолчанию ответа пользователя. Связанный с кнопкой текст выводится непосредственно на кнопке. |
| BS_GROUPBOX | Определяет прямоугольную область, охватывающую группу кнопок. Текст выводится в левом верхнем углу прямоугольника. |
| BS_LEFTEXT | Приводит к выводу текста с левой стороны переключателя. Может использоваться со стилем элемента управления BS_3STATE. |
| BS_OWNERDRAW | Определяет кнопку с нестандартным алгоритмом отри- совки. О нажатии кнопки уведомляется ее родительское окно. Данное уведомление включает вывод, инвертиро вание и запрет кнопки. |
| BS_PUSHBUTTON | Определяет маленькую кнопку в форме эллипса, содержащую указанный текст. При нажатии кнопки родительскому окну посылается соответствующее сообщение. |
| BS_RADIOBUTTON | Определяет маленькую круглую кнопку с рамкой. Если кнопка выбрана щелчком, то рамка становится жирной. Родительское окно также уведомляется о нажатии кнопки при помощи соответствующего сообщения. Следующий щелчок на кнопке приведет к отмене выбора и передаче родительскому окну другого сообщения, указывающего на изменение состояния кнопки. |
| BS_3STATE | Соответствует BS_CHECKBOX, но кнопка может быть не только выбрана, но и сделана недоступной для нажатия. Выведенная серым цветом кнопка указывает, что переключатель в данный момент недоступен. |
| BS_USERBUTTON | Определяет "кнопку пользователя". Родительское окно уведомляется о нажатии на кнопку. |
Главная проблема, возникающая при написании Win32API приложений - это неудобство ручного создания всех окон приложения. Требуется вызывать функцию CreateWindow для каждого (в том числе и дочернего) окна программы, а затем еще и менять атрибуты (такие как шрифт, цвет и т.д.) в большинстве из них. Лучшим выходом из этой ситуации является использование ресурсов диалоговых окон (dialog box resources) для создания всех окон приложения.
Преимущество такого способа создания диалоговых окон заключается в том, что Windows берет на себя обеспечение интерфейса диалоговых окон, к которому привык пользователь - кнопки по умолчанию (срабатывающие, когда пользователь нажмет <Enter> или <Esc>); возможность переключения между дочерними элементами управления при помощи клавиши <Tab> и т.п.
Для создания ресурсов лучше всего использовать обычный блокнот Windows и какой-либо редактор ресурсов (Resource Hacker, например). С начало в блокноте набирается код главного окна, например такой:
MAIN_WINDOW DIALOGEX 32768, 0, 258, 130
STYLE DS_MODALFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU
CAPTION "Главное окно"
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
FONT 8, "MS SANS SERIF"
{
CONTROL "Закрыть", 1, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 193, 107, 55, 14
}
MAINICON ICON "C:\Icons\captionicon.ico" |
В состав ресурсов окна мы также добавили значек программы (файл captionicon.ico). Заметьте, что главное окно названо MAIN_WINDOW, а значок - MAINICON. Данные идентификаторы будут нужны для обработки: вызова диалогового окна из ресурсов и отображения значка в шапке программы. Ключевое слово ICON сигнализирует, что в проект добавляется именно значок. Перед словом ICON ставится идентификатор (MAINICON), по которому этот значок будет затем "опознан" программой. В качестве идентификатора могут применяться либо целочисленные константы, либо строковые константы.
Вы сохраняете данный код как текстовый файл, меняете разрешение с *.txt на *.rc и компилируете его с помощью Borland Resource Compiler (файл BRCC32.EXE), который входит в поставку с DELPHI (в данном примере использован компилятор Delphi 3):
|
C:\Program Files\Borland\Delphi 3\BIN\Brcc32.exe example.rc |
И получаете после компиляции файл example.res, который будет содержать в себе главное окно программы с кнопкой "Закрыть" (идентификатор "1") и значек. Теперь осталось подсоединить ресурсный файл в коде программы, прописав {$R example.res}, и использовать по назначению.
Чтобы не возиться с набиранием кода диалогового окна, проще всего взять его из чужой программы, написанной на API (например, WinZIP, WinRAR) и отредактировать в редакторе ресурсов. Существуют программы для создания диалоговых окон, но как показала практика, они не удобны и способны лишь на построение простейших окон, код которых можно с легкостью набрать в блокноте.
Код API-приложения будет выглядеть сложнее кода программы, написанной с помощью VCL. Объясняется это тем, что в данном случае все обработчики элементов управления нужно создавать вручную. Достаточно посмотреть на код программы, которая вызывает из ресурсов созданное нами ранее диалоговое окно и обрабатывает кнопку "Закрыть":
program example_program;
uses
Windows, Messages;
//Функция, обрабатывающая все команды от элементов управления окна
function DlgProc(hWin, uMsg, wParam, lParam: Integer): Integer; stdcall;
begin
Result := 0;
case uMsg of
WM_INITDIALOG:
begin
//Помещаем в шапку программы значок MAINICON
SendMessage(hWin, WM_SETICON, ICON_BIG, LoadIcon(hInstance, 'MAINICON'));
end;
WM_COMMAND:
begin
case LoWord(wParam) of
//При нажатии на кнопку с идентификатором 1 закрываем программу
1: EndDialog(hWin, 0);
end;
end;
//При нажатии на кнопку "Х" в шапке программы закрываем приложение
WM_DESTROY, WM_CLOSE: PostQuitMessage(0);
end;
end;
begin
//Подключаем файл ресурсов
{$R example.res}
//При запуске программы открываем диалоговое окно MAIN_WINDOW
DialogBox(hInstance, 'MAIN_WINDOW', 0, @DlgProc);
end. |
Если вы все сделали правильно, то при запуске программы увидите диалоговое окно с кнопкой "Закрыть". В программу можно поместить любые ресурсы: приложения, шрифты, изображения, текстовые файл и т.п. Но это уже тема отдельной статьи...
|