- •Оглавление
- •Глава 1 Введение 7
- •Глава 2 Основные понятия 10
- •Глава 3 Рисование текста 42
- •Глава 4. Главное о графике 65
- •Глава 5 Клавиатура 180
- •Глава 6 Мышь 214
- •Глава 7 Таймер 233
- •Глава 8 Дочерние окна управления 247
- •Глава 1 Введение
- •Основные правила
- •1.2 Краткая история Windows
- •Глава 2 Основные понятия
- •2.1 Отличительная особенность Windows
- •2.1.1 Графический интерфейс пользователя
- •2.1.2 Концепции и обоснование gui
- •2.1.3 Содержимое интерфейса пользователя
- •2.1.4 Преимущество многозадачности
- •2.1.5 Управление памятью
- •2.1.6 Независимость графического интерфейса от оборудования
- •2.1.7 Соглашения операционной системы Windows
- •2.1.8 Вызовы функций
- •2.1.9 Объектно-ориентированное программирование
- •2.1.10 Архитектура, управляемая событиями
- •2.1.11 Оконная процедура
- •2.2 Ваша первая программа для Windows
- •2.2.1 Что в этой программе неправильно?
- •2.2.2 Файлы hellowin
- •2.2.3 Файл исходного текста программы на языке с
- •2.2.4 Вызовы функций Windows
- •2.2.5 Идентификаторы, написанные прописными буквами
- •2.2.6 Новые типы данных
- •2.2.7 Описатели
- •2.2.8 Венгерская нотация
- •2.2.9 Точка входа программы
- •2.2.10 Регистрация класса окна
- •2.2.11 Создание окна
- •2.2.12 Отображение окна
- •2.2.13 Цикл обработки сообщений
- •2.2.14 Оконная процедура
- •2.2.15 Обработка сообщений
- •2.2.15 Воспроизведение звукового файла
- •2.2.16 Сообщение wm_paint
- •2.2.17 Сообщение wm_destroy
- •2.3 Сложности программирования для Windows
- •2.3.1 Функции обратного вызова
- •2.3.2 Синхронные и асинхронные сообщения
- •Глава 3 Рисование текста
- •3.1 Рисование и обновление
- •3.1.1 Сообщение wm_paint
- •3.1.2 Действительные и недействительные прямоугольники
- •3.2 Введение в графический интерфейс устройства (gdi)
- •3.2.1 Контекст устройства
- •3.2.2 Получение описателя контекста устройства. Первый метод
- •3.2.3 Структура информации о рисовании
- •3.2.4 Получение описателя контекста устройства. Второй метод
- •3.2.5 Функция TextOut. Подробности
- •3.2.6 Системный шрифт
- •3.2.7 Размер символа
- •3.2.8 Метрические параметры текста. Подробности
- •3.2.9 Форматирование текста
- •3.2.10 Соединим все вместе
- •3.2.11 Оконная процедура программы sysmets1
- •3.2.12 Не хватает места!
- •3.2.13 Размер рабочей области
- •3.3 Полосы прокрутки
- •3.3.1 Диапазон и положение полос прокрутки
- •3.3.2 Сообщения полос прокрутки
- •3.3.3 Прокрутка в программе sysmets2
- •3.3.4 Структурирование вашей программы для рисования
- •Глава 4. Главное о графике
- •4.1 Концепция gdi
- •4.2 Структура gdi
- •4.2.1 Типы функций
- •4.2.2 Примитивы gdi
- •4.2.3 Другие аспекты
- •4.3 Контекст устройства
- •4.3.1 Получение описателя контекста устройства
- •4.3.3 Получение информации из контекста устройства
- •4.3.4 Размер устройства
- •4.3.5 О цветах
- •4.3.6 Атрибуты контекста устройства
- •4.3.7 Сохранение контекста устройства
- •4.4 Рисование отрезков
- •4.4.1 Ограничивающий прямоугольник
- •4.4.2 Сплайны Безье
- •4.4.3 Использование стандартных перьев
- •4.4.4 Создание, выбор и удаление перьев
- •4.4.5 Закрашивание пустот
- •4.4.6 Режимы рисования
- •4.5 Рисование закрашенных областей
- •4.5.1 Функция Polygon и режим закрашивания многоугольника
- •4.5.2 Закрашивание внутренней области
- •4.6 Режим отображения
- •4.6.1 Координаты устройства (физические координаты) и логические координаты
- •4.6.2 Системы координат устройства
- •4.6.3 Область вывода и окно
- •4.6.4 Работа в режиме mm_text
- •4.6.5 Метрические режимы отображения
- •4.6.6 Ваши собственные режимы отображения
- •Режим отображения mm_isotropic
- •Mm_anisotropic: растягивание изображения
- •4.6.7 Программа whatsize
- •4.7 Прямоугольники, регионы и отсечение
- •4.7.1 Работа с прямоугольниками
- •4.7.2 Случайные прямоугольники
- •4.7.3 Создание и рисование регионов
- •4.7.4 Отсечения: прямоугольники и регионы
- •4.7.5 Программа cover
- •4.8 Пути
- •4.8.1 Создание и воспроизведение путей
- •4.8.2 Расширенные перья
- •4.9 Битовые образы
- •4.9.1 Цвета и битовые образы
- •4.9.2 Битовые образы, не зависящие от устройства (dib)
- •4.9.3 Файл dib
- •4.9.4 Упакованный формат хранения dib
- •4.9.5 Отображение dib
- •4.9.6 Преобразование dib в объекты "битовые образы"
- •4.10 Битовый образ — объект gdi
- •4.10.1 Создание битовых образов в программе
- •4.10.2 Формат монохромного битового образа
- •4.10.3 Формат цветного битового образа
- •4.10.4 Контекст памяти
- •4.10.5 Запись пикселей на устройство отображения
- •Функция PatBlt
- •Координаты Blt
- •4.10.6 Перенос битов с помощью функции BitBlt
- •4.10.7 Функция DrawBitmap
- •4.10.8 Использование других rop кодов
- •4.10.9 Дополнительные сведения о контексте памяти
- •4.10.10 Преобразования цветов
- •4.10.11 Преобразования режимов отображения
- •4.10.12 Растяжение битовых образов с помощью функции StretchBlt
- •4.10.13 Кисти и битовые образы
- •4.11 Метафайлы
- •4.11.1 Простое использование метафайлов памяти
- •4.11.2 Сохранение метафайлов на диске
- •4.12 Расширенные метафайлы
- •4.12.1 Делаем это лучше
- •4.12.2 Базовая процедура
- •4.12.3 Заглянем внутрь
- •4.12.4 Вывод точных изображений
- •4.13 Текст и шрифты
- •4.13.1 Вывод простого текста
- •4.13.2 Атрибуты контекста устройства и текст
- •4.13.3 Использование стандартных шрифтов
- •4.13.4 Типы шрифтов
- •4.13.5 Шрифты TrueType
- •4.13.6 Шрифт ezfont
- •4.13.7 Внутренняя работа
- •4.13.8 Форматирование простого текста
- •4.13.9 Работа с абзацами
- •Глава 5 Клавиатура
- •5.1 Клавиатура. Основные понятия
- •5.1.1 Игнорирование клавиатуры
- •5.1.2 Фокус ввода
- •5.1.3 Аппаратные и символьные сообщения
- •5.2 Аппаратные сообщения
- •5.2.1 Системные и несистемные аппаратные сообщения клавиатуры
- •5.2.2 Переменная lParam
- •Счетчик повторений
- •Скан-код oem
- •Флаг расширенной клавиатуры
- •Код контекста
- •Флаг предыдущего состояния клавиши
- •Флаг состояния клавиши
- •5.2.3 Виртуальные коды клавиш
- •5.2.4 Состояние клавиш сдвига и клавиш-переключателей
- •5.2.5 Использование сообщений клавиатуры
- •5.4 Символьные сообщения
- •5.4.1 Сообщения wm_char
- •5.4.2 Сообщения немых символов
- •5.6 Каретка (не курсор)
- •5.6.1 Функции работы с кареткой
- •5.6.2 Программа typer
- •5.7 Наборы символов Windows
- •5.7.1 Набор символов oem
- •Поддержка языков различных стран в dos
- •5.7.2 Набор символов ansi
- •5.7.3 Наборы символов oem, ansi и шрифты
- •5.8 Решение проблемы с использованием системы unicode
- •5.8.2 Unicode и библиотека с
- •5.8.3 Типы данных, определенные в Windows для Unicode
- •5.8.4 Unicode- и ansi-функции в Windows
- •5.8.5 Строковые функции Windows
- •5.8.6 Создание программ, способных использовать и ansi, и Unicode
- •5.8.7 Ресурсы
- •5.8.8 Текстовые файлы
- •5.8.9 Перекодировка строк из Unicode в ansi и обратно
- •Глава 6 Мышь
- •6.1 Базовые знания о мыши
- •6.1.1 Несколько кратких определений
- •6.2 Сообщения мыши, связанные с рабочей областью окна
- •6.2.1 Простой пример обработки сообщений мыши
- •6.2.3 Двойные щелчки клавиш мыши
- •6.3 Сообщения мыши нерабочей области
- •6.3.1 Сообщение теста попадания
- •6.3.2 Сообщения порождают сообщения
- •6.4 Тестирование попадания в ваших программах
- •6.4.1 Гипотетический пример
- •6.4.2 Пример программы
- •6.4.3 Эмуляция мыши с помощью клавиатуры
- •6.4.4 Добавление интерфейса клавиатуры к программе checker
- •6.4.5 Использование дочерних окон для тестирования попадания
- •6.4.6 Дочерние окна в программе checker
- •6.5 Захват мыши
- •6.5.1 Рисование прямоугольника
- •6.5.2 Решение проблемы — захват
- •6.5.3 Программа blokout2
- •Глава 7 Таймер
- •7.1 Основы использования таймера
- •7.1.1 Система и таймер
- •7.1.2 Таймерные сообщения не являются асинхронными
- •7.2 Использование таймера: три способа
- •7.2.1 Первый способ
- •Что делать, если таймер недоступен
- •Пример программы
- •7.2.2 Второй способ
- •Пример программы
- •7.2.3 Третий способ
- •7.3 Использование таймера для часов
- •7.3.1 Позиционирование и изменение размеров всплывающего окна
- •7.3.2 Получение даты и времени
- •7.3.3 Обеспечение международной поддержки
- •7.3.4 Создание аналоговых часов
- •7.4 Стандартное время Windows
- •7.5 Анимация
- •Глава 8 Дочерние окна управления
- •8.1 Класс кнопок
- •8.1.1 Создание дочерних окон
- •8.1.2 Сообщения дочерних окон родительскому окну
- •8.1.3 Сообщения родительского окна дочерним окнам
- •8.1.4 Нажимаемые кнопки
- •8.1.5 Флажки
- •8.1.6 Переключатели
- •8.1.7 Окна группы
- •8.1.8 Изменение текста кнопки
- •8.1.9 Видимые и доступные кнопки
- •8.1.10 Кнопки и фокус ввода
- •8.2 Дочерние окна управления и цвета
- •8.2.1 Системные цвета
- •8.2.2 Цвета кнопок
- •8.2.3 Сообщение wm_ctlcolorbtn
- •8.2.4 Кнопки, определяемые пользователем
- •8.3 Класс статических дочерних окон
- •8.4 Класс полос прокрутки
- •8.4.1 Программа colors1
- •8.4.2 Интерфейс клавиатуры, поддерживаемый автоматически
- •8.4.3 Введение новой оконной процедуры
- •8.4.5 Закрашивание фона
- •8.4.5 Окрашивание полос прокрутки и статического текста
- •8.5 Класс редактирования
- •8.5.1 Стили класса редактирования
- •8.5.2 Коды уведомления управляющих окон редактирования
- •8.5.3 Использование управляющих окон редактирования
- •8.5.4 Сообщения управляющему окну редактирования
- •8.6 Класс окна списка
- •8.6.1 Стили окна списка
- •8.6.2 Добавление строк в окно списка
- •8.6.3 Выбор и извлечение элементов списка
- •8.6.4 Получение сообщений от окон списка
- •8.6.5 Простое приложение, использующее окно списка
- •8.6.6 Список файлов
- •Использование атрибутов файлов
- •Упорядочивание списков файлов
- •8.6.7 Утилита Head для Windows
8.6.2 Добавление строк в окно списка
После того, как вы создали окно списка, следующим шагом должно стать добавление в список строк текста. Вы делаете это, используя функцию SendMessage для отправки сообщения окну списка. Ссылка на строки текста обычно осуществляется через индекс, который начинается с 0, что соответствует самому верхнему элементу списка. В приводимых далее примерах hwndList — это описатель дочернего окна управления, т. е. окна списка, а iIndex — это значение индекса. В тех случаях, когда вы с помощью вызова функции SendMessage передаете строку текста, параметр lParam является указателем на эту оканчивающуюся нулем строку.
В большинстве приводимых примеров функция SendMessage может вернуть значение LB_ERRSPACE (равное — 2), если оконной процедуре не хватит памяти для сохранения содержимого списка. Если случится любая другая ошибка, то возвращаемым значением функции SendMessage будет LB_ERR (—1), а при ее нормальной работе — LB_OKAY (0). Вы можете проверять функцию SendMessage на 0, чтобы определить наличие каждой из этих двух ошибок.
Если вы используете стиль LBS_SORT (или, если вы располагаете строки в списке в том порядке, в котором вы хотите, чтобы они появлялись), то простейшим способом заполнить список будет использование сообщения LB_ADDSTRING:
SendMessage(hwndList, LB_ADDSTRING, 0,(LPARAM) szString);
Если вы не используете стиль LBS_SORT, то можете вставить строку в ваш список, задав индекс и используя сообщение LB_INSERTSTRING:
SendMessage(hwndList, LB_INSERTSTRING, iIndex,(LPARAM) szString);
Например, если iIndex равен 4, то szString становится новой, пятой строкой, начиная от вершины списка (поскольку счет начинается с 0) со значением индекса, равным 4. Все расположенные ниже строки сдвигаются вниз. При iIndex равном —1 строка становится последней строкой списка. Сообщение LB_INSERTSTRING можно использовать и со списком стиля LBS_SORT, но тогда содержимое списка не будет пересортировано. (Вы также можете вставить строку с помощью сообщения LB_DIR, о котором более подробно будет рассказано в конце главы.)
Удалить строку из списка можно с помощью сообщения LB_DELETESTRING, указав значение индекса:
SendMessage(hwndList, LB_DELETESTRING, iIndex, 0);
Полностью очистить список можно с помощью сообщения LB_RESETCONTENT:
SendMessage(hwndList, LB_RESETCONTENT, 0, 0);
Оконная процедура окна списка обновляет окно, если к списку добавляется или из списка удаляется элемент. Если вам известно число строк, которые необходимо добавить или удалить, то вам может понадобиться временно приостановить это обновление, сбросив флаг обновления окна:
SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
После окончания работы по изменению списка, вам следует восстановить флаг обновления окна:
SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
Окно списка, созданное со стилем LBS_NOREDRAW, открывается со сброшенным флагом обновления окна.
8.6.3 Выбор и извлечение элементов списка
Вызовы функции SendMessage, которые выполняются в представленных ниже задачах, обычно возвращают какое-то значение. Если имеет место ошибка, то это значение устанавливается в LB_ERR (определено как —1).
После того, как вы вставили в список несколько элементов, вы можете определить количество элементов в списке:
iCount = SendMessage(hwndList, LB_GETCOUNT, 0, 0);
Некоторые другие вызовы различаются для списков с единичной выборкой и для списков с множественной выборкой. Сначала рассмотрим список с единичной выборкой.
Обычно вы разрешаете пользователю выбирать из списка. Но если вы хотите выделить элемент, выбираемый по умолчанию, то можете использовать такой вызов:
SendMessage(hwndList, LB_SETCURSEL, iIndex, 0);
При установке в качестве iIndex значения —1, выборка для всех элементов отменяется.
Вы также можете выбирать элемент списка на основе его первых символов:
iIndex = SendMessage(hwndList, LB_SELECTSTRING, iIndex,(LPARAM) szSearchString);
Величина iIndex, заданная в качестве параметра lParam функции SendMessage, является номером пункта, с которого начинается поиск пункта, начальные символы которого заданы в szSearchString. При значении iIndex равном —1, поиск начинается с начала списка. Возвращаемым значением функции SendMessage является индекс выбранного элемента или LB_ERR, если в списке нет элементов, с начальными символами из строки szSearchString.
Когда вы получаете от окна списка сообщение WM_COMMAND (или в любое другое время), с помощью сообщения LB_GETCURSEL вы можете определить индекс текущего выбранного элемента:
iIndex = SendMessage(hwndList, LB_GETCURSEL, 0, 0);
Если возвращаемое значение функции SendMessage равно LB_ERR, то это означает отсутствие выбранных элементов.
Вы можете определить длину строки любого элемента списка:
iLength = SendMessage(hwndList, LB_GETTEXTLEN, iIndex, 0);
Копировать выбранную строку в буфер можно следующим образом:
iLength = SendMessage(hwndList, LB_GETTEXT, iIndex,(LPARAM) szBuffer);
В обоих случаях возвращаемое значение функции SendMessage, т. е. iLength, это длина строки. Массив szBuffer должен быть достаточно большим, чтобы вместить строку и завершающий NULL-символ. Для предварительного выделения памяти для хранения строки, можно использовать сообщение LB_GETTEXTLEN.
В списке с множественным выбором нельзя использовать сообщения LB_SETCURSEL, LB_GETCURSEL или LB_SELECTSTRING. Вместо них вы используете сообщение LB_SETSEL для установки состояния выборки конкретного элемента, при этом не оказывая влияния на другие элементы, которые могли бы быть выбраны:
SendMessage(hwndList, LB_SETSEL, wParam, iIndex);
Параметр wParam не равен 0 для выбора и выделения элемента списка и равен 0 для отмены выбора. Если параметр lParam равен —1, то все элементы списка либо выбираются, либо их выбор отменяется. Определить, выбран или нет конкретный элемент списка, можно с помощью вызова:
iSelect = SendMessage(hwndList, LB_GETSEL, iIndex, 0);
где iSelect не равно нулю, если пункт с номером iIndex выбран, и равно 0 — в противном случае.