- •Содержание
- •Глава 1 README.TXT
- •Вызов, брошенный программистам
- •Основные правила
- •Краткая история Windows
- •Краткая история этой книги
- •Начнем
- •Глава 2 Hello, Windows 95
- •Отличительная особенность Windows
- •Графический интерфейс пользователя
- •Концепции и обоснование GUI
- •Содержимое интерфейса пользователя
- •Преимущество многозадачности
- •Управление памятью
- •Независимость графического интерфейса от оборудования
- •Соглашения операционной системы Windows
- •Вызовы функций
- •Объектно-ориентированное программирование
- •Архитектура, управляемая событиями
- •Оконная процедура
- •Ваша первая программа для Windows
- •Что в этой программе неправильно?
- •Файлы HELLOWIN
- •Make-файл
- •Вызовы функций Windows
- •Идентификаторы, написанные прописными буквами
- •Новые типы данных
- •Описатели
- •Венгерская нотация
- •Точка входа программы
- •Регистрация класса окна
- •Создание окна
- •Отображение окна
- •Цикл обработки сообщений
- •Оконная процедура
- •Обработка сообщений
- •Воспроизведение звукового файла
- •Сообщение WM_PAINT
- •Сообщение WM_DESTROY
- •Сложности программирования для Windows
- •Не вызывай меня, я вызову тебя
- •Синхронные и асинхронные сообщения
- •Думайте о ближнем
- •Кривая обучения
- •Глава 3 Рисование текста
- •Рисование и обновление
- •Сообщение WM_PAINT
- •Действительные и недействительные прямоугольники
- •Введение в графический интерфейс устройства (GDI)
- •Контекст устройства
- •Структура информации о рисовании
- •Получение описателя контекста устройства. Второй метод
- •Функция TextOut. Подробности
- •Системный шрифт
- •Размер символа
- •Метрические параметры текста. Подробности
- •Форматирование текста
- •Соединим все вместе
- •Не хватает места!
- •Размер рабочей области
- •Полосы прокрутки
- •Диапазон и положение полос прокрутки
- •Сообщения полос прокрутки
- •Прокрутка в программе SYSMETS
- •Структурирование вашей программы для рисования
- •Создание улучшенной прокрутки
- •Мне не нравится пользоваться мышью
- •Глава 4 Главное о графике
- •Концепция GDI
- •Структура GDI
- •Типы функций
- •Примитивы GDI
- •Другие аспекты
- •Контекст устройства
- •Получение описателя контекста устройства
- •Программа DEVCAPS1
- •Размер устройства
- •О цветах
- •Атрибуты контекста устройства
- •Сохранение контекста устройства
- •Рисование отрезков
- •Ограничивающий прямоугольник
- •Сплайны Безье
- •Использование стандартных перьев
- •Создание, выбор и удаление перьев
- •Закрашивание пустот
- •Режимы рисования
- •Рисование закрашенных областей
- •Функция Polygon и режим закрашивания многоугольника
- •Закрашивание внутренней области
- •Режим отображения
- •Координаты устройства (физические координаты) и логические координаты
- •Системы координат устройства
- •Область вывода и окно
- •Работа в режиме MM_TEXT
- •Метрические режимы отображения
- •Ваши собственные режимы отображения
- •Программа WHATSIZE
- •Прямоугольники, регионы и отсечение
- •Работа с прямоугольниками
- •Случайные прямоугольники
- •Создание и рисование регионов
- •Отсечения: прямоугольники и регионы
- •Программа CLOVER
- •Пути
- •Создание и воспроизведение путей
- •Расширенные перья
- •Bits and Blts
- •Цвета и битовые образы
- •Файл DIB
- •Упакованный формат хранения DIB
- •Отображение DIB
- •Преобразование DIB в объекты "битовые образы"
- •Битовый образ — объект GDI
- •Создание битовых образов в программе
- •Формат монохромного битового образа
- •Формат цветного битового образа
- •Контекст памяти
- •Мощная функция BitBlt
- •Перенос битов с помощью функции BitBlt
- •Функция DrawBitmap
- •Использование других ROP кодов
- •Дополнительные сведения о контексте памяти
- •Растяжение битовых образов с помощью функции StretchBlt
- •Кисти и битовые образы
- •Метафайлы
- •Простое использование метафайлов памяти
- •Сохранение метафайлов на диске
- •Расширенные метафайлы
- •Делаем это лучше
- •Базовая процедура
- •Заглянем внутрь
- •Вывод точных изображений
- •Текст и шрифты
- •Вывод простого текста
- •Атрибуты контекста устройства и текст
- •Использование стандартных шрифтов
- •Типы шрифтов
- •Шрифты TrueType
- •Система EZFONT
- •Внутренняя работа
- •Форматирование простого текста
- •Работа с абзацами
- •Глава 5 Клавиатура
- •Клавиатура. Основные понятия
- •Игнорирование клавиатуры
- •Фокус ввода
- •Аппаратные и символьные сообщения
- •Аппаратные сообщения
- •Системные и несистемные аппаратные сообщения клавиатуры
- •Переменная lParam
- •Виртуальные коды клавиш
- •Использование сообщений клавиатуры
- •Модернизация SYSMETS: добавление интерфейса клавиатуры
- •Логика обработки сообщений WM_KEYDOWN
- •Посылка асинхронных сообщений
- •Символьные сообщения
- •Сообщения WM_CHAR
- •Сообщения немых символов
- •Каретка (не курсор)
- •Функции работы с кареткой
- •Программа TYPER
- •Наборы символов Windows
- •Набор символов OEM
- •Набор символов ANSI
- •Наборы символов OEM, ANSI и шрифты
- •Международные интересы
- •Работа с набором символов
- •Связь с MS-DOS
- •Использование цифровой клавиатуры
- •Решение проблемы с использованием системы UNICODE в Windows NT
- •Глава 6 Мышь
- •Базовые знания о мыши
- •Несколько кратких определений
- •Сообщения мыши, связанные с рабочей областью окна
- •Простой пример обработки сообщений мыши
- •Обработка клавиш <Shift>
- •Сообщения мыши нерабочей области
- •Сообщение теста попадания
- •Сообщения порождают сообщения
- •Тестирование попадания в ваших программах
- •Гипотетический пример
- •Пример программы
- •Эмуляция мыши с помощью клавиатуры
- •Добавление интерфейса клавиатуры к программе CHECKER
- •Использование дочерних окон для тестирования попадания
- •Дочерние окна в программе CHECKER
- •Захват мыши
- •Рисование прямоугольника
- •Решение проблемы — захват
- •Программа BLOKOUT2
- •Глава 7 Таймер
- •Основы использования таймера
- •Система и таймер
- •Таймерные сообщения не являются асинхронными
- •Использование таймера: три способа
- •Первый способ
- •Второй способ
- •Третий способ
- •Использование таймера для часов
- •Позиционирование и изменение размеров всплывающего окна
- •Получение даты и времени
- •Обеспечение международной поддержки
- •Создание аналоговых часов
- •Стандартное время Windows
- •Анимация
- •Класс кнопок
- •Создание дочерних окон
- •Сообщения дочерних окон родительскому окну
- •Сообщения родительского окна дочерним окнам
- •Нажимаемые кнопки
- •Флажки
- •Переключатели
- •Окна группы
- •Изменение текста кнопки
- •Видимые и доступные кнопки
- •Кнопки и фокус ввода
- •Дочерние окна управления и цвета
- •Системные цвета
- •Цвета кнопок
- •Сообщение WM_CTLCOLORBTN
- •Кнопки, определяемые пользователем
- •Класс статических дочерних окон
- •Класс полос прокрутки
- •Программа COLORS1
- •Интерфейс клавиатуры, поддерживаемый автоматически
- •Введение новой оконной процедуры
- •Закрашивание фона
- •Окрашивание полос прокрутки и статического текста
- •Класс редактирования
- •Стили класса редактирования
- •Коды уведомления управляющих окон редактирования
- •Использование управляющих окон редактирования
- •Сообщения управляющему окну редактирования
- •Класс окна списка
- •Стили окна списка
- •Добавление строк в окно списка
- •Выбор и извлечение элементов списка
- •Получение сообщений от окон списка
- •Простое приложение, использующее окно списка
- •Список файлов
- •Утилита Head для Windows
- •Компиляция ресурсов
- •Значки и курсоры
- •Редактор изображений
- •Получение описателя значков
- •Использование значков в вашей программе
- •Использование альтернативных курсоров
- •Битовые образы: картинки в пикселях
- •Использование битовых образов и кистей
- •Символьные строки
- •Использование ресурсов-символьных строк
- •Меню
- •Структура меню
- •Шаблон меню
- •Ссылки на меню в вашей программе
- •Меню и сообщения
- •Образец программы
- •Этикет при организации меню
- •Сложный способ определения меню
- •Третий подход к определению меню
- •Независимые всплывающие меню
- •Использование системного меню
- •Изменение меню
- •Другие команды меню
- •Использование в меню битовых образов
- •Два способа создания битовых образов для меню
- •Контекст памяти
- •Создание битового образа, содержащего текст
- •Масштабирование битовых образов
- •Соберем все вместе
- •Добавление интерфейса клавиатуры
- •Быстрые клавиши
- •Зачем нужны быстрые клавиши?
- •Некоторые правила назначения быстрых клавиш
- •Таблица быстрых клавиш
- •Преобразование нажатий клавиш клавиатуры
- •Получение сообщений быстрых клавиш
- •Программа POPPAD, имеющая меню и быстрые клавиши
- •Разрешение пунктов меню
- •Обработка опций меню
- •Глава 11 Окна диалога
- •Модальные окна диалога
- •Создание окна диалога About
- •Шаблон окна диалога
- •Диалоговая процедура
- •Вызов окна диалога
- •Дополнительная информация о стиле окна диалога
- •Дополнительная информация об определении дочерних окон элементов управления
- •Более сложное окно диалога
- •Работа с дочерними элементами управления окна диалога
- •Кнопки OK и Cancel
- •Позиции табуляции и группы
- •Рисование в окне диалога
- •Использование с окном диалога других функций
- •Определение собственных окон управления
- •Окна сообщений
- •Информация во всплывающих окнах
- •Немодальные окна диалога
- •Различия между модальными и немодальными окнами диалога
- •Новая программа COLORS
- •Программа HEXCALC: обычное окно или окно диалога?
- •Творческое использование идентификаторов дочерних окон элементов управления
- •Диалоговые окна общего пользования
- •Модернизированная программа POPPAD
- •Изменение шрифта
- •Поиск и замена
- •Программа для Windows, содержащая всего один вызов функции
- •Основы элементов управления общего пользования
- •Инициализация библиотеки
- •Создание элементов управления общего пользования
- •Стили элементов управления общего пользования
- •Уведомляющие сообщения от элементов управления общего пользования
- •Элементы управления главного окна
- •Панели инструментов
- •Создание панели инструментов
- •Строка состояния
- •Программа GADGETS
- •Наборы страниц свойств
- •Создание набора страниц свойств
- •Процедуры диалогового окна страницы свойств
- •Программа PROPERTY
109
Врежиме MM_ISOTROPIC похожий фрагмент программы приводил к тому, что часть рабочей области оказывалась за границами осей координат. В режиме MM_ANISOTROPIC правый верхний угол рабочей области
— это всегда точка (32767, 32767) независимо от размеров. Если рабочая область не квадратная, то логические координаты x и y будут иметь различные физические размерности.
Впредыдущем разделе говорилось о том, что в режиме отображения MM_ISOTROPIC в рабочей области можно создавать изображения, подобные изображению программы ANACLOCK, где оси x и y ранжированы от -1000 до 1000. Вы можете сделать нечто похожее в режиме MM_ANISOTROPIC:
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 1000, 1000, NULL);
SetViewportExtEx(hdc, cxClient / 2, -cyClient / 2, NULL);
SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);
Разница состоит в том, что в режиме MM_ANISOTROPIC часы, как правило, представлены в виде эллипса, а не окружности.
С другой стороны, вы можете использовать MM_ANISOTROPIC для установки фиксированных, но не равных друг другу, единиц измерения. Например, если ваша программа занимается только выводом текста, вы можете установить грубые координаты на базе высоты и ширины простого символа:
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 1, 1, NULL);
SetViewportExtEx(hdc, cxChar, cyChar, NULL);
(Здесь предполагается, что cxChar и cyChar — ширина и высота символа в пикселях для непропорционального шрифта.) Теперь вы можете в вызове функции TextOut задавать координаты символов как строку и столбец, не используя пиксельные координаты. Например, следующая инструкция выводит текст "Hello" с отступом в три символа слева и два символа сверху:
TextOut(hdc, 3, 2, "Hello", 5);
Это очень похоже на работу в среде MS DOS, а не Windows.
Когда вы впервые устанавливаете режим отображения MM_ANISOTROPIC, он всегда наследует значения протяженностей от предыдущего установленного режима. Это может быть очень удобно. Режим MM_ANISOTROPIC как бы снимает "блокировку" протяженности, т. е. позволяет изменять значения протяженностей. В этом его отличие от полностью принудительных метрических режимов отображения. Например, предположим, используется режим отображения MM_LOENGLISH, и требуется, чтобы логическая единица измерения равнялась 0.01 дюйма. Причем нежелательно, чтобы значения по координате y увеличивались при движении вверх, нужно, чтобы, как в режиме MM_TEXT, значения координаты y увеличивались при движении вниз. Ниже приведен код, реализующий это:
SIZE size;
[другие строки программы]
SetMapMode(hdc, MM_LOENGLISH); SetMapMode(hdc, MM_ANISOTROPIC);
GetViewportExtEx(hdc, &size);
SetViewportExtEx(hdc, size.cx, -size.cy, NULL );
Сначала мы устанавливаем режим отображения MM_LOENGLISH. Затем мы даем возможность изменять протяженности, устанавливая режим отображения MM_ANISOTROPIC. Функция GetViewportExtEx записывает протяженности области вывода в поля структуры SIZE. Затем мы вызываем функцию SetViewportExtEx с теми же значениями протяженностей, за исключением того, что протяженность по оси y делается отрицательной.
Программа WHATSIZE
Мы будем использовать различные режимы отображения по мере того, как будем далее изучать функции GDI в следующих главах. Сейчас же давайте взглянем на размер рабочей области в терминах дюймов и миллиметров. Программа WHATSIZE, приведенная на рис. 4.19, отображает размер рабочей области в терминах единиц, ассоциированных с шестью полностью принудительными режимами отображения: MM_TEXT, MM_LOMETRIC, MM_HIMETRIC, MM_LOENGLISH, MM_HIENGLISH и MM_TWIPS.
WHATSIZE.MAK
#------------------------
# WHATSIZE.MAK make file
#------------------------
110
whatsize.exe : whatsize.obj
$(LINKER) $(GUIFLAGS) -OUT:whatsize.exe whatsize.obj $(GUILIBS)
whatsize.obj : whatsize.c
$(CC) $(CFLAGS) whatsize.c
WHATSIZE.C
/*-----------------------------------------
WHATSIZE.C -- What Size is the Window?
(c) Charles Petzold, 1996
-----------------------------------------*/
#include <windows.h> #include <stdio.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = "WhatSize";
HWND |
hwnd; |
MSG |
msg; |
WNDCLASSEX |
wndclass; |
wndclass.cbSize |
= sizeof(wndclass); |
wndclass.style |
= CS_HREDRAW | CS_VREDRAW; |
wndclass.lpfnWndProc |
= WndProc; |
wndclass.cbClsExtra |
= 0; |
wndclass.cbWndExtra |
= 0; |
wndclass.hInstance |
= hInstance; |
wndclass.hIcon |
= LoadIcon(NULL, IDI_APPLICATION); |
wndclass.hCursor |
= LoadCursor(NULL, IDC_ARROW); |
wndclass.hbrBackground |
=(HBRUSH) GetStockObject(WHITE_BRUSH); |
wndclass.lpszMenuName |
= NULL; |
wndclass.lpszClassName |
= szAppName; |
wndclass.hIconSm |
= LoadIcon(NULL, IDI_APPLICATION); |
RegisterClassEx(&wndclass);
hwnd = CreateWindow(szAppName, "What Size is the Window?", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
void Show(HWND hwnd, HDC hdc, int xText, int yText, int iMapMode, char *szMapMode)
{
char szBuffer [60]; RECT rect;
SaveDC(hdc);
111
SetMapMode(hdc, iMapMode);
GetClientRect(hwnd, &rect);
DPtoLP(hdc,(PPOINT) &rect, 2);
RestoreDC(hdc, -1);
TextOut(hdc, xText, yText, szBuffer,
sprintf(szBuffer, "%-20s %7d %7d %7d %7d", szMapMode, rect.left, rect.right, rect.top, rect.bottom));
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{ |
|
|
|
|
|
static char |
szHeading [] = |
|
|
|
|
|
"Mapping Mode |
Left |
Right |
Top |
Bottom"; |
static char |
szUndLine [] = |
|
|
|
|
|
"------------ |
---- |
----- |
--- |
------"; |
static int |
cxChar, cyChar; |
|
|
|
|
HDC |
hdc; |
|
|
|
|
PAINTSTRUCT |
ps; |
|
|
|
|
TEXTMETRIC |
tm; |
|
|
|
|
switch(iMsg)
{
case WM_CREATE:
hdc = GetDC(hwnd);
SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(hdc, &tm); cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hwnd, hdc); return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
SetMapMode(hdc, MM_ANISOTROPIC);
SetWindowExtEx(hdc, 1, 1, NULL);
SetViewportExtEx(hdc, cxChar, cyChar, NULL);
TextOut(hdc, 1, 1, szHeading, sizeof szHeading - 1);
TextOut(hdc, 1, 2, szUndLine, sizeof szUndLine - 1);
Show(hwnd, hdc, 1, 3, MM_TEXT, |
"TEXT(pixels)"); |
Show(hwnd, hdc, 1, 4, MM_LOMETRIC, |
"LOMETRIC(.1 mm)"); |
Show(hwnd, hdc, 1, 5, MM_HIMETRIC, |
"HIMETRIC(.01 mm)"); |
Show(hwnd, hdc, 1, 6, MM_LOENGLISH, |
"LOENGLISH(.01 in)"); |
Show(hwnd, hdc, 1, 7, MM_HIENGLISH, |
"HIENGLISH(.001 in)"); |
Show(hwnd, hdc, 1, 8, MM_TWIPS, |
"TWIPS(1/1440 in)"); |
EndPaint(hwnd, &ps); return 0;
case WM_DESTROY: PostQuitMessage(0); return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Рис. 4.19 Программа WHATSIZE
Для упрощения вывода информации с использованием функции TextOut программа WHATSIZE использует режим отображения MM_ANISOTROPIC с логическими координатами, установленными на базе размеров символа: