- •Содержание
- •Глава 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
Глава 7 |
Таймер |
7 |
|
Таймер в Windows является устройством ввода информации, которое периодически извещает приложение о том, что истек заданный интервал времени. Ваша программа задает Windows интервал, как бы говоря системе: "Подталкивай меня каждые 10 секунд." Тогда Windows посылает вашей программе периодические сообщения WM_TIMER, сигнализируя об истечении интервала времени.
Сначала таймер Windows может показаться менее важным устройством ввода, чем клавиатура или мышь, и, конечно, это верно для многих приложений Windows. Но таймер более полезен, чем вы можете подумать, и не только для программ, которые индицируют время, таких как программа Windows clock, появляющаяся на панели задач. (В эту главу включены две программы clock — аналоговая и цифровая.) Существуют также и другие применения таймера в Windows, некоторые из которых, может быть, не столь очевидны:
•Многозадачность — Хотя Windows 95 является вытесняющей многозадачной средой, иногда самое эффективное решение для программы — как можно быстрее вернуть управление Windows. Если программа должна выполнять большой объем работы, она может разделить задачу на части и отрабатывать каждую часть при получении сообщения WM_TIMER. (Этот вопрос более полно будет рассмотрен в главе 14.)
•Поддержка обновления информации о состоянии — Программа может использовать таймер для вывода на экран обновляемой в "реальном времени" (real-time), постоянно меняющейся информации, связанной либо с системными ресурсами, либо с процессом выполнения определенной задачи.
•Реализация "автосохранения" — Таймер может предложить программе для Windows сохранять работу пользователя на диске всегда, когда истекает заданный интервал времени.
•Завершение демонстрационных версий программ — Некоторые демонстрационные версии программ рассчитаны на свое завершение, скажем, через 30 минут после запуска. Таймер может сигнализировать таким приложениям, когда их время истекает.
•Задание темпа изменения — Графические объекты в играх или окна с результатами в обучающих программах могут нуждаться в задании установленного темпа изменения. Использование таймера устраняет неритмичность, которая могла бы возникнуть из-за разницы в скоростях работы различных микропроцессоров.
•Мультимедиа — Программы, которые проигрывают аудиодиски, звук или музыку, часто допускают воспроизведение звуковых данных в фоновом режиме. Программа может использовать таймер для периодической проверки объема воспроизведенной информации и координации его с информацией, выводимой на экран.
Вэту главу также включены разделы, в которых использование таймера распространено и на другие области программирования для Windows. Мы уже касались концепции функций обратного вызова при работе с оконной процедурой, но функции обратного вызова встречаются и при программировании таймера. В этой главе рассказывается и о том, что делать, если программа не может получить доступа к таймеру. Эта тема теперь не столь актуальна, как в прежних версиях Windows, но сам метод, представленный здесь, также может применяться для обработки ошибок в других программах. И наконец, образцы программ, представленные здесь, связаны с такими совершенно нетаймерными задачами, как использование типа окна, известного как "всплывающее окно" (popup), доступ к файлу WIN.INI для получения информации о форматах международного времени и даты, и использование тригонометрии для эффективного вращения на экране графических объектов.
Основы использования таймера
Вы можете присоединить таймер к своей программе при помощи вызова функции SetTimer. Функция SetTimer содержит целый параметр, задающий интервал, который может находиться в пределах (теоретически) от 1 до 4 294 967 295 миллисекунд, что составляет около 50 дней. Это значение определяет темп, с которым Windows посылает
232
вашей программе сообщения WM_TIMER. Например, интервал в 1000 миллисекунд заставит Windows каждую секунду посылать вашей программе сообщение.
Если в вашей программе есть таймер, то она вызывает функцию KillTimer для остановки потока сообщений от таймера. Вы можете запрограммировать "однократный" таймер, вызывая функцию KillTimer при обработке сообщения WM_TIMER. Вызов функции KillTimer очищает очередь сообщений от всех необработанных сообщений WM_TIMER. После вызова функции KillTimer ваша программа никогда не получит случайного сообщения
WM_TIMER.
Система и таймер
Таймер в Windows является относительно простым расширением таймерной логики, встроенной в аппаратуру PC и ROM BIOS. ROM BIOS компьютера инициализирует микросхему таймера так, чтобы она генерировала аппаратное прерывание. Это прерывание иногда называют "тиком таймера". Эти прерывания генерируются каждые 54.925 миллисекунды или примерно 18,2 раза в секунду. Некоторые программы, написанные для MS-DOS, сами обрабатывают это аппаратное прерывание для реализации часов и таймеров.
В программах, сделанных для Windows, так не делается. Windows сама обрабатывает аппаратные прерывания и приложения их не получают. Для каждой программы, где в данный момент установлен таймер, Windows обрабатывает таймерное прерывание путем уменьшения на 1 значения счетчика, изначально переданного вызовом функции SetTimer. Когда это значение становится равным 0, Windows помещает сообщение WM_TIMER в очередь сообщений соответствующего приложения и восстанавливает начальное значение счетчика.
Поскольку приложения Windows получают сообщения WM_TIMER из обычной очереди сообщений, вам не нужно беспокоится о том, что ваша программа во время работы будет "прервана" внезапным сообщением WM_TIMER. В этом смысле таймер похож на клавиатуру и мышь: драйвер обрабатывает асинхронные аппаратные прерывания, а Windows преобразует эти прерывания в регулярные, структурированные, последовательные сообщения.
Таймер в Windows имеет ту же самую разрешающую способность 54.925 миллисекунды, что и встроенный таймер PC. Отсюда следуют два важных вывода:
•Приложение Windows при использовании простого таймера не сможет получать сообщения WM_TIMER в темпе, превышающем 18,2 раза в секунду.
•Временной интервал, который вы задаете при вызове функции SetTimer всегда округляется вниз до целого числа кратного частоте срабатываний таймера. Например, интервал в 1000 миллисекунд, разделенный на 54.925 миллисекунды равен 18.207 срабатываниям таймера, которые округляются вниз до 18 срабатываний, что фактически составляет интервал в 989, а не 1000 миллисекунд. Для интервалов, меньших 55 миллисекунд, каждое срабатывание таймера генерирует одно сообщение WM_TIMER.
Таймерные сообщения не являются асинхронными
Как уже упоминалось, программы под DOS, написанные для IBM PC и совместимых компьютеров, могут использовать аппаратные срабатывания таймера, перехватывая аппаратное прерывание. Когда происходит аппаратное прерывание, выполнение текущей программы приостанавливается и управление передается обработчику прерываний. Когда прерывание обработано, управление возвращается прерванной программе.
Также как аппаратные прерывания клавиатуры и мыши, аппаратное прерывание таймера иногда называется асинхронным прерыванием, поскольку оно происходит случайно по отношению к прерываемой программе. (Фактически, термин "асинхронные" не совсем точен, поскольку прерывания случаются через одинаковые промежутки времени. Но по отношению к другим процессам прерывания остаются асинхронными.)
Хотя Windows тоже обрабатывает асинхронные таймерные прерывания, сообщения WM_TIMER, которые Windows посылает приложению, не являются асинхронными. Сообщения Windows ставятся в обычную очередь сообщений и обрабатываются как все остальные сообщения. Поэтому, если вы задаете функции SetTimer 1000 миллисекунд, то вашей программе не гарантируется получение сообщения WM_TIMER каждую секунду или даже (как уже упоминалось выше) каждые 989 миллисекунд. Если ваше приложение занято больше, чем секунду, то оно вообще не получит ни одного сообщения WM_TIMER в течение этого времени. Вы можете убедиться в этом с помощью представленных в этой главе программ. Фактически, Windows обрабатывает сообщения WM_TIMER во многом также, как сообщения WM_PAINT. Оба эти сообщения имеют низкий приоритет, и программа получит только их, если в очереди нет других сообщений.
Сообщения WM_TIMER похожи на сообщения WM_PAINT и в другом смысле: Windows не хранит в очереди сообщений несколько сообщений WM_TIMER. Вместо этого Windows объединяет несколько сообщений WM_TIMER из очереди в одно сообщение. Поэтому, приложение не получает за раз группу сообщений WM_TIMER, хотя оно может получить два таких сообщения, быстро следующих одно за другим. В результате приложение не может определить число "потерянных" сообщений WM_TIMER.