Скрипт аналоговых часов на Python

Всем привет! Сегодня я расскажу как создать аналоговые часы на Python 3.0  и вывести их с помощью tkinter.
Сначала разберем самое интересное. подключаем модули math (для вычислений) и time (для получения значений часов минут и секунд на вашем компьютере).
# -*- coding:utf-8 -*-
import math #подключаем модуль math
import time #подключаем модуль для определения времени и работы со временем
Подключаем графическую библиотеку tkinter и инициализируем окно:
from tkinter import * #подключаем графическую библиотеку tkinter
root = Tk()
Создаем холст размером 500 на 500 пикселей и размещаем его в окне
canvas = Canvas(root, width = 500, height = 550) #инициализация холста 500х500
canvas.pack()#размещаем холст в нашем окне


Теперь нарисуем просто круг - будущий циферблат
canvas.create_oval(10, 10, 490, 490, fill = "lightblue") #циферблат  просто круг
Теперь выведем надпись: Сделано на Python и точку - центр часов:
#вывод текста "cделано на Python"
canvas.create_text(250, 350, text = 'сделано на Python', font = ('Arial', 8)) 
#выводим точку - центр циферблата, чтобы было куда стрелки крепить
canvas.create_text(250, 225, text = '.', font = ("Arial", 62)) 
Теперь зададим счетчик цикла i и выведем рисочки секунд и часов
i = 0 #счетчик цикла
while i < 60:   #цикл вывода секундных рисочек
    i = i + 1
    canvas.create_line(250 + 210 * math.cos(-i * 6 * math.pi/180 + math.pi/2),
                       250 - 210 * math.sin(-6 * i * math.pi/180 + math.pi/2),
                       250 + 190 * math.cos(-6 * i * math.pi/180 + math.pi/2),
                       250 - 190 * math.sin(-6 * i * math.pi/180 + math.pi/2),
                       width = 2)
    if i % 5 == 0:  #когда i кратно 5 выводим более жирную рисочку для обозначения часов
        canvas.create_line(250 + 215 * math.cos(-i * 6 * math.pi/180 + math.pi/2),
                           250 - 215 * math.sin(-6 * i * math.pi/180 + math.pi/2),
                           250 + 190 * math.cos(-6 * i * math.pi/180 + math.pi/2),
                           250 - 190 * math.sin(-6 * i * math.pi/180 + math.pi/2),
                           width = 4)
        continue
Выведем цифры:
i = 0    
while i < 12:  #цикл вывода цифр часов
    i += 1
    canvas.create_text(250 + 225 * math.cos(-i * 30 * math.pi/180 + math.pi/2),
                       250 - 225 * math.sin(-30 * i * math.pi/180 + math.pi/2),
                       text = i, font = ('Arial' ,16))
Далее создаем бесконечный цикл, получаем значение текущего времени выводим стрелки бегущую строку и т.д. все понятно из коментариев в коде:
i = 950   #счетчик цикла  и координата х для вывода текста бегущей строки
while 1:  #основной бесконечный цикл
    time_now = time.localtime()#получаем текущее время в виде
#time.struct_time(tm_year=2016, tm_mon=3, tm_mday=27, tm_hour=22,
#tm_min=23, tm_sec=35, tm_wday=6, tm_yday=87, tm_isdst=0)
    time_sec = int(time.strftime("%S", time_now))  #получаем секунды из переменной time_now
    time_hour = int(time.strftime("%I", time_now)) #получаем часы из переменной time_now
    time_min = int(time.strftime("%M", time_now))  #получаем минуты из переменной time_now
    sec_angle = 6 * time_sec                 #угол отклонения секундной стрелки за 1 секунду
    min_angle = time_min * 6 + time_sec * 0.1    #угол отклонения минутной стрелки за 1 секунду
    #угол отклонения часовой стрелки за 1 секунду
    hour_angle = time_hour * 30 + time_min * 60 * (30/3600) 
    
    
    
    #рисуем минутную стрелку
    line_min = canvas.create_line(250,
                                  250,
                                  250 - 180 * math.cos(min_angle * math.pi/180 + math.pi/2),
                                  250 - 180 * math.sin(min_angle * math.pi/180 + math.pi/2),
                                  width = 3, fill = 'darkblue')
    #рисуем часовую стрелку
    line_hour = canvas.create_line(250,
                                   250,
                                   250 - 150 * math.cos(hour_angle * math.pi/180 + math.pi/2),
                                   250 - 150 * math.sin(hour_angle * math.pi/180 + math.pi/2),
                                   width = 5, fill = 'darkblue')
    #рисуем секундную стрелку
    line_sec = canvas.create_line(250,
                                  250,
                                  250 - 180 * math.cos(sec_angle * math.pi/180 + math.pi/2),
                                  250 - 180 * math.sin(sec_angle * math.pi/180 + math.pi/2),
                                  width =2, fill = 'red')
    #Задаем бегущую строку
    text_bottom = canvas.create_text(i, 525, 
                                     text = 'Хочешь научиться программировать на Python?'+
                                     'Узнай все подробности на http://pro365.net', font = ('Arial',16))
    i = i - 0.5
    if i == -600:  
        i = 950    
    root.update()#обновляем экран/холст
    canvas.delete(line_sec) #удаляем секундную стрелку
    canvas.delete(line_min) #удаляем минутную стрелку
    canvas.delete(line_hour) #удаляем часовую стрелку
    canvas.delete(text_bottom) #удаляем строку внизу

root.mainloop   #создаем постоянный цикл
                       
