Главная страница ЕЖИдневника


Уроки по Delphi

Урок 6
Внеурочье
Урок 5 Графические часы
Урок 4
Внекласс-1
Урок 3
Урок 2
Урок 1
Урок 0
Уроки по Dephi

Урок 6. Циферблат для наших часов

Исходные тексты программы здесь


Понятия о процедурах и функциях. Синтаксис описания процедуры. Вывод текста на Canvas с помощью метода TextOut. Цикл с параметрами. Перевод целого числа в строку. Шрифт для вывода текста на Canvas, вычисление высоты и ширины выводимого текста. Вывод текста под углом.

В предыдущих уроках я уже использовал такие слова как «метод», «процедура» и «функция». Думаю, что ты на интуитивном уровне понимаешь смысл этих слов, но давай дадим им более-менее чёткое определение.

Итак, процедура - это подпрограмма, которая не возвращает никаких значений (все обработчики событий, которые мы писали, были процедурами - они выполняли какую-то работу, но ничего не возвращали). Что такое «подпрограмма», надеюсь, объяснять не надо? :-) Описание процедуры начинается со слова procedure. Функция - подпрограмма, которая возвращает результат своей деятельности в виде значения какого-либо типа (например, мы использовали функции Time, sin, cos, которые возвращают соответственно время в виде значения типа TDateTime, синус и косинус аргумента в виде вещественного числа). Описание функции начинается со слова function и заканчивается указанием типа возвращаемого функцией значения. Таким образом, процедуру можно использовать как самостоятельную команду, а функцию можно использовать в различных (не обязательно математических) выражениях.

В Delphi есть самостоятельные подпрограммы и методы, принадлежащие объектам. Например, все обработчики событий принадлежат форме, а методы MoveTo, LineTo, TextOut - принадлежат Canvas (Canvas в свою очередь принадлежит Image1), поэтому для их использования требуется указывать всех их «хозяев». Непосредственный хозяин указывается при описании подпрограммы.

Подпрограмма может иметь параметры (в sin и cos нужно передавать один параметр - угол в радианах), а может их не иметь (в функцию Time никаких параметров передавать не нужно). При описании, указывается, какие параметры имеет подпрограмма и каких типов эти параметры.

До сих пор, новые процедуры и функции я разъяснял «на пальцах», но с этого момента буду использовать более строгое их описание. Вот так:

procedure TCanvas.TextOut(x, y : integer; const text : string);

Метод-процедура TextOut описанная в типе TCanvas (и имеющаяся таким образом в любом свойстве Canvas типа TCanvas) выводит текст переданный параметром text начиная с точки с координатами x и y. Обрати внимание: x и y имеют одинаковый тип, поэтому отделяются друг от друга запятой, а сам тип integer отделяется от них двоеточием. Переменная text имеет строковый тип string (это тот же тип, что и у свойства Caption) и отделяется точкой с запятой от параметров другого типа. Переменным могут предшествовать слова const или var (а может и не быть никаких дополнительных слов) - об их значении поговорим позднее, когда сами будем писать процедуры и функции.

Итак, мы можем теперь 12 раз использовать метод TextOut, что бы написать 12 чисел на нашем циферблате… Однако программисты - народ ленивый. Зачем нам писать 12 раз практически одно и тоже? Надо придумать что-нибудь, что бы написать только одну команду, а она повторилась бы нужное количество раз. Для этой цели придуманы циклы. Сегодня мы рассмотрим один из вариантов цикла - цикл с параметрами. Выглядит этот цикл вот так:

for i := 1 to 12 do комада;

i называется параметром цикла, это должна быть ранее описанная локальная переменная целочисленного типа (разумеется она может называться не i, а как-то иначе). Вместо чисел 1 и 12 могут фигурировать любые другие числа, переменные или выражения, лишь бы они были целочисленными. И, конечно, вместо «команда» должен быть записан оператор или команда Delphi, кстати, это называется тело цикла. Если нужно несколько команд, то следует использовать операторные скобки begin-end. Это не обязательно, но настоятельно советую оформлять цикл вот так:

for i := 1 to 12 do
begin
  команда;
end;

То есть использовать begin-end даже в том случае, если у тебя всего одна команда, и начинать begin с новой строки с того же уровня, что и for. Программа в этом случае выглядит строже и читать её удобнее.

