Почему Desktop-приложение на Питоне?
Если Вы, как и я, решили впервые взглянуть в сторону Python после нескольких попыток изучения С++/C# то скорее всего первым проектом станет desktop-приложение. Отходя от темы скажу что тяга к изучению этих языков была безнадежно утрачена в виду классического преподавания в духе "лишь бы сдали" и бесчисленных однотипных и монотонных лекций. Как я сказал выше хоть и на начальном уровне, но я всё же касался разработки приложений для Windows и поэтому мне хотелось посмотреть на принципы работы питона сначала отсюда(а не прыгать в django и прочие мощные фреймворки). Должен предупредить - в статье не приводятся выдержки из кода и она является скорее выражением моих эмоций, полученных за этот проект.
Какое приложение создавать?
В этом я не сомневался ни секунды и сразу выбрал - ТАЙМЕР! Я люблю засыпать под звуки фильмов с различных ресурсов, но то что после их окончания комп работал лишние 6 часов меня решительно не устраивало. Я конечно знаю про существование разного рода приложений с подобным функционалом(например SMtimer), но во-первых его UX/UI это просто привет нулевым, а во-вторых хотелось всё-таки своё.
![Непосредственно сам SMtimer Непосредственно сам SMtimer](https://habrastorage.org/getpro/habr/upload_files/939/6f5/a95/9396f5a959c13cceaa2f706c3c2f8b8b.png)
Задачи намечены - время действовать
Посмотрев полтора гайда с youtube преисполнился и написал первый прототип с использованием стандартной библиотеки tkinter. Выглядело это весьма сомнительно с точки зрения того же UX/UI, но это уже было что-то
![Первая версия моего многострадального проекта Первая версия моего многострадального проекта](https://habrastorage.org/getpro/habr/upload_files/dcc/d26/448/dccd26448ca360a1530be915d0b96ed6.png)
Тут каждый может заметить и сказать "но ведь это ещё хуже чем SMtimer" и будут правы, в целом и меня посещали такие мысли и я решил обратиться к поиску чего-то что сможет сделать из этого адекватное приложение которым я смогу пользоваться без зазрения совести.
CustomTkinter или как я пытался познать дзен
После недолгого поиска я нашел его - CustomTkinter. Он обещал буквально сделать из моего прототипа приложение, которое будто изначально было в Windows 10. Непосредственно exampl'ы вы можете смотреть ниже:
![Темная тема "example" от CustomTkinter Темная тема "example" от CustomTkinter](https://habrastorage.org/getpro/habr/upload_files/b6c/1dd/0b1/b6c1dd0b121c875bee59ff265173f8b3.png)
![Соответственно светлая тема "example" от CustomTkinter Соответственно светлая тема "example" от CustomTkinter](https://habrastorage.org/getpro/habr/upload_files/04e/532/e60/04e532e604de089b24b99567140962ac.png)
Вдобавок к этому библиотека обещала и минимальные правки кода для переноса моего "прототипа" на эту прелесть, но мне предстоял ещё большой путь в понимании как это тут работает...
Куча проблем и нехватка понимания
Именно так бы я описал свой путь в познании этой библиотеки. Буквально пытаясь взаимодействовать с ней я понял как устроены типы данных Python(да, может показаться смешным, но когда впервые встречаешь NoneType слегка удивляешься), понял как взаимодействовать с объектами классов и собственно разделять код проекта на функциональные блоки (что до этого мне казалось чем-то странным). Но для того чтобы понять насколько всё было грустно в моих познаниях - вот референс который я запилил от безысходности( на тот момент я хотел получить хотя бы это):
![Как можно заметить даже цвет в тупую залит в Paint Как можно заметить даже цвет в тупую залит в Paint](https://habrastorage.org/getpro/habr/upload_files/466/5a2/d68/4665a2d68b7293bdbc64d9a4225653c6.png)
Проблем была целая гора - я решительно не мог понять как общаться с CusomTkinter - создание и позиционирование его объектов хоть сейчас и кажутся достаточно логичными и понятными, но тогда они были для меня сродни китайским иероглифам. После нескольких вечеров, проведённых за курением мануалов я смог собрать 3ю версию (её первая реинкарнация):
![Пусть и работающая на коленях, но РАБОТАЮЩАЯ версия Пусть и работающая на коленях, но РАБОТАЮЩАЯ версия](https://habrastorage.org/getpro/habr/upload_files/d93/5ee/dc7/d935eedc7c1870dea7a8cddd5a9b1a9a.png)
Получив это я уже был рад, что не сдался и приступил к починке расположения всех объектов по экрану. Однако следует упомянуть о "маленькая проблема" - в CustomTkinter нет SpinBox, а значит вводить данные было нужно либо с клавиатуры, либо искать как сделать этот самый SpinBox самому. Выбор пал на второй вариант, на сайте, посвященном самому ctk автор сделал FloatSpinBox, доработав который я уже мог получить то что хотел.
![Собственно FloatSpinBox Собственно FloatSpinBox](https://habrastorage.org/getpro/habr/upload_files/75f/e0e/361/75fe0e361be5c7eab3a7be2a13f2e5e0.png)
Главным его косяком было отсутствие реакции на колёсико мышки - для меня это было критично - нажимать 32 раза для установки минут меня не прельщало и я решил допилить его самостоятельно:
Добавил min и max value - теперь я мог использовать этот класс и для минут и для часов (сначала я просто наспамил несколько классов где вручную установил ограничения для каждого из них)
Реакция на колёсико мышки теперь охватывала весь SpinBox и это было чудесно. Если просто повесить обработчик на self.bind("MouseWheel", self.on_mouse_wheel)" то срабатывание будет только на границах entry и элементах кнопок, что просто ужасно.
Ну и конечно реализовал прокрутку в обратную сторону. Это так странно делать то что обычно реализовано уже за тебя.
Ну и немного поиграл с темами самого customtkinter:
![Рождение первого адекватного прототипа Рождение первого адекватного прототипа](https://habrastorage.org/getpro/habr/upload_files/692/66b/73a/69266b73a3722477acea59322a647f77.png)
![Темы которые я нашел на просторах github Темы которые я нашел на просторах github](https://habrastorage.org/getpro/habr/upload_files/160/4b0/fc1/1604b0fc1ae9076bb861f8961df29951.png)
Наконец то, что я и хотел получить
Теперь я решил сделать вывод времени до срабатывания. Я прорабатывал разные версии этого таймера и пришел к тому что запилил TimeBox. Главное отличие - никаких кнопок. Вывод конечно же стал гораздо веселее.
![Предрелизная версия моего таймера Предрелизная версия моего таймера](https://habrastorage.org/getpro/habr/upload_files/21d/9da/23b/21d9da23bdeaf8071a562f116f6f3a7a.png)
После того как я насмотрелся на кастомные темы с просторов github я решил, что мне такого ужаса точно не нужно и вернулся к истокам - стандартной зелёной теме. Победив эффект циклопа (даже 3х) я добавил переключение тем и поправил логику приложения - перезагрузка. выключение, сон и блокировка работают на ура ну и два вида условий таймера - через промежуток времени и В конкретное время. Я был полностью доволен и буквально счастлив что теперь мне не нужно каждый день идти в планировщик заданий и выставлять время выключения вручную! Но тут я увидел то, что впоследствии переведет меня из Notepad++ (да, да, именно там я и писал свой проект до этого момента) в PyCharm. Это была библиотечка pywinstyles, обещающая эффекты прозрачности как из win7 но в стиле десятки. То что нужно.
![Sample Customtkinter но с Pywinstyles Sample Customtkinter но с Pywinstyles](https://habrastorage.org/getpro/habr/upload_files/a53/817/9f1/a538179f1a562c3d09d1259ef2c36622.png)
Мне показалось это просто идеальным дополнением моей програмки. Запускаешь поверх фильма и не мешает и знаешь сколько времени осталось - красота. Но полное отсутствие документации и внятных sampl'ов заставило заново пересмотреть перспективы проекта. Я написал автору pywinstyles и с его описанием я таки смог заставить работать это всё вместе:
![Итоговые версии с pywinstyles Итоговые версии с pywinstyles](https://habrastorage.org/getpro/habr/upload_files/ce1/329/79c/ce132979c4914558fd104d1792673c67.png)
Если тут есть такие же странные люди, которые решат потрогать pywinstyles - будьте готовы к множеству проблем. К примеру после смены темы на прозрачную назад вернуть никак. Только перезапуск. У main_frame от ctk тут беловатый фон, что заставляет программу "сиять" на светлых фонах.
Выводы
Я получил то, что хотел и кучу необходимого опыта сверху. В будущем хочу реализовать автоматическую остановку таймера. В случае если фильм ставиться на паузу то и сам таймер останавливается. Как это реализовать при просмотре фильма из браузера я пока не знаю, но если у Вас есть идеи - с радостью почитаю.