Графические часы (исходники, документация)Источник: articlesorg
delphi позволяет рисовать почти где угодно. Можно рисовать на форме, можно рисовать на метке, можно даже рисовать непосредственно на экране! Но лучше использовать всё-таки специальный компонент timage, уже хотя бы потому, что этот компонент сам будет следить затем, что бы при перерисовке окна твоей программы, твои каракули тоже перерисовывались. Если ты нарисуешь что-то, например, на форме, то при сворачивании окна программы твой рисунок сотрётся. Собственно за рисование отвечает свойство canvas. Если у компонента есть такое свойство, то на нём можно рисовать, если нет - увы. Кстати, это свойство ты не найдёшь в инспекторе объектов. Это свойство не доступно во время разработки программы. Оно станет доступно только во время исполнения. Разумеется, к нему можно обращаться в тексте программы - ведь текст программы начнёт работать только после запуска. Как же определить есть свойство canvas у компонента или нет? Если ты выделишь компонент на форме, свойство или событие в инспекторе объекта или поставишь курсор внутрь какого-либо слова в тексте программы и нажмёшь клавишу f1, то откроется система помощи, причём откроется она на описании выделенного объекта, свойства, события или слова (разумеется, если этот элемент в помощи имеется). Если элементу соответствует несколько записей в системе помощи, то тебя поросят выбрать нужный (в delphi7 очень многим компонентам соответствует по 2 записи - нужно выбирать ту в которой есть аббревиатура vcl). У всех компонентов в помощи имеется ссылка properties, при нажатии на которую откроется окно со списком всех свойств этого объекта. Тебе останется только найти нужное свойство в этом списке или установить факт его отсутствия. Если на твоей форме места для таких часов нет, предлагаю включить в нашу программу ещё одну форму. 0. С помощью кнопки «new form» или пункта меню «file/new form» создаёшь новую форму. Жмёшь на кнопочку «save». Вводишь какое-нибудь имя для этого нового модуля (конечно можно оставить и unit2, но лучше использовать осмысленные имена). 1. Помещаешь на новую форму компонент image (палитра additional, 6-я кнопка в виде картинки) на форму. Свойство align выставляешь в alclient, в результате image будет растекаться по всей форме. 2. Кладёшь на форму timer. Создаёшь ему обработчик события ontimer. 3. Объявляешь новые переменные: var xc,yc : integer; Обрати внимание. Объявление переменных может занять несколько строк, но слово var пишешь только один раз, то есть var помечает весь блок переменных, а не отдельную его строку. Тип переменных double - это вещественный тип, в нём можно хранить дробные числа. Переменные xc, yc используем для хранения координат центра часов, а в переменную u будем записывать угол поворота стрелок. 4. Объявляешь типизированные константы: const lh : integer = 60; Хотя они и называются константы, в действительности это переменные, только у них с самого начала устанавливаются значения. Значения этих элементов - длина часовой, минутной и секундной стрелок в пикселях. Ну, синтаксис, по-моему, вполне понятен. 5. В теле процедуры пишем: xc := image1.width div 2; В первых двух строчках рассчитываем координаты центра image, это и будет центр наших часов. В третьей строчке считаем угол для часовой стрелки. Символ «/» означает деление, символ «*» умножение, «-» знак минус. Порядок действий стандартный для математических выражений, то есть сначала делим/умножаем, потом складываем/вычитаем. Функция pi возвращает число пи. Объяснять, почему угол считается именно так, надо? Или твоих знаний геометрии хватит? Ах, да, сначала Великая Эроида, затем тяжкое наследие гуманитарного образования… Значит, угол в математике (и в delphi) принято отсчитывать от горизонтали и против часовой стрелки. А на часах - от вертикали и по часовой. Знак «-» перед time меняет направление отсчёта, а «пи пополам» смещает начало отсчёта на четверть оборота против часовой стрелки (то есть на цифру 12 на часах). За сутки time меняет своё значение от 0 до 1, а часовая стрелка должна за это время сделать 2 оборота, то есть «2*2*pi» радиан. Таким образом, мы получаем угол u в радианах. Именно в радианах этот угол и нужно подставлять в функции синуса и косинуса. Четвёртая строка: помещаем указатель в центр. Пятая строка: проводим линию от текущего положения указателя до точки с координатами xc+round(lh*cos(u)),yc-round(lh*sin(u)). Координату x получаем, сложив xc и длину стрелки, умноженную на косинус угла. Поскольку косинус угла - величина вещественная, а координаты должны быть целочисленными, нужно использовать функцию round - округление. Вопрос на засыпку: почему нельзя писать lh*round(cos(u))? Минус при вычислении координаты y связан с тем, что ось у направлена не вверх (как обычно принято в математике), а вниз, ну для тебя, как специалиста по Бейсику это не должно удивить. 6. Последние три строчки скопируй два раза и модифицируй для отображения минутной и секундной стрелок. Справишься? 7. Теперь нужно подключить эту новую форму к нашей программе. Перейди в unit1.pas и найди блок, который начинается со слова uses. В этом списке указываются все модули подключённые к твоей программе. В конец этого списка через запятую поставь имя своего нового модуля. При запуске программы будет открываться твоя первая форма, чтобы открыть вторую, нужно дать команду form2.show; Подумай, где можно дать эту команду. Кнопочку поставить или на какое событие у формы повесить (например, у формы тоже есть событие onclick). Важно, что бы это событие вызывалось достаточно редко (один раз или по действию пользователя) - событие ontimer не подойдёт. Запусти программу. Часы работают. Только стрелки не стираются. Нужно очищать image перед каждой новой отрисовкой. Самый простой способ очистить image - закрасить его весь цветом фона. 1. Объяви новую переменную rect типа trect. Этот тип содержит внутри себя 4 поля - left, top, right, bottom целочисленного типа, и предназначен для определения координат прямоугольника. 2. В самом начале тела процедуры нужно присвоить полям rect значения координат прямоугольника, который мы хотим закрасить и вызвать метод для закраски: rect.left := 0; Вопросы и ответыВ. Вроде часы со стрелочками у меня работают=) Только вот такой вопрос: можно ли сделать так чтобы минутная стрелка перемещалась один раз в минуту, а не медленно двигалась по кругу? (аналогично часовая) О. Конечно, можно. Для минутной стрелки нужно делать угол кратным величине pi/30. Например, так: u := round(u*30/pi)/(30/pi); или так: u := int(u*30/pi)/(30/pi); Функция round, напомню, округляет числа, а int - отбрасывает дробную часть. (Вообще-то между ними есть ещё одно очень серьёзное отличие: round возвращает целочисленное значение, а int - вещественное, но для данной задачи это не важно). Для часовой - думайте сами. :-) В. На счёт второй формы, можно просто задать ей свойство visible в true, тогда её будет видно при запуске, но она будет типо второстепенной. О. Можно. Я хотел просто продемонстрировать возможность в любой момент показать форму (метод show), а в обном из следющих уроков - спрятать её (метод hide). Для этих целей можно присваивать значения true и false свойству visible - оба способа практически равнозначны (в действительности и во втором способе вызываются методы show и hide, и в первом изменяются значения visible), но рекомендуют использовать методы, как более корректный с точки зрения объектно-ориентированного программирования подход. В. Теперь на счёт закрашивания цветом фона и вообще цвета фона=) Как его (цвет фона) задавать? да и цвет линии=) В паскале для этого дела есть функции setcolor - для рисования и setbkcolor - для фона. В Делфи я ниче подобного не нашла=( О. У canvas есть свойства brush (кисть) и pen (карандаш), так вот, за закрашивание областей отвечает кисть, а за рисование карандаш. У них есть куча свойств, в том числе и цвет. Нажмите f1, выделив компонент image, щёлкните по ссылке properties, найдите canvas, опять properties, и т.д. - почитайте сами что есть у brush и pen. Мы этим тоже обязательно займёмся, но немного позже. В. И ещё на счёт паскаля, там анимацию можно делать двумя способами или страницами или перерисовывать, так вот, при перерисовывании сначала рисуется что-то цветом, потом закрашивается цветом фона, потом перерисовывается и т.д. Не знаю, можно ли с нашими стрелками сделать нечто подобное=) О. В Паскале рисование производится непосредственно работой с видеокартой, в delphi тоже возможен подобный вариант с использованием, например, библиотеки directx, но сейчас мы рисуем используя возможности операционной системы. Рисунок у нас простенький, так что всё работает без проблем. В принципе можно эмулировать привычные Вам из Паскаля страницы с помощью двух одинаковых компонентов image, расположенных друг под другом, и меняя у поочерёдно меняя у них свойство visible. В. И ещё один вопрос на счёт часов, то что графический таймер немножечко отстаёт от текстового - это нормально? О. Надо уменьшить interval у таймера. :-) |