Итак, у нас есть всё необходимое для рисования циферблата.

1. Описываешь переменную i. Описываешь новую типизированную константу, например, rc, и присваиваешь ей то значение, на каком расстоянии от центра часов ты хочешь видеть надписи циферблата. Делаешь цикл. (Кто на меня ругался, что я всё разжёвываю и думать совсем не надо? Вот, вспоминай, что значит «описать» или «объявить» переменную) :-))

2. В теле цикла пишешь

    Image1.Canvas.TextOut(xc+Round(rc*cos(Pi/2-i*Pi/6)),yc-Round(rc*sin(Pi/2-i*Pi/6)),IntToStr(i));

Строка довольно длинная, скорее всего, ты читаешь этот текст разбитым на две строки. Лучше всего в Delphi написать её всё-таки в одну строку, но можно и разбить (хоть на две, хоть на три, хоть на пять), нельзя только переносить слова, а между словами и всеми остальными знаками можно ставить сколько угодно пробелов или переводов строки.

Здесь мы используем функцию

function IntToStr(Value: Integer) : string;

Которая целочисленное значение Value (в нашем случае i) переводит в строковый формат.

3. Для вывода текста используется шрифт прописанный в свойстве Image1.Canvas.Font. Измени параметры этого шрифта так что бы было красиво. Этот шрифт, как и Canvas, недоступен в инспекторе объектов - его свойства можно менять только в программе. Обязательно поменяй название шрифта на какой-нибудь TrueType шрифт, например, на Comic Sans MS (это нам потребуется чуть позже).

4. Думаю, тебе не понравится, что циферблат немного сдвинут вправо и вниз (это произошло из-за того, что координаты, которые ты задавала в TextOut - это координаты левого верхнего угла надписи, а мы ожидаем, что это будут координаты центра соответствующих чисел). Исправить это можно пересчитав координаты для вывода текста с использованием функций:

function TextHeight(const Text: string): Integer;
function TextWidth(const Text: string): Integer;

Эти функции вычисляют соответственно высоту и ширину текста. Надеюсь, справишься.

5. Будет замечательно, если наши надписи будут выводиться не горизонтально, а под нужным углом, так, как это обычно и делается на часах. К сожалению, вывод текста под углом не включён в возможности Canvas. Поэтому эта задача далеко выходит за рамки текущего урока, более того, эта возможность даже наполовину не документирована (по крайней мере в помощи для Delphi5 я не нашёл типа TLogFont). Придётся тебе просто скопировать нужный текст, не вникая особо в его смысл.

Итак, объяви переменную LogFont типа TLogFont. Перед вызовом процедуры TextOut (но после того как ты поменяешь шрифт на TrueType) напиши текст:

     GetObject(Image1.Canvas.Font.Handle,SizeOf(LogFont),Addr(LogFont));
     LogFont.lfEscapement := Round(-i*30*10);
     Image1.Canvas.Font.Handle := CreateFontIndirect(LogFont);

Смысл этих трёх команд в том, что бы установить угол, под которым будет выводиться текст в -i*30 градусов.

Домашнее задание. Полагаю, что пункты 1 и 4 достаточно объёмные и хитрые, что бы не давать тебе дополнительных заданий.

На следующем уроке мы сделаем так, что бы пользователь мог настроить наши часы в соответствии с нашими вкусами.

Комментарии читателей.

Iron Monk:

Коды символов в Delphi это можно узнать с помощью процедуры обрабатывающей сообщение WM_CHAR ;

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;
 
type
  TForm1 = class(TForm)
    Label1: TLabel;
  private
  procedure PressKey_Char(var PressKey: TWMKEY); message WM_CHAR;
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
procedure TForm1.PressKey_Char(var PressKey: TWMKEY);
begin
  Label1.Caption:=IntToStr(PressKey.CharCode);
  inherited;
end;
end.


Все комментарии (цензурные и по возможности грамотные) рассматриваются в порядке живой очереди, принимаются к сведению и даже публикуются на сайте. Так что если тебе есть что сказать по поводу вышепрочитанного - мыль сюда!!! ;)

пользовательское соглашение, политика конфиденциальности