- •Содержание
- •Глава 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
89
3 * cxClient / 4, 3 * cyClient / 4, cxClient / 4, cyClient / 4);
EndPaint(hwnd, &ps); return 0;
case WM_DESTROY: PostQuitMessage(0); return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Рис. 4.12 Программа LINEDEMO
Рис. 4.13 Окно программы LINEDEMO
Сплайны Безье
Слово "сплайн" раньше относилось к гибкому куску дерева, резины или металла, который использовали для рисования кривых на листе бумаги. Например, если вы имели несколько отстоящих друг от друга точек, и вы хотели соединить их с помощью кривой (для интерполяции или экстраполяции), вы должны были, во-первых, отметить эти точки на чертежной бумаге, затем "привязать" сплайн к точкам и карандашом нарисовать кривую по сплайну так, как он был изогнут вокруг точек. (Пожалуйста, не смейтесь. Кажется, что так могло быть только в 19 веке, но хорошо известно, что механические сплайны использовались страховыми служащими, рассчитывавшими вероятность страхового случая, еще 15 лет назад.)
В наше время, конечно, сплайны — это математические выражения. Они имеют самые разные применения. Сплайны Безье — одни из самых популярных в программировании компьютерной графики. Это совсем недавнее усовершенствование в арсенале графических средств, доступных на уровне операционной системы, и оно пришло с неожиданной стороны. В шестидесятых годах автомобильная компания Renault переходила от ручного проектирования кузовов автомобилей (что требовало много глины) к компьютерному. Требовался математический аппарат, и Пьер Безье предложил набор формул, оказавшихся очень полезными в этой работе.
С тех пор двумерная форма сплайна Безье показала себя как самая удобная кривая (после прямых линий и эллипсов) в компьютерной графике. Например, в языке PostScript сплайны Безье используются для всех кривых — эллиптические линии аппроксимируются из сплайнов Безье. Кривые Безье также используются для описания контуров символов различных шрифтов языка PostScript. (TrueType используют более простые и быстрые формы сплайнов.)
Простой двумерный сплайн Безье определяется четырьмя точками — двумя конечными и двумя контрольными. Концы кривой привязаны к двум конечным точкам. Контрольные точки выступают в роли магнитов для оттягивания кривой от прямой, соединяющей две крайние точки. Это лучше всего иллюстрируется интерактивной программой BEZIER, приведенной на рис. 4.14.
90
BEZIER.MAK
#----------------------
# BEZIER.MAK make file
#----------------------
bezier.exe : bezier.obj
$(LINKER) $(GUIFLAGS) -OUT:bezier.exe bezier.obj $(GUILIBS)
bezier.obj : bezier.c
$(CC) $(CFLAGS) bezier.c
BEZIER.C
/*--------------------------------------- |
|
|
BEZIER.C -- |
Bezier Splines Demo |
|
|
(c) Charles Petzold, |
1996 |
--------------------------------------- |
|
*/ |
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = "Bezier";
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, "Bezier Splines", 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 DrawBezier(HDC hdc, POINT apt[])
{
91
PolyBezier(hdc, apt, 4);
MoveToEx(hdc, apt[0].x, apt[0].y, NULL);
LineTo (hdc, apt[1].x, apt[1].y);
MoveToEx(hdc, apt[2].x, apt[2].y, NULL);
LineTo (hdc, apt[3].x, apt[3].y);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static POINT apt[4];
HDC |
hdc; |
int |
cxClient, cyClient; |
PAINTSTRUCT |
ps; |
switch(iMsg)
{
case WM_SIZE:
cxClient = LOWORD(lParam); cyClient = HIWORD(lParam);
apt[0].x = cxClient / 4; apt[0].y = cyClient / 2;
apt[1].x = cxClient / 2; apt[1].y = cyClient / 4;
apt[2].x = cxClient / 2;
apt[2].y = 3 |
* |
cyClient / 4; |
|
apt[3].x = |
3 |
* cxClient / 4; |
|
apt[3].y = |
|
|
cyClient / 2; |
return 0;
case WM_MOUSEMOVE:
if(wParam & MK_LBUTTON || wParam & MK_RBUTTON)
{
hdc = GetDC(hwnd);
SelectObject(hdc, GetStockObject(WHITE_PEN));
DrawBezier(hdc, apt);
if(wParam & MK_LBUTTON)
{
apt[1].x = LOWORD(lParam); apt[1].y = HIWORD(lParam);
}
if(wParam & MK_RBUTTON)
{
apt[2].x = LOWORD(lParam); apt[2].y = HIWORD(lParam);
}
SelectObject(hdc, GetStockObject(BLACK_PEN));
DrawBezier(hdc, apt);
ReleaseDC(hwnd, hdc);
}
return 0; case WM_PAINT:
InvalidateRect(hwnd, NULL, TRUE);
92
hdc = BeginPaint(hwnd, &ps);
DrawBezier(hdc, apt);
EndPaint(hwnd, &ps); return 0;
case WM_DESTROY: PostQuitMessage(0); return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Рис. 4.14 Программа BEZIER
Поскольку эта программа использует логику обработки мыши (об этом пойдет речь в главе 6), здесь не будут объясняться принципы ее функционирования (это было бы преждевременным). Вместо этого, поэкспериментируйте со сплайнами Безье. В этой программе две крайние точки установлены на половине высоты и на 1/4 и 3/4 ширины рабочей зоны окна. Двумя контрольными точками можно манипулировать: первой — нажатием левой кнопки мыши и перемещением мыши, второй — нажатием правой кнопки мыши и перемещением. На рис. 4.15 показан типовой вид окна программы.
Кроме самого сплайна Безье программа также отображает слева прямую линию из первой контрольной точки в первую крайнюю точку (или начальную точку) и прямую линию из второй контрольной точки в конечную точку справа.
Сплайны Безье считаются полезными для компьютерного проектирования благодаря следующим характеристикам: Во-первых, немного попрактиковавшись, вы можете легко манипулировать кривой для получения нужной формы.
Во-вторых, сплайны Безье очень легко управляются. В некоторых формах сплайнов кривая не может быть проведена через все определяющие точки. Сплайны Безье всегда "привязаны" к двум конечным точкам. (Это первое допущение, которое берет начало в формулах Безье.) Кроме того, существуют сплайны с бесконечными кривыми, которые имеют свои особенности. В компьютерном проектировании редко встречаются подобные типы сплайнов. Как правило, кривые Безье всегда ограничены четырехэлементной ломаной, называемой "выпуклым корпусом" (convex hull), которая получается соединением конечных и контрольных точек.
В-третьих, в сплайнах Безье существует связь между конечными и контрольными точками. Кривая всегда является касательной к прямой, соединяющей начальную точку и первую контрольную точку, и направленной в ту же сторону. (Это иллюстрируется программой BEZIER.) Кривая также является касательной к прямой, соединяющей конечную точку и вторую контрольную точку, и направленной в ту же сторону. Это еще два допущения на основе формул Безье.
В-четвертых, сплайны Безье в основном хорошо смотрятся. Понятно, что это критерий субъективный, но так считают многие.
До появления Windows 95 сплайны Безье создавались с помощью функции Polyline. Вам следовало также знать параметрические уравнения, описывающие сплайны Безье. Начальная точка (x0,y0), конечная точка (x3, y3). Две контрольные точки (x1, y1) и (x2, y2). Кривая, отображаемая в интервале t от 0 до 1 описывалась так:
x(t) = (1—t)3x0 + 3t(1—t)2x1 + 3t2(1—t)x2 +t3x3 y(t) = (1—t)3y0 + 3t(1—t)2y1 + 3t2(1—t)y2 +t3y3
В Windows 95 эти формулы знать не нужно. Для того, чтобы нарисовать одну или более связанных сплайнов Безье, используйте:
PolyBezier(hdc, pt, iCount);
или
PolyBezierTo(hdc, pt, iCount);
В обоих случаях pt — массив структур типа POINT. В функции PolyBezier первые четыре точки идут в таком порядке: начальная точка, первая контрольная точка, вторая контрольная точка, конечная точка кривой Безье. Каждая следующая кривая Безье требует три новых точки, поскольку начальная точка следующей кривой есть