Создание графического интерфейса пользователя средствами Win32 API
Создание графического интерфейса пользователя средствами Win32 API
Создание графического интерфейса пользователя средствами Win32 API С появлением разнообразных визуальных средств разработки приложений, написание графических интерфейсов программ превратилось в подобие детской игры. Ткнул мышкой - появилась формочка, второй раз ткнул - кнопочка нарисовалась. Как мне кажется, многие сейчас не помышляют об ином способе программирования в графической среде. Безусловно, против прогресса не попрешь, при написании больших проектов все эти удобства очень даже кстати. Но разговор не об этом. Иногда дело доходит до абсурда, примитивное приложение пишется с использованием mfc, vcl etc. Такие программы жрут память, как термиты и занимают, своим жирным телом, лишнее дисковое пространство. Как правило, mfc/vcl аналоги "весят" в десять - двадцать раз больше, чем программы написанные на чистом api. А visual basic (да простит меня бог за это словосочетание) с его msvbvmxx.dll? Да и системных ресурсов расходуется значительно больше (в несколько раз). Бедные пользователи, отказывая себе в пиве, копят ассигнации на покупку нового железа. Разве не жалко - бедне ньких? Не только же программерам пиво пить? Есть еще один положительный момент в api кодинге, программист становится ближе к операционной системе. Соответственно - лучше ее понимает и контролирует. Да и просто - это очень увлекательное занятие. Повторюсь, все вышесказанное относится именно к маленьким, простеньким программкам, в больших проектах все обстоит совершенно иначе. Надеюсь, убедил. Поехали. Мы рассмотрим создание простенького оконного интерфейса с минимальной функциональностью. Это будет простое окошко с двумя полями ввода и двумя кнопочками. При нажатии на кнопку "copy", текст из первого поля ввода будет скопирован во второе. При нажатии на кнопку "close", программа завершит свою работу. В дальнейшем оно может послужить шаблоном для написания других, более сложных, приложений. Будем общаться на языке c/c++, хотя и delphi не обидим. Общий принцип один и тот же, различается только синтаксис. Чтобы работать с системными сообщениями и api-функциями, необходимо к своему проекту подключить заголовочные файлы; в c/c++ это windows.h, в delphi это модули windows и messages. Любая программа в ОС windows состоит из трех основных частей: главной функции, цикла обработки сообщений и оконной функции, которая обрабатывает все сообщения, посылаемые окну. Наша программа начинает выполняться с функции winmain(). Это и есть главная функция. Функция winmain() выполняет, обычно, следующие задачи: -Определяет класс окна. Не путать с классом ООП. -Регистрирует данный класс в системе. -Создает главное окно приложения и другие элементы управления. -Отображает окно на экране. -Запускает цикл обработки сообщений. -Объявляется она вот каким образом: int apientry winmain(hinstance hinstance, hinstance hprevinstance, lpstr lpcmdline, int ncmdshow) Разберемся с параметрами: hinstance - дескриптор текущего экземпляра приложения. hprevinstance - дескриптор предыдущего экземпляра приложения, если оно запущено. lpcmdline - указатель на строку, содержащую параметры передаваемые программе при запуске. ncmdshow - константа определяющая способ отображения окна. (Смотри константы sw_). В delphi мы не увидим такой картины, в этой среде разработки главная функция скрывается от программиста компилятором. Хотя, несомненно, она присутствует в конечном коде. Для регистрации класса окна, необходимо заполнить поля структуры типа wndclass (в delphi twndclass). У нас, для этого, объявлена переменная wcl. wcl.hinstance = hinstance; Дескриптор текущего экземпляра приложения, переменная hinstance инициализируется функцией winmain(). В delphi инициализируется неявным образом. wcl.lpszclassname = szwinname; Имя класса. Строковую переменную szwinname мы создали и инициализировали предварительно. wcl.lpfnwndproc = windowfunc; Указатель на оконную функцию. wcl.style = 0; Константа, задающая стиль окна. Для этого используется флаги cs_, я просто обнулил. Можно задавать комбинацию флагов с помощью битовой операции "или". wcl.hicon = loadicon(null, idi_asterisk); Дескриптор иконки приложения, возвращаемый функцией loadicon(). Я загрузил стандартную иконку. Смотри константы idi_. wcl.hcursor = loadcursor(null,idc_arrow); Дескриптор курсора приложения, возвращаемый функцией loadcursor(). Я загрузил стандартную стрелочку. Смотри константы idc_. wcl.lpszmenuname = null; Указатель на строку, задающую имя ресурса меню для данного оконного класса. Нет меню, нет и указателя. wcl.cbclsextra = 0; Зарезервированное поле. Обнуляем. wcl.cbwndextra = 0; Зарезервированное поле. Обнуляем. wcl.hbrbackground = (hbrush)color_window; Цвет окошка. Константа color_window приводится к типу hbrush (в delphi приводить не нужно). Также, с помощью функции getstockobject(), можно задать цвет кисти окна или фоновый рисунок. Теперь, смело, регистрируем класс окна. registerclass(&wcl); В качестве параметра функции registerclass передается указатель на структуру wcl. Следующей строкой мы создаем наше окно. hmainwnd = createwindow(szwinname, "Простое окно на api.", ws_overlappedwindow ^ ws_thickframe ^ s_maximizebox, cw_usedefault, cw_usedefault, 300, 170, hwnd_desktop, null, hinstance, null); -Первый параметр - имя класса окна. -Второй параметр - Заголовок окна. -Третий параметр - стиль окна. Из стандартного ws_overlappedwindow, с помощью операции xor, я изъял возможность масштабирования окна и отключил кнопку максимизации. -Четвертый и пятый - положение окна от левого, верхнего угла экрана. У меня cw_usedefault, при этом значении система выбирает положение окна автоматически. -Шестой и седьмой параметры - ширина и высота окна, соответственно. -Восьмой параметр - окно владелец. У главного окна, владелец - рабочий стол (0). У элементов управления - главное окно. -Девятый - указатель на дескриптор меню. Нет меню, нет и указателя. -Десятый параметр - Дескриптор текущего экземпляра приложения. -Одиннадцатый - Используется при создании приложений с mdi-интерфейсом. Нам не нужен. Функция возвращает дескриптор созданного окна, который заносится в переменную hmainwnd. Дескриптор окна - уникальный номер в системе, по которому идентифицируется окно или элемент управления. Далее мы создадим необходимые элементы управления. Все элементы управления - те же окна, просто они имеют другое имя класса. Классы элементов управления регистрировать не нужно, они уже предопределены в системе. Кнопка - класс button. Поле ввода - класс edit. Надпись - класс ststic. Существует множество классов, которые соответствуют стандартным элементам управления. Контролы создаем с помощью, знакомой нам, функции createwindow() и незнакомой createwindowex(). createwindowex() позволяет создать окно с расширенным стилем. Мы используем ее для создания полей ввода. В этой функции добавлен первый параметр, который и задает этот самый расширенный стиль, остальные параметры как у createwindow(). Элементы управления являются дочерними окнами, их владелец главное окно. Создавая контролы, в параметрах функции необходимо указать дескриптор главного окна, а также стиль окна ws_child. Внешним видом и функциональностью элементов управления можно манипулировать с помощью флагов: ws_, es_, bs_, ss_, объединяя их битовой операцией "или". Создавая контролы, мы инициализируем соответствующие переменные их дескрипторами, которые возвращают функции createwindow() и createwindowex(). Эти дескрипторы понадобятся нам для дальнейшей работы с элементами управления. Отображаем, созданное нами, окно на экране и перерисовываем его. showwindow(hmainwnd, ncmdshow); updatewindow(hmainwnd); Создаем цикл обработки сообщений. while(getmessage(&msg, null, 0, 0)) { translatemessage(&msg); dispatchmessage(&msg); } Функция getmessage выбирает очередное сообщение из очереди сообщений приложения и отправляет его окну. Первый параметр - структура типа msg (в delphi типа tmsg) Второй параметр - дескриптор окна, которому предназначено сообщение. Если null или 0, то все окна приложения. Третий и четвертый - позволяют задать диапазон принимаемых сообщений. Если 0, то все сообщения, адресованные окну. getmessage - возвращает false при появлении сообщения wm_quit, в этом случае происходит выход из цикла и приложение завершает работу. translatemessage - переводит виртуальные коды клавиш в клавиатурные сообщения. dispatchmessage - отправляет сообщение оконной функции, для обработки. Оконная функция обеспечивает функциональность программы, путем обработки системных сообщений. Оконная функция является callback - функцией, т.е. вызывается операционной системой в ответ на поступившее, новое сообщение. Оконная функция объявлена таким образом: lresult callback windowfunc(hwnd hmainwnd, uint imsg, wparam wparam, lparam lparam) hmainwnd - дескриптор главного окна. imsg - номер сообщения. Смотри константы wm_. lparam и wparam - параметры сообщения. При появлении сообщения, мы можем сравнить параметр imsg с одной из констант wm_ и запрограммировать соответствующую реакцию программы. Например: при нажатии левой кнопки мыши, когда указатель мыши находится над клиентской областью окна, возникает событие wm_lbuttondown. Вызывается оконная функция, в параметр imsg заносится значение константы wm_lbuttondown, мы можем проверить условие и запрограммировать нужную нам реакцию программы. Внутри оконной функции расположен оператор выбора, который и выполняет вышеописанную задачу. В операторе выбора обязательно должен быть организован обработчик по умолчанию, который реализуется функцией defwindowproc(hmainwnd, imsg, wparam, lparam); Если этого не сделать, наша программа издохнет так и не ожив. Множество сообщений, обрабатывается самой системой, такие как: изменение размеров окна, сворачивание/разворачивание окна, вызов системного меню etc. Для этого и служит defwindowproc(). При работе с оконными элементами управления, окну владельцу посылается сообщение wm_command, при этом lparam содержит дескриптор элемента управления, а старший байт параметра wparam - идентификатор события, вызванного в элементе управления. Например: при нажатии на кнопку - bn_clicked. Смотри константы bn_, wm_. Закрыть прогу мы можем использовав функцию postquitmessage(0). Эта функция посылает окну сообщение wm_quit. Несколько слов о том, как писать такие программы на delphi. Создаем новый проект, запускаем project manager, удаляем unit1 вместе с формой. Жмем ctrl + f12 и открываем файл проекта. Удаляем из uses модуль forms, добавляем туда windows и messages. Удаляем все между begin и end. Заготовка готова. Можно кодить. Писать программы на чистом api невозможно без справки, которая всегда должна быть под рукой. Будь ты самим Гейтсом - все не запомнить. Рекомендую: - прежде всего - msdn: ; - справочная система delphi (файл mstools.hlp); - на сайте есть русская справка по win32 api. Вот и все. Удачи.