- •Содержание
- •Глава 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
278
Окрашивание полос прокрутки и статического текста
Впрограмме COLORS1 внутренние участки трех полос прокрутки и текст шести текстовых полей окрашиваются красным, зеленым и голубым цветами. Окрашивание полос прокрутки осуществляется путем обработки сообщений WM_CTLCOLORSCROLLBAR.
ВWndProc мы для кистей определяем статический массив трех описателей:
static HBRUSH hBrush[3];
При обработке сообщения WM_CREATE мы создаем три кисти:
for(i = 0; i < 3; i++)
hBrush[i] = CreateSolidBrush(crPrim[i]);
где в массиве crPrim хранятся RGB-значения трех первичных цветов. При обработке сообщений WM_CTLCOLORSCROLLBAR, возвращаемым значением оконной процедуры является одна из этих трех кистей:
case WM_CTLCOLORSCROLLBAR:
i = GetWindowLong((HWND) lParam, GWW_ID); return(LRESULT) hBrush[i];
При обработке сообщения WM_DESTROY эти три кисти должны быть удалены:
for(i = 0; i < 3; DeleteObject(hBrush[i++]));
Аналогичным образом, путем обработки сообщения WM_CTLCOLORSTATIC и вызова функции SetTextColor, окрашивается текст в статических текстовых полях. Фон текста устанавливается функцией SetBkColor с системным цветом COLOR_BTNHIGHLIGHT. Это приводит к тому, что фон текста становится таким же, как цвет статического прямоугольника окна управления, который находится позади полос прокрутки и текста. Для статических дочерних текстовых окон управления этот цвет фона относится только к прямоугольнику позади каждого символа строки, а не ко всей ширине окна управления. Для того, чтобы это реализовать, оконная процедура должна также возвращать описатель кисти цвета COLOR_BTNHIGHLIGHT. Эта кисть называется hBrushStatic и создается при обработке сообщения WM_CREATE, а удаляется при обработке сообщения
WM_DESTROY.
Создав, при обработке сообщения WM_CREATE, кисть на основе цвета COLOR_BTNHIGHLIGHT, и пользуясь ею на протяжении работы программы, мы создали себе маленькую проблему. Если во время работы программы цвет COLOR_BTNHIGHLIGHT изменяется, то изменится и цвет статического прямоугольника, а также цвет его текстового фона, однако весь фон текстового окна управления останется прежним — COLOR_BTNHIGHLIGHT.
Для решения этой проблемы в программе COLORS1 обрабатывается сообщение WM_SYSCOLORCHANGE путем простого повторного создания кисти hBrushStatic, использующей новый цвет.
Класс редактирования
Класс редактирования (edit) является, в некотором смысле, простейшим из предопределенных в Windows классов окна, хотя с других точек зрения он оказывается и более сложным. Когда вы создаете дочернее окно, используя имя класса "edit", вы определяете прямоугольник на основе параметров положения х и у, ширины и высоты функции CreateWindow. В этом прямоугольнике содержится редактируемый текст. Когда дочернее окно управления имеет фокус ввода, вы можете набирать текст, двигать курсор, выбирать группы символов, используя либо мышь, либо клавишу <Shift> и клавиши управления курсором, удалять выбранный текст в папку обмена нажимая комбинацию клавиш <Ctrl>+<X>, копировать текст нажимая комбинацию клавиш <Ctrl>+<С>, и вставлять текст из папки обмена используя комбинацию клавиш <Ctrl>+<V>.
Одним из простейших применений окон редактирования — элементов управления (или управляющих окон редактирования, edit controls) является простое однострочное окно ввода данных. Но окна редактирования не ограничены только одной строкой, что иллюстрируется в программе POPPAD1, представленной на рис. 8.7. Как программы, с которыми мы уже сталкивались в этой книге, программа POPPAD будет модернизироваться с целью использования окон меню, диалога (для открытия и сохранения файлов) и принтеров. Последней версией программы будет простой, но полноценный текстовый редактор с небольшими добавлениями, которые потребуется сделать для его реализации в тексте нашей программы.
POPPAD1.MAK
#-----------------------
# POPPAD1.MAK make file
#-----------------------
poppad1.exe : poppad1.obj
279
$(LINKER) $(GUIFLAGS) -OUT:poppad1.exe poppad1.obj $(GUILIBS)
poppad1.obj : poppad1.c
$(CC) $(CFLAGS) poppad1.c
POPPAD1.C
/*------------------------------------------------------- |
|
POPPAD1.C -- |
Popup Editor using child window edit box |
|
(c) Charles Petzold, 1996 |
------------------------------------------------------- |
*/ |
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
char szAppName[] = "PopPad1";
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{ |
|
|
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, szAppName, 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;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndEdit;
switch(iMsg)
{
case WM_CREATE :
hwndEdit = CreateWindow("edit", NULL,
WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
280
WS_BORDER | ES_LEFT | ES_MULTILINE |
ES_AUTOHSCROLL | ES_AUTOVSCROLL,
0, 0, 0, 0, hwnd,(HMENU) 1,
((LPCREATESTRUCT) lParam) -> hInstance, NULL); return 0;
case WM_SETFOCUS : SetFocus(hwndEdit); return 0;
case WM_SIZE :
MoveWindow(hwndEdit, 0, 0, LOWORD(lParam),
HIWORD(lParam), TRUE);
return 0;
case WM_COMMAND : if(LOWORD(wParam) == 1)
if(HIWORD(wParam) == EN_ERRSPACE || HIWORD(wParam) == EN_MAXTEXT)
MessageBox(hwnd, "Edit control out of space.", szAppName, MB_OK | MB_ICONSTOP);
return 0; case WM_DESTROY :
PostQuitMessage(0); return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Рис. 8.7 Программа POPPAD1
Программа POPPAD1 — это многострочный текстовый редактор (хотя пока еще и без возможности ввода/вывода файлов), который уместился в менее чем 100 строках текста на языке С. (Один недостаток, тем не менее, имеется. Он состоит в том, что предопределенное многострочное окно редактирования не позволяет редактировать текст размером более 32 килобайт.) Как видите, сама программа POPPAD1 делает немного. Предопределенное окно редактирования делает достаточно много. По этой причине программа позволяет вам узнать о потенциальных возможностях управляющего окна редактирования как такового, без помощи вашей программы.
Стили класса редактирования
Как уже говорилось, вы создаете управляющее окно редактирования, используя в качестве имени класса окна "edit" при вызове функции CreateWindow. Стилем окна является WS_CHILD и еще несколько опций. Как и в статических дочерних окнах управления, текст в управляющих окнах редактирования может быть выравнен либо по левому краю, либо по правому, либо по центру. Формат можно задать с помощью стилей окна ES_LEFT, ES_RIGHT и ES_CENTER.
По умолчанию в управляющем окне редактирования имеется одна строка. Вы можете создать многострочное управляющее окно редактирования, используя стиль окна ES_MULTILINE. Для однострочного управляющего окна редактирования обычно можно вводить текст только в конце прямоугольника редактирования. Для создания управляющего окна редактирования с автоматической горизонтальной прокруткой используйте стиль ES_AUTOHSCROOL. Для многострочного управляющего окна редактирования, если не задан стиль ES_AUTOHSCROOL, то текст автоматически переносится на новую строку. При задании этого стиля для перехода на новую строку нужно нажимать клавишу <Enter>. Используя стиль окна ES_AUTOVSCROOL, в многострочное управляющее окно редактирования можно включить полосу вертикальной прокрутки.
Если вы включите эти стили прокрутки в многострочные управляющие окна редактирования, то вы можете добавить полосы прокрутки к управляющему окну редактирования. Это делается путем использования тех же идентификаторов стиля окна, что и для недочерних окон: WS_HSCROLL и WS_VSCROLL.
По умолчанию в управляющем окне редактирования отсутствует рамка окна. Добавить ее можно, используя стиль
WS_BORDER.
Когда вы выделяете текст в управляющем окне редактирования, Windows отображает его на экране в инвертированном виде. Однако, при потере управляющим окном редактирования фокуса ввода, выбранный текст
281
больше не выделяется. Если вы хотите, чтобы выделенный текст подсвечивался даже в том случае, если управляющее окно редактирования не имеет фокуса ввода, вы можете использовать стиль ES_NOHIDESEL.
Когда в программе POPPAD1 создается управляющее окно редактирования, его стиль при вызове функции CreateWindow задается равным:
WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL
Далее в программе POPPAD1 определяются размеры управляющего окна редактирования, это делается путем вызова функции MoveWindow при получении оконной процедурой WndProc сообщения WM_SIZE. Размер управляющего окна просто устанавливается равным размеру главного окна:
MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
Для однострочного управляющего окна редактирования высота окна должна соответствовать высоте символа. Если управляющее окно редактирования имеет рамку (как чаще и бывает), используйте полуторную высоту символа (включая межстрочное пространство).
Коды уведомления управляющих окон редактирования
Окна редактирования посылают оконной процедуре родительского окна сообщения WM_COMMAND. Значения переменных lParam и wParam, являющихся параметрами этих сообщений такие же, как и для кнопок управления:
Параметр |
Описание |
LOWORD (wParam) |
Идентификатор дочернего окна |
HIWORD (wParam) |
Код уведомления |
lParam |
Описатель дочернего окна |
Ниже представлены коды уведомления управляющих окон редактирования:
EN_SETFOCUS |
Окно получило фокус ввода |
EN_KILLFOCUS |
Окно потеряло фокус ввода |
EN_CHANGE |
Содержимое окна будет меняться |
EN_UPDATE |
Содержимое окна изменилось |
EN_ERRSPACE |
Произошло переполнение буфера редактирования |
EN_MAXTEXT |
Произошло переполнение буфера редактирования при вставке |
EN_HSCROLL |
На горизонтальной полосе прокрутки был щелчок мышью |
EN_VSCROLL |
На вертикальной полосе прокрутки был щелчок мышью |
В программе POPPAD1 обрабатываются только коды уведомления EN_ERRSPACE и EN_MAXTEXT. При получении этих уведомлений на экран выводится окно сообщений.
Управляющие окна редактирования хранят текст в области памяти программы их родительского окна. Как уже отмечалось ранее, содержимое управляющего окна редактирования ограничено примерно 32 килобайтами.
Использование управляющих окон редактирования
Если вы используете несколько однострочных управляющих окон редактирования на поверхности вашего главного окна, то для передачи фокуса ввода от окна к окну вам понадобится вводить новую оконную процедуру. Вы можете это сделать также, как это делается в программе COLORS1, перехватывая нажатия клавиш <Tab> и <Shift>+<Tab>. (Другой пример введения новой оконной процедуры показан далее в этой главе в программе HEAD.) То как использовать клавишу <Enter> — дело ваше. Вы можете управлять ею также, как клавишей <Tab> или использовать ее как сигнал для программы, что все поля редактирования готовы.
Если вы хотите поместить в редактируемое поле текст, вы можете воспользоваться функцией SetWindowText. Для получения текста из окна редактирования используются функции GetWindowTextLength и GetWindowText. Мы рассмотрим примеры таких возможностей в более поздних версиях программы POPPAD.
Сообщения управляющему окну редактирования
Мы не станем обсуждать все сообщения, которые мы можем послать управляющему окну редактирования с помощью функции SendMessage, поскольку их достаточно много, а некоторые будут использоваться в следующих версиях программы POPPAD. Здесь дан общий обзор.