Эта статья является продолжением статьи о создании счетчика просмотров для каждой страницы сайта на php и MySQL (если Вы ее не читали, то обязательно прочтите, иначе ничего не поймете из ниже сказанного). В этой статья я решил продолжить тему и расширить возможности счетчика просмотров страниц.
Для увеличения возможностей и получения статистики просмотров страниц сайта к базовому php скрипту необходимо добавить несколько строк и своих функций. В частности нужно будет создать еще одну таблицу, которая имеет следующую структуру:
Как видно из структуры MySQL таблицы, она состоит всего из двух полей (page_id – хэш сумма md5() от urla страницы и page_url – url страницы) и индекса, установленного на поле page_id – для значительного ускорения поиска значения в таблице. И еще, я не стал изменять изначальную таблицу my_log, которая использовалась для подсчета количества просмотров страниц, а создал другую по одной простой, но очень весомой причине: чем больше данных в таблице – тем медленнее осуществляется поиск по таблице. А скорость работы php скриптов такого уровня не должна ощутимо влиять на работу сайта в целом. Ведь если у вас коммерческий и при этом очень посещаемый сайт, то тратить строго ограниченное процессорное время на второстепенные задачи просто невыгодно, ведь зачастую прибыль зависит от того, сколько человек сможет увидеть ваш сайт.
Теперь перейдем непосредственно к коду php скрипта. Я внес в него незначительные изменения, в основном это новые функции для работы с MySQL таблицей my_log_urls.
В counter.php внес следующие изменения:
добавляем функцию Default_Write_URL
В результате, получаем значительную экономию времени т.к. делаем всего одну запись в таблицу my_log_urls и одну в my_log, и при следующих запросах этой же страницы запрос к таблице my_log_urls выполняться не будет, т.к. запись уже существует в таблице my_log, следовательно и в таблице my_log_urls она то же есть.
Для подсчета рейтинга страниц сайта, предлагаю написать другой php скрипт, который будет по значениям просмотров страницы в таблице my_log брать значения в таблице my_log_urls. А результат представлять в виде таблицы с данными о просмотрах страниц, отсортированными по убыванию (от большего значения к меньшему).
Ниже приведен код php скрипта, который необходимо скопировать в созданный вами файл top.php:
Данный php скрипт выводит 10 самых популярных страниц вашего сайта за последние сутки и за все время. В принципе, можно осуществлять вывод и большего числа страниц, изменив в php функциях MySQLReadAll и MySQLReadToday лимит считываемых из таблицы записей. А так же можно вместо самых популярных страниц увидеть самые непопулярные, изменив способ сортировки в этих же функциях с DESC на ASC.
Скачать данный php скрипт, вместе с модифицированным php скриптом подсчета просмотров страниц, можно по этой ссылке.
bluetooth - это технология, которая призвана заменить соединение сотового телефона, мобильного компьютера и других периферийных устройств между собой с помощью проводов, на более удобное соединение по радио каналу.
Немного истории.
Вообще-то, bluetooth дословно переводится как "Голубой зуб". Так прозвали когда-то короля викингов Харальда, жившего в Дании около тысячи лет назад. Прозвище это король получил за темный передний зуб.
Король Харальд вошел в историю как человек, объединивший Данию и принесший им христианство. Таким образом, именем исторической личности был назван протокол, который, по замыслу его создателей, так же должен творить историю.
Как все начиналось.
Где-то в начале 1998 года сразу несколько гигантов компьютерного и телекоммуникационного рынка, такие как ericsson, nokia, intel, ibm, toshiba, объединились с целью создания технологии беспроводного соединения между мобильными устройствами и периферийной техникой.
20 мая миру была представлена специальная рабочая группа (sig, special interest group), в задачу которой как раз и входило создать и запустить такую систему, получившую название bluetooth.
Очень быстро к Группе присоединились такие компании, как, например, motorola, dell, compaq, xircom и многие, многие другие.
Создаётся форум bluetooth, в который входит более 1300 компаний (Полный список участников группы bluetooth доступен по адресу http://www.bluetooth.com/).
Компания ericsson впервые создаёт аппарат, реально подтверждающий, что bluetooth работает, развивается и будет продолжать свое развитие.
Речь идет об уже упоминавшемся комплекте беспроводной связи с сотовым телефоном, состоящем из наушника и микрофона. Этот комплект способен работать на расстоянии до 10 метров от базы, которой, в данном случае, и является сотовый телефон со встроенной платой bluetooth.
Кстати, в скором времени компания собирается увеличить дальность работы комплекта в несколько раз:
При этом эти два аппарата могут не находиться в прямой видимости друг друга. Чтобы ответить на звонок, вам достаточно нажать на кнопку микрофона, а при наборе номера вам на помощь придет функция голосового вызова. Растущая словно снежный ком популярность bluetooth объясняется так же и его общедоступностью. Во-первых, использование частоты 2,44 ГГц. не требует лицензирования, да и распространение других лицензий на работу с bluetooth будет производиться за символическую плату. Во-вторых, помимо общедоступности, данная технология обещает стать и общепринятой, то есть стандартом де-факто, так как в ближайшее время мировое промышленное сообщество примет технологию как глобальный стандарт. Такое единство вызвано тем, что гораздо проще и дешевле снабжать все устройства одинаковым стандартным чипом, нежели разрабатывать компьютеры под разные интерфейс-карты.
Еще один аргумент за - это дешевизна сетевых адаптеров, которые будут встроены буквально во все - в средства связи, в бытовые приборы, в компьютеры, в другую оргтехнику.
Перспективы.
Они у bluetooth огромны. Эта технология, как ожидается, будет (и есть) совместима с очень многими протоколами и аналогичными системами. gsm, tcp, ip и так далее. Кроме того, есть надежды на относительно низкую стоимость, ведь технология уже изначально задумывалась как общедоступная. Пользователю будет гарантирована высокая степень защиты и отличное качество работы.
Согласно прогнозу компании international data corporation к 2004 в мире будет насчитываться 448.9 млн. устройств, поддерживающих этот стандарт. Одними из первых поддержат стандарт мобильные телефоны. Следом идут принтеры - они начнут поддержку bluetooth в 2001-2002 годах. А к 2004 году 19% всех цифровых камер будут поддерживать bluetooth.
Уже начались поставки инструментального набора от компании ericsson, для разработчиков приложений. И наконец, сегодня (точнее, совсем недавно) компания ericsson, один из главных "родителей" технологии, выпустила телефон, действительно работающий с технологией bluetooth. Это - ericsson t36. Данный сотовый телефон вообще можно назвать образцовым. В нем объединено все лучшее, чего достигла сотовая связь на сегодняшний день. Так, t36 является телефоном трехдиапазонным, у него есть wap-броузер, он поддерживает технологию high speed data, что дает возможность организовать более быстрое соединение, чем стандарт gsm, огромное количество функций, делающих его не просто телефоном, а полноценным помощником в бизнесе, и конечно, он поддерживает технологию bluetooth.
Так же компания выпустила аналогичный по своим возможностям Т36 телефон ericsson r520. Основное отличие - это, безусловно, дизайн - Т36 продолжает линейку таких телефонов, как Т10, Т18, Т28, а r520 можно с уверенностью назвать более совершенным вариантом r320. Трехдиапазонность Т36 позволяет ему работать практически в любой точке земного шара. Но, конечно, диапазон 1900 работает только в Америке.
Но не только ericsson выпускает bluetooth - компоненты. На том же cebit компания toshiba продемонстрировала устройство, использующее bluetooth и видеостандарт mpeg-4 для проведения видеоконференции - изображение с камеры передавалось на компьютер и затем на еще один компьютер.
А, например, компания anoto (http://www.anoto.com/) совместно со все той же компанией ericsson, разработала авторучку, позволяющую передавать сделанные ей записи по мобильной связи.
Конечно, писать придется не на простой бумаге, а на специальной, состоящей из множества точек, которые и различает находящаяся внутри ручки миниатюрная видеокамера.
nec заявила о своем намерении начать в середине этого года выпуск ноутбуков со встроенными чипами bluetooth. Новые модели будут иметь возможность выводить данные на принтеры и другие периферийные устройства, используя беспроводное соединение. Коммуникационный модуль bluetooth, используемый nec, построен на rf-чипе от national semiconductor corp.
ibm сообщила, что сейчас она ведет разработку bluetooth-модема для органайзеров типа palm, в том числе и для своего palm-совместимого карманного компьютера workpad. Как сообщается, эта модемная карта bluetooth pc card будет стоить не дороже 200 дол.
Следует отметить, что осенью этого года компании acer neweb и widcomm собираются выпустить свой bluetooth-модем, который должен составить конкуренцию модему от ibm. Это тоже будет карта стандарта bluetooth pc card, называться она будет bluecard, а стоить - около 100 дол.
На некоторых сайтах часто можно увидеть следующую надпись внизу страницы или под статьями: "Всего просмотров xxx. Сегодня xx". На первый взгляд ничего особенного, но все равно, многим интересно, как это сделано.
В этой статье я попробую рассказать вам о том, как устроена данная статистика просмотров страниц сайта, на самом простом примере, написанном на php. Статистика просмотров страниц будет работать на связке MySQL + PHP. Основным отличием этой статистики от других будет то, что MySQL таблица будет занимать очень мало места, но при этом нельзя будет точно сказать какую именно страницу и сколько раз просмотрели. А все из-за того, что все url будут хешированны с помощью php функции md5(), что гарантирует почти 100% неповторяющихся id для каждой страницы сайта. Делается это только для ускорения работы php скрипта (при условии, что индексом является id страницы) и уменьшения размеров MySQL таблицы (за счет отсутствия длинных url).
MySQL таблица будет иметь следующую структуру:
page_id – уникальный id для каждой страницы сайта сгенерированный php функцией md5().
all – значение всех просмотров данной страницы.
today – просмотров страницы сегодня.
date – дата возвращаемая php функцией time() + 24 часа
Для правильного учета посещений страниц значение поля date будет изменяться, тогда, когда текущая дата будет больше той, что указанна в таблице. В этот же момент будет происходить и обнуление счетчика просмотров страницы за прошедшие сутки.
Почти весь php скрипт статистики просмотров для каждой страницы сайта состоит в основном из функций, которые выполняют строго определенную роль. Все функции снабжены комментариями, поэтому, надеюсь, все поймете сами.
PHP код скрипта статистики просмотров страниц сайта:
Вот в принципе и весь php скрипт статистики просмотров страниц сайта. Для того, что бы он работал, его нужно "подключить" к нужному вам скрипту, например к index.php, добавив в index.php строчку include(' counter.php ');. А в том месте, где должно выводиться сообщение о том, сколько человек просмотрело данную страницу – строчку echo Today_and_all_counter;.
Скачать данный php скрипт статистики просмотров страниц сайта и MySQL файл со структурой таблицы можно здесь
Создавая свой php движок для нового сайта, я, как и всегда не захотел выполнять нудную работу сам и поэтому такое задание как подбор ключевых слов к каждой странице сайта доверил php скрипту, который написал меньше чем за полчаса.
Конечно, многие могут сказать, что поисковики не учитывают мета теги keywords и description, и вовсе незачем голову морочить проблемой подбора ключевых слов, но учитывают или нет, это известно только администраторам поисковых машин. В частности, я недавно проводил эксперимент, в котором участвовало три пары сайтов, на каждой паре сайтов был один и тот же контент, но на одном из сайтов каждой пары были прописаны keywords и description. И что вы думаете, через месяц, все три сайта с keywords и description были выше в выдаче Яндекса, чем их двойники без этих мета тегов. (Примечание: сайты были оптимизированы под абсолютно не конкурентные запросы и не имели бэклинков).
Принцип работы php скрипта, основной задачей которого является “на лету” подбирать к тексту ключевые слова (keywords), заключается в разделении всего текста на слова и занесение их в массив. Из исходного текста сначала удаляются все знаки препинания, затем слова помещаются в массив и каждому слову присваивается число его повторений в тексте. После заполнения массива слова упорядочиваются по количеству повторений, и в качестве результатов берется верхушка массива – 15-25 самых часто употребляемых слов.
А вот и сам исходный код этого php-скрипта для подбора ключевых слов:
Пользоваться данным php классом очень просто, создаете экземпляр класса функцией new а потом вызываете внутреннюю функцию get_keywords(), класса Counter. Вот наглядный пример использования этого класса:
В переменной $content должен содержатся основной текст страницы, для которой создаются ключевые слова. И еще, полученная строка содержит только ключевые слова, без мета тегов. Скачать данный php класс для подбора ключевых слов в zip архиве вы можете здесь.
Когда вы вызываете функцию Windows, она проверяет переданные ей параметры, а затем пытается выполнить работу. Если передан недопустимый параметр или если данную операцию нельзя выполнить по другой причине, она возвращает значение, свидетельствующее об ошибке. За каждой ошибкой закреплен свой 32 битный код. Функция Windows, обнаружив ошибку, через механизм локальной памяти потока сопоставляет соответствующий код ошибки с вызывающим потоком. Это позволяет потокам работать независимо друг от друга, не вмешиваясь в чужие ошибки.
Когда функция вернет вам управление, ее возвратное значение будет указывать на то, что произошла какая-то ошибка. Какая именно - вы узнаете, вызвав функцию GetLastError(). Она просто возвращает 32-битный код ошибки для данного потока. Список кодов ошибок, определенных Microsoft, содержится в файле WinError.h.
Функцию GetLastError необходимо вызывать сразу же за проверяемой функцией, иначе код ошибки будет утерян.
Для отладки бывает нужно следить не за одной ошибкой , а за их постоянным изменением, для этого нет необходимости включать в код постоянные проверки и чтение GetLastError, можно в окне дебагирования Visual C++ ввести @err,hr. В окне вы увидите значение переменной ошибки.
Так как ошибки, которые возникают в программе, возникают не только в процессе отладки, но могут быть обусловлены текущим состоянием системы, на которй бежит программа, то иногда бывает полезно сообщить тип ошибки в нормальном текстовом виде.
В Windows есть специальная функция, которая "конвертирует" код ошибки в ее описание, - FormatMessage.
Для разработчика особенно важно, при создании API или SDK подобных вещей, создавать сходный механизм возврата ошибок для своих функций.
С этой целью вы просто устанавливаете код последней ошибки в потоке и возвращаете значение FALSE, INVALID_HANDLE_VALUE, NULL или что-то другое, более подходящее по ситуации. Чтобы установить код последней ошибки в потоке используйте SetLastError.
Параметр - 32-битное число. Использовать лучше подходящий код ошибки Windows, однако если такового подходящего не нашлось, то можно ввести свой собственный код ошибки. Он должен представлять собой 32-битное число, разбитое по следующим правилам.
Биты
31-30 - Код тяжести - 0=успех, 1=информация, 2=предупреждение, 3=ошибка
29 - Кем определен - 0-Microsoft 1-пользователем
28 - Должен быть 0
27-16 - Определяется Microsoft. (Код подсистемы)
15-0 - Код ошибки.
Собственно Microsoft обещает, что бит 29 будет в ее ошибках всегда равен 0 поэтому, поставив там 1, вы будете в какой-то степени в безопасности от конфликтов с кодами ошибок Microsoft.
При разработке больших приложений, оперирующих большими объемами информации на первое место при отладке встает проблема обнаружения неправильного распределения памяти. Суть проблемы состоит в том, что если мы выделили участок памяти, а затем освободили не весь выделенный объем, то образуются блоки памяти, которые помечены как занятые, но на самом деле они не используются. При длительной работе программы такие блоки могут накапливаться, приводя к значительному расходу памяти.
Для обнаружения подобных ошибок создано специализированное программное обеспечение (типа BoundsChecker от Numega), однако чаще бывает удобнее встроить механизм обнаружения утечки в свои проекты. Поэтому метод должен быть простым, и в то же время как можно более универсальным. Кроме того, не хотелось бы переписывать годами накопленные мегабайты кода, написанного и отлаженного задолго до того, как вам пришло в голову оградить себя от ошибок. Так что к списку требований добавляется стандартизация, т.е. нужно каким-то образом встроить защиту от ошибок в стандартный код.
Предлагаемое решение основывается на перегрузке стандартных операторов распределения памяти new и delete. Причем перегружать мы будем глобальные операторы new|delete, т.к. переписать эти операторы для каждого разработанного ранее класса было бы очень трудоемким процессом. Т.о. после перегрузки нам нужно будет только отследить распределение памяти и, соответственно, освобождение ее в момент завершения программы. Все несоответствия - ошибка.
Реализация
Проект написан на Visual C++, но переписать его на любой другой диалект С++ не будет слишком сложной задачей. Во-первых, нужно переопределить стандартные операторы new и delete так, чтобы это работало во всех проектах. Поэтому в stdafx.h добавляем следующий фрагмент:
Как видите, переопределение операторов происходит в блоке #ifdef/#endif. Это ограждает наш код от влияния на релиз компилируемой программы. Вы, наверное, заметили, что теперь оператор new имеет три параметра вместо одного. Два дополнительных параметра содержат имя файла и номер строки, в которой выделяется память. Это удобно для обнаружения конкретного места, где происходит ошибка. Однако код наших проектов по-прежнему ссылается на оператор new, принимающий один параметр. Для исправления этого несоответствия нужно добавиить следующий фрагмент
Теперь все наши операторы new будут вызываться с тремя параметрами, причем недостающие параметры подставит препроцессор. Конечно, пустые переопределенные функции ни в чем нам не помогут, так что давайте добавим в них какой-нибудь код:
Для полноты картины нужно переопределить операторы new[] и delete[], однако никаких существенных отличий здесь нет - творите!
Последний штрих - пишем функции AddTrack() и RemoveTrack(). Для создания списка используемых блоков памяти будем использовать стандартные средства STL:
Перед самым завершением программы наш список allocList содержит ссылки на блоки памяти, котороые не были освобождены. Все, что нужно сделать - вывести эту информацию куда-нибудь. В нашем проекте мы выведем список неосвобожденных участков памяти в окно вывода отладочных сообщений Visual C++:
Надеюсь, этот проект сделает ваши баг-листы короче, а программы устойчивее. Удачи!
Потоки всегда создаются в контексте какого-либо процесса, и вся их жизнь проходит только в его границах. На практике это означает, что потоки исполняют код и манипулируют данными в адресном пространстве процесса. Если два или более потока выполняются внутри одного процесса, они делят одно адресное пространство.
Любой поток (thread) состоит из двух компонентов:
объекта ядра, через который ОС управляет потоком. Там же хранится статистическая информация о потоке.
Стека потока, который содержит параметры всех функций и локальные переменные, необходимые потоку для выполнения кода.
Потоки могут выполнять один и тот же код, манипулировать одними и теми же данными, а также совместно использовать описатели объектов ядра, поскольку таблица описателей создается не в отдельных потоках, а в процессах.
Потоки используют намного меньше ресурсов системы, чем процессы, поэтому все задачи, требующие параллельного выполнения нескольких подзадач, стоит решать по возможности с помощью потоков, не прибегая к созданию нескольких процессов.
Обычная структура многопоточного приложения рассчитана на одновременное исполнение нескольких подзадач. Однако стоит помнить, что, создавая многопоточное приложение, нам придется заботиться о сохранности и ликвидности, общих для всех потоков, данных.
Создание потока.
Первичный поток, который присутствует в программе, начинает свое выполнение с главной функции потока типа WinMain.
Для создания вторичного потока необходимо создать и для него входную функцию, которая выглядит примерно так:
Имя у функции вторичного потока, в отличии от первичного, может быть любым однако, при наличии нескольких разных потоков, назвать функции необходимо по-разному, иначе система создаст разные реализации одной и той же функции.
Когда поток закончит свое исполнение, он вернет управление системе, память, отведенная под его стек, будет освобождена, а счетчик пользователей его объекта ядра "поток" уменьшится на 1. Когда счетчик обнулится, этот объект ядра будет разрушен.
Для создания своего потока необходимо использовать функцию CreateThread:
При каждом вызове этой функции система создает объект ядра (поток). Это не сам поток, а компактная структура данных, которая используется операционной системой для управления потоком и хранит статистическую информацию о потоке.
Система выделяет память под стек потока из адресного пространства процесса. Новый поток выполняется в контексте того же процесса, что и родительский поток. Поэтому он получает доступ ко всем описателям объектов ядра, всей памяти и стекам всех потоков в процессе. За счет этого потоки в рамках одного процесса могут легко взаимодействовать друг с другом.
CreateThread - это Windows-функция, создающая поток. Если вы пишете код на С/С++ не вызывайте ее. Вместо нее Вы должны использовать _beginthreadex из библиотеки Visual C++. Почему это так важно в наших следующих выпусках.
Параметры функции CreateThread.
LpThreadAttributes - является указателем на структуру LPSECURITY_ATTRIBUTES. Для присвоения атрибутов защиты по умолчанию, передавайте в этом параметре NULL.
DwStackSize - параметр определяет размер стека, выделяемый для потока из общего адресного пространства процесса. При передаче 0 - размер устанавливается в значение по умолчанию.
LpStartAddress - указатель на адрес входной функции потока.
LpParameter - параметр, который будет передан внутрь функции потока.
DwCreationFlags - принимает одно из двух значений: 0 - исполнение начинается немедленно, или CREATE_SUSPENDED - исполнение приостанавливается до последующих указаний.
LpThreadId - Адрес переменной типа DWORD в который функция возвращает идентификатор, приписанный системой новому потоку.
Завершение потока
Поток можно завершит четырьмя способами:
функция потока возвращает управление (рекомендуемо);
поток самоуничтожается вызовом функции ExitThread;
другой поток процесса вызывает функцию TerminateThread;
завершается процесс, содержащий данный поток.
Все способы , за исключением рекомендуемого, являются нежелательными и должны использоваться только в форс-мажорных обстоятельствах.
Функция потока, возвращая управление, гарантирует корректную очистку всех ресурсов, принадлежащих данному потоку. При этом:
любые С++ объекты, созданные данным потоком, уничтожаются соответствующими деструкторами;
система корректно освобождает память, которую занимал стек потока;
система устанавливает код завершения данного потока. Его функция и возвращает;
счетчик пользователей данного объекта ядра (поток) уменьшается на 1.
При желании немедленно завершить поток изнутри используют функцию ExitThread(DWORD dwExitCode).
При этом освобождаются все ресурсы ОС, выделенные данному потоку, но С С++ ресурсы (например, объекты классов С++) не очищаются. Именно поэтому не рекомендовано завершать поток, используя эту функцию.
Если же вы ее использовали, то кодом возврата потока будет тот параметр, который вы передадите в данную функцию.
Как и для CreateThread для библиотеки Visual C++ существует ее аналог _endthreadex, который и стоит использовать. Об причинах в следующем выпуске.
Если появилась необходимость уничтожить поток снаружи, то это моет сделать функция TeminateThread.
Эта функция уменьшит счетчик пользователей объекта ядра (поток) на 1, однако при этом не разрушит и не очистит стек потока. Стек будет существовать, пока не завершится процесс, которому принадлежит поток. При задачах, постоянно создающих и уничтожающих потоки, это приводит к потере памяти внутри процесса.
При завершении процесса происходит следующее.
Завершение потока происходит принудительно. Деструкторы объектов не вызываются, и т.д. и т.д.
При завершении потока по такой причине, связанный с ним объект ядра (поток) не освобождается до тех пор, пока не будут закрыты все внешние ссылки на этот объект.
В этой статье будет рассмотрен скрипт, который создает анимацию в виде падающего снега. Анимация воспроизводится в заданной области web-страницы. Анимационный эффект, создаваемый данным скриптом выглядит весьма привлекательно, поэтому скрипт вполне может быть использован для создания анимированных логотипов, или блоков новогодних объявлений и поздравлений на сайте.
Область web-страницы, в которой производится анимация, задается элементом DIV с идентификатором ID_ANIMATE. Принцип работы скрипта заключается в вертикальном перемещении (с небольшими стохастическими перемещениями по горизонтали) элементов IMG, представляющих изображение снежинки в пределах этого элемента (элемент DIV с идентификатором ID_ANIMATE является элементом-контейнером для элементов IMG).
Элемент-контейнер DIV с идентификатором ID_ANIMATE определяется при помощи HTML-разметки в документе, в котором содержится скрипт. В этот элемент может быть помещено произвольное гипертекстовое содержимое, которое будет располагаться "на фоне" падающих снежинок, либо на фоне которого будут падать снежинки (это зависит от значения позиционного уровня этого содержимого). Код фрагмента HTML-разметки, определяющей элемент-контейнер DIV и его содержимое в демо-примере, приложенном к статье (см. демо-пример), приведен далее:
Параметры элемента-контейнера DIV (его размеры, схема позиционирования, значение свойства переполнения, цвет фона, параметры границы), а также перемещаемых в нем элементов IMG (схема позиционирования, размер, значение позиционного уровня), определяются правилами внедренной в документ таблицы слилей CSS:
Как можно видеть из листинга, элементам IMG, являющимся потомками элемента DIV с идентификатором ID_ANIMATE, назначается значение позиционного уровня 1. Поэтому, если вы хотите, чтобы "снежинки" двигались "под" остальным содержимым этого элемента, содержимому следует задать значение позиционного уровня больше 1 (как это сделано в демо-примере). Обратите также внимание на то, что элементам IMG назначена схема абсолютного позиционирования.
Теперь рассмотрим непосредственно работу скрипта. Полный листинг кода скрипта приведен далее.
Как можно видеть из листинга, в начале скрипта производится инициализация нескольких переменных. В переменную oAnimate заносится ссылка на DOM-объект элемента DIV с идентификатором ID_ANIMATE. Переменные nWidth и nHeight инициализируются значениями значения ширины и высоты этого элемента. Переменная nFSize должна содержать значение высоты (в пикселях) элементов изображений-снежинок (оно должно быть таким же, как задано в таблице стилей). Переменная strFlakeURL содержит URI ресурса изображения снежинки. Значение переменной nCount определяет общее количество движущихся изображений. Массив aoFlakes предназначен для хранения ссылок на DOM-объекты элементов изображений-снежинок.
Создание элементов изображений, добавление их в дерево документа, ссылок на DOM-объекты этих элементов в массив aoFlakes производится в процессе инициализации скрипта (см. окончание листинга кода скрипта). Значению свойства src DOM-объектов элементов изображений при этом присваивается значение переменной strFlakeURL. Для установки параметров движения каждого созданного элемента, вызывается функция ResetFlake. Для позиционирования соответствующего элемента IMG относительно элемента-контейнера DIV - UpdateFlakePos.
Функция ResetFlake устанавливает значения свойствам m_nX, m_nY и m_nSpeed DOM-объекта элемента, ссылка на который содержится в элементе массива aoFlakes с индексом, равным значению первого параметра ResetFlake. Свойство m_nX объекта хранит текущую координату по оси X, а свойство m_nY - по оси Y соответствующего элемента относительно контейнера. Свойство m_nSpeed определяет "скорость" движения элемента (величину его вертикального смещения на каждом шаге анимации). Функция ResetFlake устанавливает случайные значения свойствам m_nX и m_nSpeed. Свойству m_nY случайное значение устанавливается только в том случае, если параметр bRandY функции вычисляется в true (в этом случае элемент изображения снежинки будет иметь случайную позицию по вертикали). Иначе свойству m_nY устанавливаетя значение -nFSize (при этом изображение будет позиционироваться так, что оно будет полностью скрыто за верхней границей элемента-контейнера). При создании элементов изображений в процессе инициализации скрипта, ResetFlake вызывается со значением параметра bRandY, равным true.
Функция UpdateFlakePos принимает в качестве единственного параметра значение индекса в массиве aoFlakes и производит позиционирование элемента, ссылка на DOM-объект которого содержится в элементе массива aoFlakes с данным индексом в соответствии со значениями его свойств m_nX и m_nY.
Перемещение всех изображений-снежинок осуществляется функцией OnTimer, которая является обработчиком событий таймера, запускаемого в процессе инициализации скрипта.
Как можно видеть из приведенного ранее листинга кода скрипта, в функции OnTimer производится перебор всех DOM-объектов элементов изображений снежинок. Значение свойства m_nY каждого из этих объектов наращивается на величину его свойства m_nSpeed. Значение свойства m_nX изменяется на случайную величину, которая находится в диапазоне [-1..1] (так достигается случайное горизонтальное движение "снежинок"). В случае, если элемент изображения вышел за нижнюю границу элемента-контейнера, вызывается функция ResetFlake, которая устанавливает случайные значения свойств m_nX и m_nSpeed соответствующего объекта, а значение его свойства m_nY устанавливаетт в -nFSize. Затем вызывается функция UpdateFlakePos для перемещения конкретного элемента IMG в нужную позицию.
В этом разделе вы создадите два новых приложения OLE. Первое - простая программа-сервер OLE, второе - пример простого контейнера OLE. Эти программы предназначены для демонстрации минимальных затрат программирования, необходимых для создания приложений OLE 2.
В любом случае, для создания оболочки программы следует воспользоваться приложением AppExpert. Сначала необходимо сгенерировать основу приложения в AppExpert, затем модифицировать созданные файлы для создания законченного рабочего примера.
При написании своих версий этих программ необходимо иметь в виду несколько моментов. Во-первых, в этой главе приводятся листинги только исходных, немодифицированных файлов.
Во-вторых, CLSID этих программ будет отличаться от CLSID программ, которые вы сгенерируете с помощью AppExpert. Это нормально и даже необходимо, поскольку с помощью CLSID одни серверные приложения в Windows отличаются от других.
В-третьих, эти примеры содержат минимум необходимых средств для того, чтобы начать программировать с OLE. Вы можете использовать эти примеры в качестве начального кода для создания своего действительно полезного сервера или контейнера. В этой главе просто не хватает места для описания реализации функциональных сервера и контейнера - в этом случае вам понадобился бы грузоподъемник, чтобы положить эту книгу на стол.
Создание сервера OLE
Первое приложение OLE в этой главе - сервер. В этом примере вы построите полный сервер - сервер, который может использоваться и как автономное приложение, и как сервер. Создавая автономный сервер (т.е. в виде исполняемой программы .ЕХЕ, а не в виде динамически подключаемой библиотеки DLL), вы упрощаете процесс регистрации сервера в Windows.
Начальный процесс разработки сервера прост. Сначала из интегрированной среды Borland C++ версии 4.5 запустите AppExpert. Задайте каталог и имя вашего проекта. Я поместил свой проект в каталог \BC45\SOURCE\OLESVR. Проект я назвал OLESVR (я всегда называю проекты и каталоги проектов одним и тем же именем, это облегчает запоминание). Ниже приводится последовательность действий, в результате которых был создан проект OLESVR.
Запустите AppExpert. В первом диалоговом окне следует задать имя и каталог проекта. Как уже отмечалось, я использовал OLESVR для задания обоих.
После выбора ОК в диалоговом окне имени и каталога проекта следующий раздел АррЕхреrt - диалоговое окно Application General Options (основные опции приложения). Это диалоговое окно позволяет задать конфигурацию приложения, генерируемого AppExpert. Вам придется модифицировать несколько опций для проекта OLESVR.
Первая опция, которую необходимо изменить, находится в блоке Application: Summary. Замените параметр по умолчанию Multiple document interface на Single document interface. Это изменение согласуется с призывом Microsoft делать ставку на однодокументные приложения для Windows. На рис. 21.1 демонстрируется модифицированный блок Application: Summary.
Второе изменение, которое необходимо внести, - указать AppExpert, что ваша программа будет сервером OLE. Это изменение вносится в пункт Application: OLE 2 Options, имеющий ряд опций OLE 2, которые можно задавать. Поскольку вы создаете сервер OLE, вы будете оперировать только элементами блока группы OLE 2 Server: (поищите его в правой верхней части диалога). Выберите кнопку ячейки пометки Server EXE. На рис. 21.2 демонстрируются изменения, проведенные в пункте Application:OLE 2 Options.
При желании вы можете заполнить элементы пункта Application: Admin Options блока диалога AppExpert. С его помощью вы можете задать в приложении заметку об авторском праве, имя и информацию о версии. Все элементы в Application: Admin Options необязательны, и вы можете их не задавать.
Подпункты пункта Main Window не нуждаются в модификациях, их следует оставить заданными значениями по умолчанию. Для данного приложения нет необходимости менять что-либо в этих подпунктах. Пункт MDI Child/View неприменим для этого проекта, поэтому нет нужды в нем что-нибудь менять.
После задания всех необходимых модификаций следует выбрать кнопку Generate в нижней части блока диалога AppExpert Application General Options. AppExpert запросит у вас подтверждение, действительно ли вы собираетесь создать проект; после принятия подтверждения AppExpert сгенерирует приложение. На рис. 21.3 приводится конечный проект, загруженный в интегрированную среду Borland C++ версии 4.5.
Теперь, когда программа сгенерирована, в нее следует добавить код, задающий функциональность сервера OLE. Необходимо включить код, рисующий изображение, а также провести другие незначительные изменения.
К счастью, помимо Borland C++ версии 4.5 можно воспользоваться программой ClassExpert, что облегчит внесение большей части изменений. Предположим, вы хотите сперва заняться вопросами отображения. Как и в любой созданной с помощью AppExpert программе, основная часть рисования выполняется классом отображения, производным от класса OWL TOleView. Файл, в котором содержится реализация отображения, имеет имя LSVROLVW.CPP. В листинге 21.1 приводится первоначальный файл OSROLVW.CPP.
Листинг (файл реализации класса отображения OLESVR, OSVROLVW.CPP)
Давайте определимся с номенклатурой. Поле - это ячейка в таблице. Запись - набор из полей. Так вот, существуют разные типы полей - обычные, индексные и ключевые. Обычные поля - просто данные. Индексное поле - поле, по которому данные сортируются. Ключевое - поле, значение которого уникально. В общем-то четкого разделения нет. Ведь программа базы данных может сортировать таблицу и по обычным полям, а индексное поле может быть также уникальным.
В BDE достаточно логично поределена структура построения полей и их типов. Для этого имеются классы TxxxDef (три икса здесь обозначают подстановку, а то мало ли что Вы подумаете ;)), произведенные ото абстрактного базового класса TNamedItem. В компоненте TTable имеются и соответствующие свойства
TIndexDefs
TFieldDefs
Как и следовало предполагать, эти свойства содержат в себе определения индексных и обычных полей. Здесь нет свойства типа TKeyDefs, потому что в таблицах типа Парадокс индексные поля могут быть сами по себе уникальны. За счет этих свойств и задаются параметры таблицы, ее сетка. Создание таблицы довершает метод CreateTable.
Теории было много, теперь практика. Вот пример, честно скажу, взятый их Хелпа и перекомментированный автором (то есть мной).
Это все еще объяснять и объяснять. Но, я надеюсь, общая логика понятна.
Такие типы данных, как int, float, char и long, являются неотъемлемой частью C/C++ и вам не нужно писать никакого кода, чтобы сообщить компилятору о том, что означают эти слова. C/C++ позволяет вам также объ-являть свои собственные, специальные типы данных. В следующем разделе вы узнаете, как объявлять структуры, которые можно отнести к специальным типам данных.
Как вы уже знаете, переменная в C/C++ объявляется следующим образом:
В приведенном операторе iMyVariable объявлена как целая переменная. А вот объявление переменной типа char:
Напишите следующий исходный код:
В коде, который вы написали, имеются два оператора #include:
Файл iostream.h включен в код, поскольку в main(void) используется cout. Файл string.h включается потому, что в main(void) используется функция strcpy() (объявленная в файле string.h). Затем вы объявляете структуру:
Обратите внимание на синтаксис объявления структуры. Оно начинается с ключевого слова struct, за которым следует имя типа-структуры. В этой программе типу структуры присвоено имя MYSTRUCTURE. Затем следует собственно определение структуры, заключенное в фигурные скобки. Не забудьте поставить точку с запятой после закрывающей фигурной скобки. Теперь посмотрите на код внутри фигурных скобок:
Это означает, что MYSTRUCTURE состоит из строки с именем sName и целого с именем iAge, sName и iAge называются элементами данных структуры; Вы объявили их "Внутри" cтруктуры MYSTRUCTURE. Код в main(void) объявляет переменную с именем MyStructure типа MYSTRUCTURE:
Вспомните, что в объявляли переменную iNum1 следующим образом:
Когда вы объявляете MyStructure , которая будет структурой типа MYSTRUCTURE, рассматривайте переменную MyStructure аналогично переменной iNum1. MyStructure - это имя переменной, а ее типом является MYSTRUCTURE точно так же, как типом переменной iNum1 является int. (Обратите внимание, что по традиции имя структуры составлено из символов нижнего регистра или в нем смешаны символы нижнего и верхнего регистров, как, например, в имени MyStructure, но в имени типа структуры используются только символы верхнего регистра, как, например, в MYSTRUCTURE.)
Следующий оператор в main(void) копирует строку 'Andy' в элемент данных MyStructure.sName:
В этом операторе обращение к элементу данных sName записано как MyStructure.sName Следующий оператор присваивает значение 13 элементу данных iAge cтруктуры MyStructure: MyStructure.iAge - 13; Затем выполняется ряд операторов вывода cout:
Сложив все вместе, мы видим, что программа MyStruct выводит сообщение My name is Andy and I am 13 years old. (Меня зовут Andy и мне 13 лет)
В состав библиотеки MFC входит ряд классов, представляющих стандартные диалоговые панели. Эти классы позволяют легко реализовать такие часто используемые операции, как открытие и сохранение файла, выбор цвета, выбор шрифта и т.д. Все эти классы наследуются от CCommonDialog, который в свою очередь является производным по отношению к базовому классу CDialog.
Приведем классы стандартных диалоговых панелей и их назначение:
CColorDialog - Панель для выбора цвета
CFileDialog - Панель выбора файлов для открытия и сохранения на диске
CFindReplaceDialog - Панель для выполнения операции поиска и замены
CFontDialog - Панель для выбора шрифта
CPrintDialog - Панель для вывода документа на печать
CPageSetupDialog - Панель выбора формата документа
COleDialog - Панель для управления технологией OLE
Классы, управляющие стандартными диалоговыми панелями, определены в файле afxdlgs.h. Поэтому при использовании этих классов в приложении необходимо включить этот файл в исходный текст при помощи директивы #include.
Панель выбора цвета (класс CColorDialog)
Чтобы отобразить на экране стандартную диалоговую панель выбора цвета, надо создать объект класса CColorDialog, а затем вызвать метод DoModal. При создании объекта класса СColorDialog используется следующий конструктор:
Все параметры конструктора необязательны, однако в некоторых случаях использование этих параметров может помочь.
Первый параметр clrInit позволяет указать цвет, выбранный по умолчанию сразу после открытия диалоговой панели. Если параметр не будет указан, в качестве цвета, выбранного по умолчанию, будет использоваться черный цвет.
Параметр dwFlags содержит набор флагов, управляющих диалоговой панелью выбора цвета. При помощи него блокировать или разрешать работу некоторых элементов управления диалоговой панели выбора цвета. Если при создании объекта класса CColorDialog не указать параметр dwFlags, тем не менее можно выполнить настройку диалоговой панели, обратившись непосредственно к элементу m_cc данного класса. Параметр dwFlags, указанный в конструкторе, используется для инициализации m_cc. Изменения в элемент m_cc должны быть внесены до того, как панель будет отображаться на экране.
Последний параметр pParentWnd можно использовать, чтобы указать родительское окно диалоговой панели.
Методы класса CСolorDialog
Чтобы вывести диалоговую панель выбора цвета на экран, необходимо использовать метод DoModal. После отображения панели на экране пользователь может выбрать из нее цвет и нажать кнопки OK или Cancel для подтверждения выбора цвета или отказа от него. Когда диалоговая панель закрывается, метод DoModal возвращается значения IDOK и IDCANCEL, в зависимости от того, какую кнопку нажал пользователь:
На экране появится стандартная диалоговая панель выбора цвета Color. В верхней половине диалоговой панели расположены 48 прямоугольников, имеющих различные цвета. Они представляют так называемые основные цвета (Basic colors). Можно выбрать один из этих цветов и нажать кнопку OK. После того, как диалоговая панель закрыта (метод DoModal завершил свою работу), можно воспользоваться методами класса CColorDialog, чтобы узнать цвета, выбранные пользователем.
Для определения цвета, выбранного пользователем, можно обратиться к методу GetColor класса CColorDialog. Данный метод возвращает значение COLORREF, соответствующее выбранному цвету.
Если пользователю недостаточно основных цветов, представленных в диалоговой панели Color, он может выбрать до 16 дополнительных цветов. Для этого он должен нажать кнопку DefineCustom Colors. Диалоговая панель изменит свой внешний вид - появятся дополнительные органы управления, позволяющие выбрать любой из 16 777 216 цветов. Когда цвет выбран, нужно нажать кнопку Add Custom Colors. Выбранный цвет будет добавлен к дополнительным цветам (Custom colors) - один из свободных прямоугольников окрасится соответствующим цветом.
При помощи метода GetSavedCustomColors класса CColorDialog можно определить дополнительные цвета, выбранные пользователем в диалоговой панели Color. Этот метод возвращает указатель на массив из 16 элементов типа COLORREF. Каждый элемент массива описывает один дополнительный цвет.
Когда диалоговая панель Color отображается приложением первый раз, все прямоугольники, отображающие дополнительные цвета, имеют белый цвет. Дополнительные цвета, выбранные пользователем, сохраняются во время работы приложения. После перезапуска приложения дополнительные цвета сбрасываются.
Панель выбора файлов (класс CFileDialog)
Среди стандартных диалоговых панелей, для которых в библиотеке MFC создан специальный класс, есть панели для работы с файловой системой - Open и Save As. Диалоговая панель Open позволяет выбрать один или несколько файлов и открыть их для дальнейшего использования. Диалоговая панель Save As позволяет выбрать имя файла для записи в него документа.
Для управления диалоговыми панелями Open и Save As предназначен один класс CFileDialog. Рассмотрим конструктор класса CFileDialog более подробно:
Объекты класса CFileDialog представляют диалоговые панели Open или Save As в зависимости от параметра bOpenFileDialog. Если параметр bOpenFileDialog содержит значение TRUE, то создается объект, управляющий диалоговой панелью Open, а если FALSE - диалоговой панелью Save As.
Параметр bOpenFileDialog является единственным обязательным параметром, который необходимо указать. Остальные параметры конструктора класса CFileDialog задают различные режимы работы панели и могут не указываться.
Чтобы создать объект класса CFileDialog , представляющий диалоговую панель для открытия файлов (mFileOpen), и объект, представляющий диалоговую панель для сохранения файлов (mFileSaveAs), можно воспользоваться следующими вызовами конструктора класса:
Во многих случаях имена файлов, которые нужно открыть или закрыть, имеют определенное расширение. Параметр lpszDefExt позволяет задать расширение файлов, используемое по умолчанию. То есть, если пользователь при определении имени файла не укажет расширение, имени файла автоматически присваивается расширение, принятое по умолчанию. Если при определении свойств диалоговой панели программист присвоит параметру lpszDefExt значение NULL, то расширение файлов должно задаваться пользователем явно.
В некоторых случаях требуется, чтобы диалоговые панели отображались с уже выбранным именем файла. Чтобы указать имя файла, используемое по умолчанию, применяется параметр lpszFileName. Если параметр lpszFileName имеет значение NULL, данная возможность не реализуется.
С помощью флага dwFlags можно изменить внешний вид и некоторые другие характеристики стандартных диалоговых панелей класса CFileDialog. В него можно записать комбинацию флагов, управляющих различными характеристиками этих панелей. Например, флаг OFN_HIDEREADONLY означает, что из диалоговой панели удаляется переключатель "Read Only", а флаг OFN_OVERWRITEPROMPT (используемый для панели Save As) - что необходимо выводить диалоговую панель с предупреждением, если пользователь выбирает для сохранения имя уже существующего файла.
Диалоговые панели выбора файлов обычно имеют список так называемых фильтров, включающих названия типов файлов и расширения имен файлов данного типа. Выбрав фильтр, пользователь указывает, что он желает работать только с файлами определенного типа, имеющими соответствующее расширение. Файлы с другими расширениями в диалоговых панелях не отображаются.
Список фильтров можно указать через параметр lpszFilter. Одновременно можно указать несколько фильтров. Каждый фильтр задается двумя строками - строкой, содержащей имя фильтра, и строкой, в которой перечислены соответствующие ему расширения имен файлов. Если одному типу соответствует несколько расширений, они разделяются символом ;. Строка, содержащая имя фильтра, отделяется от строки с расширениями файлов символом |. Если используется несколько фильтров, то они также отделяются друг от друга символом |. Например, в качестве строки, задающей фильтры, можно использовать строку вида:
Диалоговые панели, представленные объектами класса CFileDialog, могут иметь или не иметь родительского окна. Чтобы указать родительское окно, нужно передать конструктору CFileDialog указатель на него через параметр pParentWnd.
Методы класса CFileDialog
Создание объекта класса CFileDialog еще не вызывает отображения соответствующей диалоговой панели. Для этого необходимо воспользоваться методом DoModal класса CFileDialog.При вызове метода DoModal для ранее созданного объекта класса CFileDialog на экране открывается соответствующая диалоговая панель. После того, как пользователь завершает работу с диалоговой панелью, метод DoModal вернет значение IDOK или IDCANCEL в случае успешного завершения и нуль - в случае возникновения ошибок:
После того, как пользователь закроет диалоговую панель и метод DoModal вернет управление, можно воспользоваться другими методами класса CFileDialog , чтобы определить имена выбранных файлов:
GetPathName - Определяет полный путь файла
GetFileName - Определяет имя выбранного файла
GetFileExt - Определяет расширение имени выбранного файла
GetFileTitle - Позволяет определить заголовок выбранного файла
GetNextPathName - Если диалоговая панель позволяет выбрать сразу несколько файлов, то этот метод можно использовать для определения полного пути следующего из выбранных файлов
GetReadOnlyPref - Позволяет узнать состояние атрибута "только для чтения" (read-only) выбранного файла
GetStartPosition - Возвращает положение первого элемента из списка имен файлов
Наиболее важный метод - GetPathName. Он получает полный путь файла, выбранного из диалоговых панелей Open или Save As. Если диалоговая панель позволяет выбрать сразу несколько файлов, тогда метод GetPathName возвращает массив строк, состоящий из нескольких строк, заканчивающихся двоичным нулем. Первая из данных строк содержит путь к каталогу, в котором расположены выбранные файлы, остальные строки содержат имена выбранных файлов. Выделение строки, содержащей путь к каталогу, проблем не вызывает, а чтобы получить имена выбранных файлов, необходимо воспользоваться методами GetStartPosition и GetNextPathName.
[pagebreak]
Метод GetStartPosition возвращает значение типа POSITION. Оно предназначено для передачи методу GetNextPathName и получения очередного имени выбранного файла. Если пользователь не выбрал ни одного файла, метод GetStartPosition возвращает значение NULL. Значение, полученное этим методом, следует записать во временную переменную типа POSITION и передать ссылку на нее методу GetNextPathName. Метод GetNextPathName вернет полный путь первого из выбранных в диалоговой панели файлов и изменит значение переменной pos, переданной методу по ссылке. Новое значение pos можно использовать для последующих вызовов метода GetNextPathName и получения путей всех остальных выбранных файлов. Когда метод GetNextPathName вернет имена всех выбранных файлов, в переменную pos записывается значение NULL.
В панелях Open и Save As имеется переключатель "ReadOnly". По умолчанию этот преключатель не отображается. Если есть необходимость воспользоваться этим переключателем, то нужно отказаться от использования флага OFN_HIDEREADONLY.
Метод GetReadOnlyPref позволяет определить положение переключателя "ReadOnly". Если переключатель включен, то метод GetReadOnlyPref возвращает ненулевое значение. В противном случае GetReadOnlyPref возвращает нуль.
Панель выбора шрифта (класс CFontDialog)
Стандартная диалоговая панель Font предназначена для выбора шрифта. Эта панель отображает список шрифтов, установленных в системе, и позволяет выбрать название шрифта, его начертание и другие параметры.
Для управления диалоговой панелью Font в библиотеку классов MFC включен класс CFontDialog. Методы этого класса можно использовать для отображения панели Font и определения характеристик шрифта, выбранного пользователем. Конструктор класса CFontDialog:
Все параметры конструктора являются необязательными. Настройка стандартной панели выбора шрифта, которая выполняется конструктором класса CFontDialog по умолчанию, удовлетворяет большинству пользователей.
Параметр lplfInitial является указателем на структуру LOGFONT, описывающую логический шрифт. Если этот параметр используется, то в диалоговой панели по умолчанию будет выбран шрифт, наиболее соответствующий шрифту, описанному в структуре LOGFONT.
Параметр dwFlags задает набор флагов, управляющий различными режимами работы панели. Например, флаг CF_EFFECTS позволяет пользователю создавать подчеркнутые и перечеркнутые буквы, определять цвет букв, а флаг CF_SCREENFONTS - разрешает выбирать только экранные шрифты.
Через параметр pdcPrinter можно передать конструктору контекст отображения принтера, шрифты которого будут представлены в диалоговой панели Font. Данный параметр используется только в том случае, если в параметре dwFlags указаны флаги CF_PRINTERFONTS или CF_BOTH.
Через параметр pParentWnd можно указать родительское окно для диалоговой панели Font.
Методы класса CFontDialog
Для отображения диалоговой панели Font предназначен виртуальный метод DoModal. Если пользователь выбрал шрифт и нажал кнопку OK, метод DoModal возвращает идентификатор IDOK, если пользователь отменил выбор шрифта, метод DoModal возвращает идентификатор IDCANCEL:
Остальные методы класса предназначены для определения характеристик выбранного пользователем шрифта.
Метод GetCurrentFont позволяет сразу определить все характеристики выбранного шрифта, записав их в структуру LOGFONT.
Остальные методы класса позволяют определить только отдельные характеристики выбранного шрифта:
GetFaceName - Возвращает имя выбранного шрифта
GetStyleName - Возвращает имя стиля выбранного шрифта
GetSize - Возвращает размер выбранного шрифта
GetColor - Возвращает цвет выбранного шрифта
GetWeight - Возвращает плотность выбранного шрифта
IsStrikeOut - Определяет, является ли шрифт выделенным перечеркнутой линией
IsUnderline - Определяет, является ли шрифт выделенным подчеркиванием
IsBold - Определяет, является ли шрифт жирным
IsItalic - Определяет, является ли шрифт наклонным
Панель для вывода документов на печать (класс CPrintDialog)
Класс CPrintDialog можно использовать для создания двух видов диалоговых панелей, предназначенных для печати документов и выбора форматов документов. Кроме класса CPrintDialog можно также использовать класс CPageSetupDialog. Он позволяет создать диалоговую панель для выбора формата документа, имеющую несколько иной вид.
В приложениях, подготовленных с использованием средств MFC AppWizard и построенные по модели документ-облик, по умолчанию встроена возможность вывода редактируемого документа на печать.
В меню File такого приложения находятся три строки (Print, Print Preview и Print Setup), которые управляют процессом печати документов, подготовленных в приложении. Чтобы распечатать документ, достаточно выбрать из меню File строку Print. На экране появится диалоговая панель Print. В ней можно выбрать печатающее устройство для печати документов (группа Name), указать, будет печататься весь документ либо его часть (группа Print range), а также сколько копий документа будет напечатано (группа Copies). Также можно настроить различные характеристики печатающего устройства, если нажать кнопку Properties в группе Printer.
Если требуется определить только печатающее устройство и формат документа, из меню File следует выбрать строку Printer Setup. В группе Printer можно указать печатающее устройство и настроить его соответствующим образом. Группа Paper задает формат бумаги и режим подачи бумаги в печатающее устройство. Группа Orientation включает только один переключатель, определяющий ориентацию бумаги. Он принимает положение Portrait для вертикальной ориентации изображения на бумаге (режим "портрет") или Landscape для горизонтальной ориентации изоборажения на бумаге (режим "ландшафт").
Строка Print Preview меню File выбирается для предварительного просмотра документа перед печатью. При этом главное окно приложения изменит свой внешний вид и можно будет просмотреть, как будет выглядеть документ после печати.
Если не требуется выполнять специфическую обработку документа перед печатью, то вряд ли понадобится самостоятельное добавление программного кода, отвечающего за процесс печати. Просто следует отметить, что процедура создания панелей, связанных с печатью документа, практически ничем не отличается от создания выше описанных стандартных диалоговых панелей.
Панель для выполнения поиска и замены (класс CFindReplaceDialog)
Класс CFindReplaceDialog предназначен для управления диалоговыми окнами Find и Replace. Диалоговая панель Find используется для поиска известных строк в документе приложения, а панель Replace позволяет замену одной строки на другую.
Важным отличием диалоговых панелей Find и Replace от других стандартных диалоговых панелей является то, что они представляют собой немодальные диалоговые панели. Поэтому процесс создания этих панелей значительно отличается от процесса создания стандартных панелей для выбора цвета, шрифта и имен файла.
В этом разделе речь пойдет о растеризации двумерных графических примитивов, таких как отрезки, окружности, эллипсы. Мы попробуем разобраться, в чем отличие идеальных математических объектов от реальных отрезков и окружностей, рисуемых на экране.
При этом рассматриваются реальные задачи отрисовки графики, поэтому предложенные алгоритмы должны работать с приемлемой скоростью и использовать различные оптимизации.
Далее, на базе рассмотренных методов, будут построенны алгоритмы заливки фигур.
Связность
Идеальная математическая линия представляет собой бесконечное количество точек, удовлетворяющих определенному уравнению, или задана другим образом. Реальный экран это всегда конечное количество точек. Изображение представляет из себя прямоугольную сетку, узлы которой имеет целочисленные координаты. Появляется законный вопрос: как определить связность линии на экране?
Традиционно вводятся два понятия связности.
4-связность: пикселы p1(x1, y1) и p2(x2, y2) называются соседними, если либо разность их координат по оси x, либо разность их координат по оси y равна 1 (либо исключающее):
|x2 – x1| + |y2 – y1| <= 1
8-связность: пикселы p1(x1, y1) и p2(x2, y2) называются соседними, если разность их координат по оси x и разность их координат по оси y не больше 1:
|x2 – x1| <= 1, |y2 – y1| <= 1
8-связность(рис 1.) и 4-связность (рис 2.)
Линией на растровой сетке будем считать последовательность пикселов {P1, …, Pn}, таких, что любые два пиксела Pi, Pi+1 являются соседними в смысле заданной связности.
Прим. Отметим, что любая четырехсвязная линия одновременно является восьмисвязной, но не наоборот. Таким образом 4-связность является более сильным понятием.
Отсечение
Понятие связности, введенное выше, позволяет обойти требование на целочисленность координат всех точек. С помощью этого понятия можно судить о связности дискретной линии. Другая проблема состоит в том, что область вывода всегда имеет ограниченные размеры. Область формы, на которую делался вывод в предыдущих разделах, имеет форму прямоугольника. Таким образом появляется задача отсечения выводимых геометрических примитивов по границе некоторой области. Алгоритмы отчесения будут рассмотрены ниже.
Переход к оконным координатам
В предыдущем разделе не акцентировалось внимание, где именно стоит перейти из логических координат в оконные. Дискретность сетки, на которую выводится изображение, имеет определенные преимущества. А именно, за счет целочисленности коорднат пикселей можно создать алгоритмы, которые будут также работать только с целыми числами. Более того, во многих случаях основной цикл из числа арифметических операций содержит только сложения!
Становится ясно, что переход к оконным коодинатам нужно осуществить до начала работы основного алгоритма. В общем случае схема работы будет выглядеть следующим образом:
Это то, что касается базовых понятий. В последующих статьях будут рассмотрены математические основы задания графических примитивов и алгоритмы их построения (растеризации).