Файл скрипта можно скачать по ссылке и запускать на Python 3:

https://drive.google.com/file/d/0Bzi-qFYpx9H1VjhXdG5FYnFxZjQ/view?usp=drivesdk&resourcekey=0-YqyP_ZGDwF360fGSdIVrlQ
Далее для тех кто хочет разобраться немного математики.
Чтобы создать аналоговые часы в любом языке программирования нужно немного математики
Рассчитаем на какой угол повернуться секундная, часовая и минутная стрелки за одну секунду:
Секундная повернется на угол 360 °/60 = 6 °, т.к. вся окружность 360 ° и всего по ней распределены 60 секунд.
Минутная стрелка за это время повернется на 1/60 минуты т.е. расстояние от одной рисочки минут до другой разделится на 60 частей и каждую секунду минутная стрелка будет проходить одну часть которая рассчитывается так: (1/60) * (360 °/60) = 0,1 °.
Часы на циферблате располагаются через каждые 30 °. Расстояние (значение угла) от одного часа до следующего поделится на 3600 частей потомучто в часе 3600 секунд. Значит часовая стрелка за 1 секунду будет перемещаться на 1/3600 секунды или 1/60 минуты (т.к. один час равен 60 мин.) и расстояние между рисочками от одного часа до другого равно 5 рисочкам минут. Таким образом угол на который повернется часовая стрелка за секунду будет равен
30 °/3600 = 0,0083(3).
Опираясь на рассуждения выше запишем формулы расчета углов поворота для каждой стрелки мы можем написать формулы для отсчета углов:
#угол отклонения секундной стрелки за 1 секунду
sec_angle = 6 * time_sec
#угол отклонения минутной стрелки за 1 секунду
min_angle = time_min * 6 + time_sec * 0.1 
#угол отклонения часовой стрелки за 1 секунду
hour_angle = time_hour * 30 + time_min * 60 * (30/3600)

как можно заметить секундная стрелка будет двигаться рывками (дискретно) как в кварцевых часах,
а остальные стрелки двигаются плавно.
Описание переменных:
time_sec, time_min, time_hour - реальные значения времени соответственно секунд, минут и часов которое установлено на вашем компьютере.
Стрелки часов выходят из центра. Для отрисовки стрелок нужно создать линию один конец которой известен (условный центр - допустим x и y) , для определения координат второго конца потребуются тригонометрические формулы. Координаты любой стрелки могут быть описаны следующим образом
начало - (x, y), конец - (x - x1 * cos(angle * П/180 + П/2), y - y1 * sin (angle * П/180 + П/2) ).
Вместо angle подставляем sec_angle если стрелка секундная и т.д. Умножение на П/180 нужно для того чтобы перевести градусы в радианы,  + П/2 нужно для того чтобы начало отсчета было от 12 часов.
Формулы для всех стрелок будут выглядеть так:
    #рисуем минутную стрелку
    line_min = canvas.create_line(250,
                                  250,
                                  250 - 180 * math.cos(min_angle * math.pi/180 + math.pi/2),
                                  250 - 180 * math.sin(min_angle * math.pi/180 + math.pi/2),
                                  width = 3, fill = 'darkblue')
    #рисуем часовую стрелку
    line_hour = canvas.create_line(250,
                                   250,
                                   250 - 150 * math.cos(hour_angle * math.pi/180 + math.pi/2),
                                   250 - 150 * math.sin(hour_angle * math.pi/180 + math.pi/2),
                                   width = 5, fill = 'darkblue')
    #рисуем секундную стрелку
    line_sec = canvas.create_line(250,
                                  250,
                                  250 - 180 * math.cos(sec_angle * math.pi/180 + math.pi/2),
                                  250 - 180 * math.sin(sec_angle * math.pi/180 + math.pi/2),
                                  width =2, fill = 'red')
На этом все если есть вопросы задавайте в комментариях.

13 комментариев:

  1. Ответы
    1. добрый день! будьте добры,аргументируйте ваш вопль пожалуйста :)

      Удалить
    2. красава , ответочка супер

      Удалить
    3. Этот комментарий был удален администратором блога.

      Удалить
    4. Этот комментарий был удален администратором блога.

      Удалить
  2. В Pascal эта программа выглядит короче и проще, по моему.

    ОтветитьУдалить
  3. Soory! Часы с секундной стрелкой написать в паскале будут иметь более короткий код.

    ОтветитьУдалить
  4. Unknown просто хамит. Не даром имя такое избрал!
    Материал интересен, спасибо!
    А вот мой: http://ite.kspu.edu/webfm_send/1073
    Желаю успеха блогеру!

    ОтветитьУдалить
  5. Благодарю)
    я начинающий, и хотелось бы побольше готовых и так хорошо описанных примеров.

    ОтветитьУдалить
  6. вместо вайла лучше пользоваться фором это раз. А во вторых: зачем реклама!?

    ОтветитьУдалить
  7. Идея хорошая, но код нужно доработать... Напрмер с бесконечным циклом Вы навертели непонять чего. Зачем столько i? Там они вообще не нужны ;)

    ОтветитьУдалить
    Ответы
    1. это писал начинающий, движимый одним желанием написать что нибудь необычное и чтобы было весело. своей цели я добился :)

      Удалить
  8. Идея хорошая. У меня несколько комплектов циферблатов и стрелок красивых. ХОЧУ: 1. Сделать часы с циферблатом и стрелками в png формате. 2, Чтобы каждый день циферблат и стрелки по кругу менялись. Благодарствую заранее

    ОтветитьУдалить