«Часы со Стрелками» на платформе WPF (Windows Presentation Foundation) .NET Core в качестве знакомства с новой моделью создания графических интерфейсов. Окно часов круглой формы, реалистичны настолько, что просто хочется снять их с экрана компьютера и повесить на стену. Недалеко то будущее, когда так и будет. Красочный интерфейс часов создан с применением только стандартных элементов, включённых в каркас WPF.
В отличие от Windows Forms графика в WPF полностью основана на технологии DirectX. Составляющие интерфейса пользователя, кнопки, диалоговые окна, списки, текстовые блоки и даже сам текст прорисовывается аппаратно-ускоренным способом. Причём нет никаких методов OnPaint(), где мы должны создавать код рисования. На мониторах с разным количеством точек на дюйм DPI, интерфейс приложений WPF сохраняет неизменное качество графики.
Для сравнения графических возможностей Windows Presetation Foundation и C++ MFC программы посмотрите исходник часов на GDI
Создание часов на JavaScript
В приложении имитации стрелочных часов демонстрируется модель компоновки WPF, совершенно отличной от принципа размещения элементов управления Windows Forms. Создаётся первый и единственный контейнер, все остальные контейнеры и элементы управления вкладываются в главный. Каждый контейнер WPF обладает собственной логикой размещения дочерних элементов в пределах своего пространства. В WPF рекомендуется использовать относительные координаты. Для изменения позиции элементов используются величины: Margin, Padding, HorizontalAlignment, VerticalAlignment контейнеров и их вложений.
Окно круглой формы
В WPF легко создавать окна фигурной формы. Разработчики Windows Presentation Foundation добавили свойство Window.AllowsTransparency специально для упрощения создания окон непрямоугольной формы. Если свойству присвоить значение истинно, то окно становится прозрачным, но всё что расположено на окне видимо. Для формирования круглого окна я использовал элемент Border с закруглёнными углами. При изменении свойства Border.CornerRadius можно получать циферблат прямоугольной, с закругленными углами и даже круглой формы.
Чтобы получить окно произвольной формы, необходимо присвоить некоторым свойствам окна определенные значения: удалить или сделать фон окна прозрачным, скрыть заголовок и границу окна, позволить окну быть прозрачным.
.
Код графики в XAML
Интерфейс программ WPF можно создавать двумя способами: используя расширяемый язык разметки в текстовых файлах XAML и классическим программным способом. В прикрепленных исходниках используются оба способа построения интерфейса.
Язык XAML базируется на структуре файлов XML со своими специфическими расширениями. Файлы XAML отделяют графическую часть приложения от программной. Такое разделение даёт преимущество при командной разработке, когда дизайнеры могут сосредоточиться над графикой, а программисты работают с кодом. Индивидуальные разработчики также получают эффект повышения качества и скорости разработки, работая отдельно с графическим и программным модулями.
Как создать программу часы
Для работы с графикой приложения используя язык XAML в комплект MS Visual Studio входит инструмент для дизайнеров Blend. Возможности его гораздо шире, чем редактор встроенный в Visual Studio. Например, Blend позволяет визуализировать создание анимации, осуществлять её предпросмотр и редактирование существенно увеличивая скорость разработки.
XAML код графики приложения
Программная часть интерфейса
Несмотря на то, что интерфейс приложения Windows Presentation Foundation рекомендуется реализовывать в файле XAML, иногда рациональней всё же создавать графику программным способом. Речь идёт о многократно повторяющихся элементах интерфейса. Например, в прикрепленном приложении это метки циферблата: 12 часовых и 60 минутных. В программном коде, в цикле мы их легко реализуем.
// Минутная маркировка циферблата void MinuteMarks() < for (int i = 0; i < 60; i++) < // Контейнер для метки. // Необходим для вращения пространства // в котором расположена декоративная метка. var b = new Border() < HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Center, RenderTransformOrigin = new Point(0.5, 0.5), // Базовая ориентация контейнера метки горизонтальное, // поэтому высота играет роль толщины метки. Height = 2 >; // В роли метки выступает элемент Border. var b1 = new Border() < Background = Brushes.Brown, // Базовая ориентация горизонтальная, // поэтому ширина визуально является длиной метки. Width = 10, HorizontalAlignment = HorizontalAlignment.Right >; b.Child = b1; // Вращаем только сам контейнер. var rotate = new RotateTransform(i * 6); b.RenderTransform = rotate; // Исключаем из маркировки метки 0 и // через каждые 30 градусов. // В этих местах будут часовые метки. if (i * 6 % 30 != 0) < // Добавляем на циферблат контейнеры с метками. ClockFace.Children.Add(b); >> >
Принцип вращения стрелок
Анимационная графика стрелок приложения-часов построена так: создаётся контейнер-носитель, в него добавляются декоративные элементы. Так формируется статическая графика стрелок. На рисунке показана секундная стрелка. Корпус стрелки состоит из двух элементов Border , которые создают визуализацию указателя и противовеса. Благодаря графической технологии WPF «запчасти» часов выглядят очень реалистично.
Слаженное вращение всех частей стрелок обеспечивает контейнер-носитель. Функцию контейнера выполняет также элемент управления Border . Относительно контейнера дочерние элементы неподвижны. Контейнер вращается относительно центра циферблата, сохраняя положение своих элементов. Такой способ анимации стрелок значительно упрощает создание целостного вращательного движения.
Код XAML секундной стрелки:
Для вращения контейнера точно вокруг своего центра определяем свойство RenderTransformOrigin=»0.5,0.5″ . Интересная деталь кода противовеса: свойство Margin имеет отрицательные значения. Такое делается тогда, когда необходимо «раздуть» элемент за пределы пространства родителя.
Механизм вращения стрелок
Для вращения стрелок часам требуется часовой механизм. Электродвигателем в приложении служат события таймера. Во время тика таймера происходит вычисление углов поворота всех стрелок часов. Часы приложения синхронизируются с системным временем компьютера.
Таймер работает с разрешением один тик в 100 миллисекунд, и секундная стрелка движется синхронно с секундами цифровых часов операционной системы. Положения стрелок исчисляются из базового угла поворота 6 градусов. Секундная стрелка за 60 шагов проходит полный круг (360°) циферблата часов.
Листинг кода вычисления углов
private void Timer_Tick(object sender, EventArgs e) < var rotateSecondArrow = new RotateTransform(); var rotateMinuteArrow = new RotateTransform(); var rotateHourArrow = new RotateTransform(); // Данные текущего времени. int sec = DateTime.Now.Second; int min = DateTime.Now.Minute; int hour = DateTime.Now.Hour; // Вычисленный угол для секундной стрелки. rotateSecondArrow.Angle = baseAngleNumberSystem * sec; // Вращение стрелки на вычисленный угол. SecondArrow.RenderTransform = rotateSecondArrow; // Угол минутной стрелки от количества полных минут плюс // угол секунд приведенный к долям текущей минуты. rotateMinuteArrow.Angle = (min * baseAngleNumberSystem) + (rotateSecondArrow.Angle / 60.0); MinuteArrow.RenderTransform = rotateMinuteArrow; // Данные часа конвертируем в 12-часовой вид, // вычисляем угол полных часов плюс // угол минут приведенный к долям текущего часа. rotateHourArrow.Angle = (hour — 12) * baseAngleHour + rotateMinuteArrow.Angle / 12; HourArrow.RenderTransform = rotateHourArrow; >
Исходник программы часов на WPF
Архив файла содержит исходник программы часов. Инструмент программирования MS Visual Studio 2019. Среда .NET Core 3.1
Источник: www.interestprograms.ru
Аналоговые часы SFML C++
Мультимедийная библиотека SFML лечит головную боль не только новичкам в игровой индустрии, но и преподавателям информатики в школе. Основная задача которых состоит в том, чтобы не только научить ребёнка программировать, но и привить любовь к разработке приложений. Используя простые графические объекты и их методы можно за короткое время создать прототип игры или симулятор физико-математических процессов. В этой статье мы рассмотрим разработку аналоговых часов на C++ используя библиотеку SFML.
Инструменты для разработки
- Visual Studio c установленным пакетом «Разработка классических приложений на С++».
- Мультимедийная библиотека SFML.
- Подключаемый файл заголовка SFMLWorldTime.
- Шрифты и программный код для самостоятельной разработки или репозиторий.
Подготовительная работа
Подключаем к Visual Studio библиотеку SFML и копируем шаблон кода библиотеки SFML в редактор кода.
#include #include»SFMLWorldTime.h» using namespace sf; int main() < // Создаём графическое окно размером 900х900 RenderWindow window(VideoMode(900, 900), L»Аналоговые часы», Style::Default); window.setVerticalSyncEnabled(true); // Вертикальная синхронизация SFMLWorldTime etm(50, 50, 4, Color::Yellow); // Объект электронные часы while (window.isOpen()) < Event event; while (window.pollEvent(event)) < if (event.type == Event::Closed) window.close(); >window.clear(Color::Blue); // Очищаем графическое окно и закрашиваем в синий цвет etm.drawTime(window); // Рисуем электронные часы в графическом окне window.display(); > return 0; >
Добавляем в папку проекта файлы SFMLWorldTime.h и SFMLWorldTime.cpp и папку со шрифтами lib.
Добавляем в проект файлы SFMLWorldTime.h и SFMLWorldTime.cpp.
В код шаблона программы прописываем вызов заголовочного файла SFMLWorldTime.h.
#include»SFMLWorldTime.h»
Создаём объект электронные часы и рисуем их в графическом окне.
SFMLWorldTime etm(50, 50, 4, Color::Yellow); etm.drawTime(window);
Часовых дел мастер
#define _USE_MATH_DEFINES #include #include»SFMLWorldTime.h» #include using namespace sf; using namespace std; int main() < RenderWindow window(VideoMode(900, 900), L»Аналоговые часы», Style::Default); window.setVerticalSyncEnabled(true); SFMLWorldTime etm(50, 50, 4, Color::Yellow); // Корпус аналоговых часов CircleShape circleTime(300.f); circleTime.setOrigin(150, 150); circleTime.setPosition(303, 303); circleTime.setFillColor(Color::Blue); circleTime.setOutlineThickness(10); circleTime.setOutlineColor(Color::Yellow); // Риски аналоговых часов объявление переменных CircleShape PointMin; PointMin.setFillColor(Color::Yellow); float radiusNum = 280; // радиус расположения рисок float radiusPoint; float CenterClockX = 450; float CenterClockY = 450; float xPoint, yPoint; // Оцифровка циферблата аналоговых часов объявление переменных Font fontTime; if (!fontTime.loadFromFile(«lib/dockerthree.ttf»)) return 777; Text TimeText; TimeText.setFont(fontTime); TimeText.setCharacterSize(30); TimeText.setFillColor(Color::Yellow); float numx, numy; // Рисуем стрелки аналоговых часов RectangleShape secArrow(Vector2f(2, 280)); //секундная InitRect(secArrow, 453, 453, 1, 280, Color::Red); RectangleShape minArrow(Vector2f(8, 260)); //минутная InitRect(minArrow, 455, 455, 4, 260, Color::Yellow); RectangleShape hourArrow(Vector2f(12, 180)); //часовая InitRect(hourArrow, 455, 455, 6, 180, Color::Yellow); while (window.isOpen()) < Event event; while (window.pollEvent(event)) < if (event.type == Event::Closed) window.close(); >window.clear(Color::Blue); etm.drawTime(window); // электронные часы window.draw(circleTime); // корпус аналоговых часов // Риски аналоговых часов for (int a = 0; a < 60; a++) < if (a % 5 == 0) radiusPoint = 8; else radiusPoint = 4; xPoint = CenterClockX + radiusNum * cos(-6 * a * (M_PI / 180) + M_PI / 2); yPoint = CenterClockY — radiusNum * sin(-6 * a * (M_PI / 180) + M_PI / 2); PointMin.setRadius(radiusPoint); PointMin.setOrigin(radiusPoint / 2, radiusPoint / 2); PointMin.setPosition(xPoint, yPoint); window.draw(PointMin); >// Оцифровка циферблата аналоговых часов for (int i = 1; i secArrow.setRotation(6 * etm.getsec()); // вращение секундной стрелки minArrow.setRotation(6 * etm.getmin() + etm.getsec() * 0.1); // вращение минутной стрелки hourArrow.setRotation(30 * etm.gethour() + etm.getmin() * 0.5); // вращение часовой стрелки window.draw(hourArrow); // часовая стрелка window.draw(minArrow); // минутная стрелка window.draw(secArrow); // секундная window.display(); > return 0; >
Рисуем окружность т.е. контур будущих часов
// Блок объявления и установки параметров объектов CircleShape circleTime(300.f); circleTime.setOrigin(150, 150); circleTime.setPosition(303, 303); circleTime.setFillColor(Color::Blue); circleTime.setOutlineThickness(10); circleTime.setOutlineColor(Color::Yellow); // Блок отрисовки графических объектов window.draw(circleTime);
Подключаем макрос математических констант
#define _USE_MATH_DEFINES
Подключаем заголовочный файл математических функций
#include
Объявляем объекты и переменные для рисования рисок часов.
Создаём объект круга, который и будет отображать окружность в виде рисок.
// Блок объявления и установки параметров объектов CircleShape PointMin; // объект круга PointMin.setFillColor(Color::Yellow); // цвет круга жёлтый
Объявим и инициализируем вещественную переменную значением расстояния от центра часов до расположения рисок.
float radiusNum = 280;
Создадим вещественную переменную размера рисок т.е. радиуса объекта круга PointMin
float radiusPoint;
Обозначим переменными координаты центра окружности
float CenterClockX = 450; float CenterClockY = 450;
Объявим переменные координат рисок
float xPoint, yPoint;
Рисуем риски в графическом окне
for (int a = 0; a < 60; a++) < // каждой пятой риски увеличиваем радиус if (a % 5 == 0) radiusPoint = 8; else radiusPoint = 4; // вычисляем координаты риски xPoint = CenterClockX + radiusNum * cos(-6 * a * (M_PI / 180) + M_PI / 2); yPoint = CenterClockY — radiusNum * sin(-6 * a * (M_PI / 180) + M_PI / 2); // задаём координаты и параметры риски т.е. объекту круга PointMin PointMin.setRadius(radiusPoint); PointMin.setOrigin(radiusPoint / 2, radiusPoint / 2); PointMin.setPosition(xPoint, yPoint); // рисуем риску в графическом окне window.draw(PointMin); >
В формуле вычисления координат рисок, используем математическую константу числа Пи — M_PI.
Объявим объекты и переменные для отображения циферблата часов
Загрузим шрифт для отображения цифр, создаём объект шрифта fontTime и загружаем в него шрифт dockerthree.ttf
Font fontTime; if (!fontTime.loadFromFile(«lib/dockerthree.ttf»)) return 777;
Создаём объект текста и задаём ему параметры: шрифта, размера и цвета.
Text TimeText; TimeText.setFont(fontTime); TimeText.setCharacterSize(30); TimeText.setFillColor(Color::Yellow);
Объявляем переменные координат текстового объекта, для отображения цифр.
float numx, numy;
Рисуем циферблат в графическом окне
for (int i = 1; i
Объявляем объекты для стрелок часов и настраиваем их.
RectangleShape secArrow(Vector2f(2, 280)); // Секундная стрелка InitRect(secArrow, 453, 453, 1, 280, Color::Red); RectangleShape minArrow(Vector2f(8, 260)); // Минутная стрелка InitRect(minArrow, 455, 455, 4, 260, Color::Yellow); RectangleShape hourArrow(Vector2f(12, 180)); // Часовая стрелка InitRect(hourArrow, 455, 455, 6, 180, Color::Yellow);
Графическое отображение стрелок базируются на объекте формы прямоугольника RectangleShape. Настраиваем объекты с помощью функции InitRect (), которая находится в заголовочном файле SFMLWorldTime.h.
Рисуем стрелки часов
// Изменение угла положения прямоугольников т.е. стрелок secArrow.setRotation(6 * etm.getsec()); // Вращение секундной стрелки minArrow.setRotation(6 * etm.getmin() + etm.getsec() * 0.1); // Вращение минутной стрелки hourArrow.setRotation(30 * etm.gethour() + etm.getmin() * 0.5); // Вращение часовой стрелки // Рисование стрелок в графическом окне window.draw(hourArrow); // часовая стрелка window.draw(minArrow); // минутная стрелка window.draw(secArrow); // секундная
Метод setRotation вращает объект вокруг заданной оси, согласно установленному углу поворота в параметрах метода.
Рассчитаем угол поворота стрелок.
Секундная стрелка повернется на угол равный 360 °/60 сек = 6 ° (вся окружность 360 ° по ней распределяем 60 секунд) и умножаем на текущее значение времени секунд.
Минутная стрелка за это время повернется на 360 °/60 мин = 6 ° умноженных на текущее значение времени минут и добавляем 6 °/60сек=0.1 ° умноженный на количество пройденного времени секунд.
Часовая стрелка за это время повернётся на 360°/12 часов = 30 ° умноженных на текущее время часов и добавляем 30 °/60мин=0,5° умноженным на пройденное время минут.
Более подробную инструкцию вы можете получить посмотрев видео «Аналоговые часы SFML C++».
Источник: habr.com