пятница, 25 марта 2016 г.

Как крутить шарикоподшипник. Ч.2 - часики.


Я уже не помню, как выглядел тот фанерный циферблат с картонными стрелками, который папа сделал, чтобы объяснить мне устройство часов. Помню только то страшное разочарование, когда я понял, что сутки состоят практически только из того, что я вижу с утра до ночи, и нет никакой второй такой же длинной как проживаемый мной день половины суток, которую я из-за своего детского бесправного положения вынужден просто проводить во сне. Мир стал другим. Оказалось, что полночь - это вовсе не такая же середина ночи, как полдень - середина дня. Мои мечты о том, что когда я стану взрослым, я смогу проживать каждый день в два раза больше времени, потому что никто не будет меня заставлять спать вторую, волшебную ночную половину суток, и я смогу играть ещё и ночью столько же, сколько днём - рассыпались в прах. Помню, что я испытал тогда чувство страшной утраты, осознав, что в сутках всего лишь только 24 часа.

Картинка из Википедии
Увлекшись программированием, я делал стрелочные часы на разных языках и под разные операционные системы. И поэтому делать очередные часы на FireMonkey было бы мне совсем не интересно, если бы не то обстоятельство, что здесь часы можно сделать чисто визуальными средствами, совсем не используя никакого "языкового" программирования. Итак, начинаем.

1. Создадим новое пустое мультиплатформенное приложение - File | New | Multi-Device Application, Blank Application. Во избежание потерь я сразу сохраняю приложение, дав модулю 'Unit1.pas' имя 'uMain', а проекту - имя 'Clock'. Затем после каждого шага я нажимаю Ctrl+S, чтобы сохранить работу. Увы, случаи бывают не только счастливые.

2. Бросим на форму TRectangle, отцентрируем его Align = Center и увеличим стороны до 350. Это будет циферблат.

3. Находим на Tool Palette и бросаем на квадрат (не забываем поглядывать в окно Structure) компонент TLayout, который при помощи Align = Top прижмём к верху квадрата. Layout1 при этом увеличит свою ширину до размеров квадрата - 350, а в высоту останется таким же, как был - 50. 

4. На Layout1 кидаем новый TRectangle. Его размер оставляем по умолчанию - 50х50. Центрируем фигуру Align=Center. Внимание, внимание - начинается подготовка к фокусу размещения цифр на циферблате: этот квадрат мы будем "вращать" вокруг центра, который находится в середине большого квадрата, т.е. от верхнего края маленького квадрата на расстоянии 350/2 = 175, что составляет 3,5 корпусов маленького квадрата. Поэтому у Rectangle2 ставим RotationCenter.Y = 3,5.

5. На маленький квадрат кладём TLabel, выравниваем по центру Align = Center и устанавливаем большой (TextSettings.Font.Size = 20) жирный (TextSettings.Font.Style = [fsBold]) шрифт. Ещё я включил автоподгон размера компонента по тексту AutoSize = True.  И ещё это - Text = '12'.



6. Одной цифры 12 (традиционно число на часах называется цифрой) будет маловато. Поэтому отмечаем Rectangle1 и копируем его на Layout1 ещё 11 раз, контролируя в окне Structure расположение новых копий и их количество. Количество можно легко отследить по номеру имени Label* - номера меток должны быть от 1 до 12.

7. И вот теперь начинается волшебство. Мы бегаем по списку квадратов в окне Structure, приглядываясь к именам Label* (начиная с Label2), и расставляем этим Rectangle* углы вращения Rotation.Angle = 30, 60, 90 ... 330.


8. Как мы видим, текст в квадратах также вращается. И как, вы думаете, будет выглядеть цифра 6 внизу циферблата, когда мы её туда вставим? Плохо она будет выглядеть. Поэтому цифры надо вeрнуть обратно в нормальное вертикальное положение. Тыча в хорошо видимые на форме Label* расставляем углы вращения Rotation.Angle = -30, -60, -90 ... -330.


9. Мне так понравилось бегать по Label* на форме,  что так и тянет пробежаться ещё раз и расставить меткам  свойство Text = '1', '2', ... '11'. Стоит ли себе отказывать? Нет, конечно! Получилось так красиво, что я даже добавил на циферблат фирменную часовую надпись TLabel (Align = Bottom, Position.Y = 232, TextSettings.HorzAlign = Center,   TextSettings.VertAlign = Leading, Text = 'FMX design'#13'model 4ACbI'). К сожалению, Object Inspector не позволяет вводить символ #13 в текст метки. Можно использовать текстовый вид формы - Alt+F12 или копировать компонент в редактор кода, и редактировать там.


10. Пришла пора стрелок. На Rectangle1 добавляем новый Rectangle14. Сделаем Align = Center, Width = 25, Height = 125. Это часовая стрелка. Сдвигаем стрелку вверх - Align = None, Position.Y = 75. Центр циферблата - 175. Получается, что вращение стрелки RotationCenter.Y будет на 100 ниже её верхнего края, что составляет от высоты фигуры 100/125 = 0,8. Так и запишем. А теперь создадим TFloatAnimation на RotationAngle. Включим анимацию Enabled = True, зациклим её Loop = True, StopValue = 360, а Duration = 144. Почему 144? Я подумал, что в реальном времени ждать оборота стрелки очень тяжело, и установил, что минутная стрелка будет проходить по цифре в секунду, т.е. на полный круг потратит 12 секунд, а часовая стрелка, как известно, движется в 12 раз медленнее минутной, т.е. 144 секунды.

11. На Rectangle1 добавляем новый Rectangle15. Сделаем Align = Center, Width = 10, Height = 160. Сдвигаем стрелку вверх - Align = None, Position.Y = 50. Вращение стрелки RotationCenter.Y будет на 125 ниже её верхнего края, что составляет от общей высоты фигуры 125/160 = 0,78125. Создаём TFloatAnimation на RotationAngle (Enabled = True, Loop = True, StopValue = 360, Duration = 12). Честно признаюсь, что хотел было сделать стрелку высотой 150, но при делении какое-то иррациональное число получалось. Поэтому я решил немного изменить картинку. И знаете что? По-моему стало даже лучше!


12. F9

После такого опыта, глядя на бодро вращающиеся часовые стрелки, так и хочется спеть "Нам нет преград!" (© А.А. Д'Актиль). И в следующем посте мы приступим уже непосредственно к самому опорному подшипнику качения.



ЗЫ: Исходники здесь: https://github.com/alhymov/Clock.git