Разработка кроссплатформенного менеджера виджетов рабочего стола

Интерфейс и функции виджетов, используемые в разработке программные средства. Элементы: часы, календарь, заметки, сервер. Формирование кроссплатформенного менеджера виджетов рабочего стола, обладающего интерфейсом на нескольких операционных системах.

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 06.07.2015
Размер файла 210,4 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

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

Размещено на http://www.allbest.ru/

Размещено на http://www.allbest.ru/

Выпускная квалификационная работа

Разработка кроссплатформенного менеджера виджетов рабочего стола

Введение

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

На текущий момент времени существует множество различных операционных систем (далее - ОС) для персональных компьютеров. Каждая ОС обладает своим уникальным интерфейсом, что создает неудобства для пользователя при работе пользователя с разными ОС, особенно, если на домашнем ПК он использует одну ОС, а на рабочем - другую. Многие ОС, а также программные пакеты - окружения рабочего стола содержат сервисные программы для пользователя - Виджеты. Виджет - это программа, обладающая графическим интерфейсом, предназначенная для отображения какой-либо специализированной информации, облегчая доступ пользователя к ней, и, как правило, заменяющая реальное устройство или программу программой на компьютере, но с удобным отображением данных. Наиболее известным виджетом является виджет часов (замена реальных часов), виджет заметок (замена реальных стикеров), виджет системного монитора (замена программы - системного монитора, и удобное отображение на рабочем столе ресурсов ПК).

Управление и расположение виджетами берет на себя специальная программа ОС - менеджер виджетов. Он позволяет добавлять, удалять, перемещать, виджеты, а также занимается компоновкой виджетов на экране (например, не позволяя вынести пользователю виджет за границы экрана).

Стандартизация интерфейсов ОС позволила бы значительно увеличить производительность человека при использовании компьютера, однако, это обезличило бы ОС, что не выгодно производителям коммеческих ОС.

В данной работе будет разработан кроссплатформенный менеджер виджетов рабочего стола (далее - КМВ), обладающий одинаковым интерфейсом на нескольких ОС, и 3 виджета рабочего стола: часы, заметки, календарь, обладающий функцией ежедневника.

1. Анализ

1.1 Программные средства

программный операционный интерфейс виджет

Основная сложность разработки кроссплатформенного приложения на заключается в различичных наборах команд для воспроизведения одних и тех же действий на разных ОС ввиду разных API, предоставляемых различными ОС. Поэтому, при использовании компилируемых, платформо-зависимых языков, таких как C/C++, зачастую приходится создавать уровень абстракции от API ОС, позволяющий минимизировать платформо-зависимый код. Если количество платформо-зависимого кода превышает 50%, то, по сути, разрабатывается уже несколько программ, каждая для своей ОС, что значительно увеличивает количество затрачиваемых ресурсов при разработке:

- время на разработку

- время на тестирование

- время на поддержку

- время на расширение функционала

- время на компиляцию

Положительной стороной компилируемых является:

- более высокая скорость работы при прочих равных

- более низкое потребление ресурса ОЗУ при прочих равных

Избежать этих колоссальных затрат времени позволяют языки, исполняемые на виртуальных машинах, такие как Java и Python. Исходные коды, транслируясь в байт-код, выполняются на виртуальной машине (Java Virtual Machine и Python Virtual Machine соответственно), что сводит к минимуму платформо-зависимость: если на целевой ОС есть соответствующая виртуальная машина, то результат работы будет одинаковым даже на разных ОС. Более того, многие операции выполняются в вышеприведенных языках более лаконично, нежели в языках С и С++, что позволяет значительно снизить время на разработку. Недостатком языков, исполняемых на виртуальных машинах (далее - ВМ) являются большие требования к ОЗУ (так как требуется загрузить в память не только программу, но и саму ВМ), и большее время на выполнение операций, связанны с хост-машиной (например, записыва в файл, делается вызов в программе, затем, вызов к хост-ОС из ВМ, вызов хост-ОС к хост-машине).

Язык Python обладает следующими приемуществами перед Java:

- Функции являются объектами второго рода, что позволяет сделать программу более лаконичной

- Нестрогая типизация, предоставляющая высокий уровень абстракции

- Динамичность, что позволяет сделать язык более лаконичным

- Многие функции используют C-вызовы, что ускоряет работу программы

- Python установлен «из коробки» в ОС семейства Mac OS и ОС с ядром Linux, что позволит сократить размеры stand-alone дистрибутива программы и облегчит установку для пользователя

- Является открытым и бесплатным

Ввиду нестрогой типизации, требуется больше проверок при работе, что делает эквивалентную операцию немного медленнее, чем в Java.

Для реализации графического интерфейса пользователя (далее - GUI), Python использует свою библиотеку Tinker, однако, возможности этой библиотеки не позволят реализовать некоторые особенности виджетов. Ввиду чего, для создания GUI будет использована библиотека Qt. Положительные особенности Qt:

- Написанна на С++

- Кроссплатформенность

- Широкий функционал

- Бесплатность

Для работы с Python и Qt используются так называемые «связывания» (англ. «bindings») PyQt, что позволяет использовать гибкость и динамичность Python и скорость работы Qt (C++).

Для создания изображений необходим графический редактор, способный сохранять изображения в форматах PNG и XPM. Был выбран графический редактор GIMP, удовлетворяющий всем требованиям, являющийся бесплатным, кроссплатформенным редактором.

1.2 Интерфейс и функции виджетов

КМВ не должен отвлекать пользователя во время работы, однако, должен предоставлять доступ к функциям по первому требованию. Таким образом, наилучшим решением будет отсутствие окна КМВ, но присутствие иконки в системном трее ОС, кликая мышью на котором, быдет появляться меню, обеспечивающее основные функции КМВ. Сообщения пользователю передавать через уведомления системного трея.

Функции:

- Размещение виджетов на рабочем столе (т. н. Компоновка)

- Изменение состава виджетов на рабочем столе (добавление / удаление)

- Экспорт и импорт настроек

- Предоставление пользовательского интерфейса для предоставления пользователю вышеперечисленных функций

- Сериализация/десериализация

Рисунок 1. Интерфейс КМВ

Рисунок 2. Уведомление пользователя

Для человека гораздо легче воспринимать время по стрелочным часам. Поэтому виджет часов необходимо выполнить в виде стрелочных часов. Предоставить кнопки закрытия виджета, кнопки смены часового пояса и кнопки управления будильниками.

Функции:

- Вывод текущего времени суток в графическом представлении

- Установка сигнала по времени (т. н. «будильник»)

- Изменение поправки отображаемого времени по запросу пользователя (т. н. «выбор часового пояса»)

- Предоставление пользовательского интерфейса для предоставления пользователю вышеперечисленных функций

- Сериализация/десериализация

Рисунок 3. Интерфейс часов

Интерфейс виджета заметки должен напоминать по виду липкие стикеры, создавая у пользователя необходимую ассоциацию. Предоставить текстовое поле, должны присутствовать кнопка быстрой очистки заметки и закрытия виджета.

Функции:

- хранения произвольной текстовой информации ограниченной длины (неменее 512 символов)

- Предоставление пользовательского интерфейса для предоставления пользователю вышеперечисленных функций

- сериализация / десериализация

Рисунок 4. Интерфейс заметки

Виджет календаря должен визуально соответствовать привычному пользователю календарю на месяц. Даты, на которые назначены события, должны быть выделены. Виджет должен уведомлять о предстоящих событиях, иметь кнопку добавления события, просмотра и редактирования события, кнопку закрытия виджета.

Функции:

- Вывод сетки дат текущего месяца в графическом представлении

- Изменение состава событий дат календаря (например, праздников)

- Оповещение о предстоящих событиях

- Предоставление пользовательского интерфейса для предоставления пользователю вышеперечисленных функций

- Сериализация/десериализация

Рисунок 5. Интерфейс календаря и заметка календаря

Серверная часть не ребует интерфейса.

Функции:

- Получение данных пользователя

- Проверка пользователя

- Хранение данных пользователя

- Возвращение данных по требованию

2. Проектирование

2.1 Менеджер виджетов

Перед запуском, менеджер виджетов должен проверить, на какой ОС он запущен, и, если ОС поддерживаемая - продолжить работу. Для обеспечения простого и гибкого добавления виджетов в набор виджетов, все КМВ осуществляет проверку каталога, и, в случае наличия в нем виджетов, оформленных в виде python-пакета, добавить его в список и позволить пользователю добавлять его на рабочий стол. Интерпритируемость и динамичность языка позволяет импортировать новые модули во время работы программы.

Для возможности синхронизации с сервером, необходимо работать с подсистемой сокетов. Пакет «socket» позволяет получить доступ к работе с подсистемой сокетов.

Ввиду того, что виджеты могут быть перекрыты другими окнами, необходимо добавить функцию, переносящую виджеты на самый верхний слой оконного менеджера ОС. Данный функционал позволяет осуществить библиотека Qt.

Виджеты не должны иметь представления в списке запущенных задач, путая пользователя. Библиотека Qt позволяет создавать окна, не имеющие заголовка, и не имеющие представления в списке запущенных задач.

Создание иконки в трее и передача сообщения реализуются классом библиотеки Qt.

Для взаимодействия виджетов друг с другом, КМВ должен предоставлять соответствующие методы. Блягодаря «договорной» инкапсуляции языка python, взаимодействие с виджетами будет максимальным.

Для сериализации классов python используется, как правило, модуль pickle. Однако, ввиду того, что классы будут наследниками классов библиотеки Qt, требуется создать свой метод сериализации, который позволит восстановить состояние КМВ и виджетов однозначно.

Также, необходимо верно устанавливать значение локали, предоставляя пользователям верные данные календаря.

2.2 Виджет часов

При отрисовке стрелок на часах необходимо использовать антиалиасинг, чтобы стрелки часов выглядели приятнее пользователю. Библиотека Qt позволяет использовать антиалиасинг при отрисовке виджетов.

Отрисовка должна происходить не слишком часто, чтобы не использовать слишком много ресурсов, но и не слишком редко, чтобы предоставлять актуальные данные о времени.

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

Список будильников должен отображать все будильники, которые сработают в будущем. Виджет должен предоставлять наглядный список будильников и позволять удалять / добавлять их.

Для отображения времени другого часового пояса виджет должен предоставлять возможность смены временной поправки, и, в случае отличия её от локальной, выводить на виджете смещение, относительно времени по Гринвичу.

Для удобства перемещения виджета необходимо реализовать механизм перемещения перетаскиванием.

2.3 Виджет заметки

Виджет должен поддерживать операции работы с буфером обмена. Библиотека Qt позволяет работать с буфером обмена ОС.

Для быстрого удаления данных заметки необходимо реализовать клавишу очистки.

Для удобства перемещения виджета необходимо реализовать механизм перемещения перетаскиванием.

2.4 Виджет календаря

Виджет должен позволять добавлять удобным способом даты: двойной клик на дате должен открывать диалог добавления даты с автоматически заполненными полями.

Виджет должен позволять создавать гибкие условия. Необходимость этого диктуется необычными условиями наступления специализированных праздников в календарях, например, первый понедельник какого-либо месяца.

В случаях Дней рождений, виджет должен корректно информировать о возрасте именинника. В случае знаменательных дат, если задан год, выводить количество лет, прошедших с момента наступления события в прошлом.

При выборе дня на календаре, если присутствуют события в этот день, календарь должен вывести заметку с информацией о событиях. Заметка календаря должна быть иммутабельна для пользователя, и не должна сериализовываться.

Виджет должен предоставлять удобный пользователю способ редактирования событий, предоставляя понятную информацию о условиях наступления даты, сколь сложной они бы не были.

Для удобства перемещения виджета необходимо реализовать механизм перемещения перетаскиванием.

2.5 Сервер

Серверная часть должна предоставить возможность создать каталог для хранения данных нового пользователя, сохранения данных уже существующего пользователя. Пользовательский интерфейс для серверной части не требуется.

При разработке следует учесть специфическое ограничение python: один интерпритатор - один одновременно выполняющийся на процессоре поток исполнения. Это ограничение влияет исключительно на скрипты python, поэтому не замедлит выполнение приложения, использующие сторонние библиотеки, такие, как Qt, поэтому графическое исполнение виджетов и КМВ не будет ограничено этим ограничением.

3. Разработка

3.1 Менеджер виджетов

Была выбрана следующая файловая структура менеджера виджетов, внутри корневого каталога КМВ:

- Файл исходного кода CWM.pyw. Данный файл содержит логику КМВ, описанную на языке программирования python.

- Файл data.txt. Данный файл содержит персистентные данные локального пользователя о виджетах. Иными словами, если пользователь не подключался к серверу, или подключиться не удалось, менеджер сохранит данные в этот файл.

- Файл login.txt. Данный файл содержит информацию о данных подключения к серверу.

- Файл icon.xpm. Этот файл содержит изображение иконки, отображаемой в системном трее. Файл создан при помощи редактора GIMP.

- Каталог widgets. Данный каталог сожержит пакеты виджетов.

Перед запуском менеджера проверяется ОС, на которой запускается приложение. Для этого был использован модуль platform, функция system, возвращающая имя семейства системы строковым параметром, например, «Windows».

Далее, устанавливается локаль. Если не установить локаль, то в некоторых виджетах будут не верно отображаться данные, например, в виджете календаря названия месяцев или дней недель будут на английском в случае запуска с ОС, использующим русскую локаль.

Создается объект QApplication. Этот объект - основа работы с библиотекой Qt и взаимодействия с приложением, написанным на Qt, например, выход из приложения путем вызова метода exit().

Импортируются модули из каталога widgets, содержащие классы виджетов.

Логика КМВ заложена в классе CWM, который наследует класс QWidget.

Создается экземпляр класса CWM. Конструктору передается параметр - экземпляр раннее созданного приложения QApplication для взаимодействия с приложением и корректного завершения приложения.

Для приложения задается правило setQuitOnLastWindowClosed(False), запрещающее завершать приложение, если было закрыто последнее видимое окно сзаголовком, т.к. КМВ и виджеты не имеют заголовков окон, а КМВ не имеет видимого окна, лишь только иконку в системном трее.

Вызывается метод загрузки данных CWM.load().

Запускается приложение на Qt методом exec_().

КМВ оформлен в класс ввиду того, что это облегчит использование в других проектах КМВ, если это потребуется. Для этого нужно будет создать в каталоге КМВ пустой файл __init__.py и в проекте, в котором необходимо использовать его функционал, провести импорт класса: import CWM.

Конструктор класса CWM __init__(self, parent=None, app=None) проводит инициализацию и подготовку к работе, устанавливая значения по умолчанию для пароля, логина, хоста, создает иконку системного трея и меню, составляя подменю «добавить» на основе содержимого каталога widgets, составляет окно заполнения параметров подключения к серверу и скрывает его, проводит соединение соответствующих сигналов со слотами и, в случае успешной инициализации создает сообщение в системном трее о успешном запуске.

Класс CWM обладает следующими слотами:

- ontop. Предназначен для выведения всех виджетов на верхний слой оконного менеджера. Получает сигналы в случае выбора меню «активировать» в меню системного трея КМВ, или при нажатии на иконку системного трея КМВ. Позволяет пользователю увидеть виджеты, если он скрыл их другим окном.

- addWidgetSlt. Предназначен для отлавливания нажатий пунктов подменю в меню добавления нового виджета. Вызывает метод addWidget без параметра данных виджета.

- exit. Предназначен для завершения работы с менеджером виджетов. Получает сигнал при нажатии в меню КМВ пункта «Выход». Сораняет данные на сервере / локально.

- show_connect_diag. Предназначен для отображения диалога ввода данных для подключения к серверу. Получает сигнал при нажатии пункта меню «подключиться».

Класс CWM обладает следующими методами:

- save_login. Сохраняет данные о подключении к серверу в полях класса, обновляет значения «по умолчанию» в диалоге заполняния данных о подключении. Скрывает диалог ввода данных о подключении к серверу.

- addWidget. Метод добавления виджета. Принимает параметром имя виджета и опционально данные виджета, если виджет требуется десериализовать. В случае ошибки создает сообщение в трее о неудаче с иконкой сообщения «внимание». Виджет добавляется в список виджетов CWM.

- trayMessage. Показывает сообщение в системном трее. Принимает параметром заголовок сообщения, текст сообщения и опционально тип иконки (по умолчанию используется тип «Информация»).

- getWidget. Принимает имя виджета параметром и возвращает первый виджет с таким именем в списке виджетов, если такой виджет имелся.

- serialize. Возвращает все данные, необходимые для восстановления текущего состояния КМВ и виджетов, в виде строки. Вызывает метод сериализации каждого отдельного виджета, не являющегося сервисным, разделяя строки, принадлежащие каждому отдельному виджету спец-символом с hex-кодом 4, параметры положения х, у и данные разделяются спец-символом с hex-кодом 5.

- load. Получение данных. В первую очередь, пытается подключиться к серверу, если данные о подключении указаны, затем, считывает данные из локального файла. В случае наличия данных, проводит десериализацию и добавление виджетов.

Менеджер виджетов следит за расположением виджетов, проверяя их расположение и перекрытие другими окнами. Более того, если пользователь использовал на одном из своих ПК монитор с большим разрешением, и координаты виджетов сохранились так, что, когда пользователь перешел за другой ПК, оказались за границами видимого пространства, менеджер виджетов исправит ситуацию и расположит виджеты у границы, за которую они «хотели вылезть», позволяя пользователю не заботится о расположении виджетов на разных ПК с разными мониторами. КМВ позволяет добавлять новые виджеты в коллекцию виджетов просто и быстро: благодаря динамичности языка python достаточно просто поместить новый тип виджета в каталог widgets менеджера виджетов и перезапустить КМВ. При запуске новый тип виджета будет добавлен в подменю «добавить» с соответствующим именем. КМВ выводит пользователю информацию о работе и ошибках в неназойливом и наглядном виде путем отображения сообщений системного трея. Таким образом, пользователь не будет отвлечен от работы, если ему необходимо нахождения фокуса оконного менеджера на его приложении. Файл данных менеджера виджетов можно копировать и носить с собой, если другой ПК пользователя не имеет доступа к серверу. Более того, КМВ является portable программой, что означает, что его достаточно скопировать на носитель и запускать прямо с него, не устанавливая в целевой системе.

3.2 Виджет часов

Редактором GIMP были созданы следующие изображения:

- bg.png - Фоновое изображение виджета

- cb.png - Изображение для кнопки закрытия виджета

- cfg_b.png - Изображение кнопки управления будильником

- db.png - Изображение кнопки смены часового пояса

При помощи аппаратных средств был записан звук механического стрелочного будильника и сохранен в файл analogue_alarm.wav

Виджет часов оформлен в виде класса Clock в пакете clock. Класс реализует общие для всех реализованных виджетов методы:

- exit. Метод, закрывающий виджет без сохранения данных и высвобождеющий ресурсы системы, использованные данным виджетом. Виджет удаляетя из списка виджетов КМВ, скрывается, и вызывает деструктор. Стоит заметить, что в python нет такого понятия, как «деструктор» у класса ввиду автоматической сборки мусора, однако, унаследован класс QWidget, написанный на С++ в библиотеке Qt, которая, в свою очередь, имеет тоже специальный механизм особождения памяти. Поэтому, после закрытия виджета, вызывается метод ксласса destroy(), сообщающий механизму сборки Qt о том, что ресурсы виджета можно освободить.

- mousePressEvent. Отлавливает нажатия на виджет в области, которой можно перетаскивать. Если левая клавиша мыши зажата, то флажок moveing виджета устанавливается в True, что означает, что виджет можно перетаскивать. Флажок moveing утанавливается False после того, как клавиша была отущена.

- mouseMoveEvent. При перемещении курсора мыши и зажатой левой клавишей мыши (флажок moveing установлен в True) перемещает виджет, позволяя пользователю «перетаскивать» в удобное для пользователя места на рабочем столе. Пользователю не удасться переместить виджет за видимые границы экрана.

- serialize. Метод, возвращающий данные виджета, при помощи которых можно однозначно восстановить текущее состояние виджета. Для виджета это: список будильников, смещение.

Список слотов класса:

- edit_alarms. Предназначен для отображения окна редактирования будильников. Получает сигнал от кнопки редактирования будильников.

- dt_pick_ok. Предназначен для вызова метода добавления будильника. Получает сигнал от кнопки «создать будильник» в окне редактирования будильника.

- dt_pick_del. Предназначен для удаления будильника. Получает сигнал от кнопки «удалить будильник» в окне редактирования будильника.

- change_delta. Предназначен для отображения окна выбора временного смещения отностительно UTC. Получает сигнал от кнопки редактирования верменного смещения относительно UTC.

- d_pick_ok. Предназначен для смены временного смещения относительно UTC. Получает сигнал от кнопки «задать часовой пояс» в окне редактирования смещения относительно UTC.

Методы класса:

- paintEvent. Метод, отрисовывающий стрелки на часах и, в случае отличия смещения времено от локального, надпись UTC величина_смещения.

- timerEvent. Метод, выполняющийся каждые 10 секунд для перерисовки стрелок и проверки будильников. В случае наступления времени будильников, вопроизводится звуковой сигнал и создается сервисный виджет заметки со списком сработавших будильников.

- add_alarm. Метод добавления будильника в список. В случае, если такой будильник существует, выведет пользователю сообщение, что такой будильник уже существует.

- del_alarm. Метод удаления будильника.

- refresh_al_list. В данный метод был вынесен повторяемый функционал для сокращения количества кода. Метод обновляет список существующих будильников в окне управления будильниками.

- alarm. Метод, воспроизводящий звуковой сигнал analogue_alarm.wav. Содержит платформо-зависимый код. Для воспроизведения звука использует способы библиотеки Qt, но на Linux эти методы не работают, поэтому на ОС семейства Linux использует sox для вывода звука.

Общий стиль виджета соответствует представлению человека о аналоговых часах, что облегчает восприятие времени человеком. Изменение часового пояса производится легко и быстро, а в списке выбора смещения напротив локального смещения указано в скобках, что пользователь в этом часовом поясе. Управление будильниками предельно просто: при нажатии на кнопку управления перед пользователем предстает интерфейс управления будильниками. В списке отображаются время и даты будильников (будильник можно устанавливать на любое время и дату, хоть в следующем году). Если пользователь планирует установить будильник в будущем, то, нажав на пиктограмму календаря в поле редактирования времени будильника, появится всплывающее окно календаря, на котором пользователь может выбрать необходимую дату. Заполнив время, дату (автоматически подставляется сегодня), комментарий будильника, необхожимо нажать кнопку «добавить будильник». Будильник будет добавлен и отобразится в списке, который отсортирован по близости времени будильников. Для удаления достаточно выбрать будильник в списке и нажать кнопку «удалить будильник». Все будильники, время которых находится в прошлом от текущего момента, сработают в ближайшем timerEvent, однако, сигнал будет один, чтобы за счет суммирования звуков звуковой системой ОС не перегрузить акустическую систему ПК и не повредить слух пользователя. Так же, при наступлении времени будильника создается заметка с текстом того, что будильники сработали и описанием будильников. Это оповестит пользователя даже если он отошел от ПК во время срабатывания будильника.

3.3 Виджет заметки

Редактором GIMP были созданы следующие изображения:

- bg.png - Фоновое изображение виджета

- cb.png - Изображение для кнопки закрытия виджета

- clrb.png - Изображение кнопки очистки содержимого

Виджет заметки оформлен в виде класса Note в пакете note. Класс реализует общие для всех реализованных виджетов методы:

- exit. Метод, закрывающий виджет без сохранения данных и высвобождеющий ресурсы системы, использованные данным виджетом. Виджет удаляетя из списка виджетов КМВ, скрывается, и вызывает деструктор. Стоит заметить, что в python нет такого понятия, как «деструктор» у класса ввиду автоматической сборки мусора, однако, унаследован класс QWidget, написанный на С++ в библиотеке Qt, которая, в свою очередь, имеет тоже специальный механизм особождения памяти. Поэтому, после закрытия виджета, вызывается метод ксласса destroy(), сообщающий механизму сборки Qt о том, что ресурсы виджета можно освободить.

- mousePressEvent. Отлавливает нажатия на виджет в области, которой можно перетаскивать. Если левая клавиша мыши зажата, то флажок moveing виджета устанавливается в True, что означает, что виджет можно перетаскивать. Флажок moveing утанавливается False после того, как клавиша была отущена.

- mouseMoveEvent. При перемещении курсора мыши и зажатой левой клавишей мыши (флажок moveing установлен в True) перемещает виджет, позволяя пользователю «перетаскивать» в удобное для пользователя места на рабочем столе. Пользователю не удасться переместить виджет за видимые границы экрана.

- serialize. Метод, возвращающий данные виджета, при помощи которых можно однозначно восстановить текущее состояние виджета. Для виджета это: содержание заметки.

Класс обладает следующими слотами:

- clear_note. Очищает текст заметки. Получает сигнал в случае нажатия кнопки очистки заметки.

Класс обладает следующими методами:

- set_text. Метод предназначен для сторонних виджетов для задания текста заметки. Данный метод используют виджеты календарь и часы для отображения информации.

Виджет заметки визуально оформлен в виде занкомых всем современным людям небольшими отрывными цветными листочками - стикерами. Такой дизайн создает у пользователя правильное представление о виджете: хранение и отображение небольших объемов информации и заметок. Кнопки виджета заметки выполнены в едином стиле: кнопка очистки имеет пиктограмму ластика, а кнопка закрытия - рукописного диагонального крестика. Поля ввода заметки позволяет использовать буфер обмена ОС, позволяя пользователю использовать вставку и копирование текста (клавиатурные комбинации Ctrl+C и Ctrl+V, а также комбинация «вырезать» Ctrl+X).

3.4 Виджет календаря

Редактором GIMP были созданы следующие изображения:

- bg.png - Фоновое изображение виджета

- cb.png - Изображение для кнопки закрытия виджета

- cfg_b.png - Изображение кнопки управления датами

- aeb.png - Изображение кнопки добавления события

Виджет календаря оформлен в виде класса Calendar в пакете calendar. Класс реализует общие для всех реализованных виджетов методы:

- exit. Метод, закрывающий виджет без сохранения данных и высвобождеющий ресурсы системы, использованные данным виджетом. Виджет удаляетя из списка виджетов КМВ, скрывается, и вызывает деструктор. Стоит заметить, что в python нет такого понятия, как «деструктор» у класса ввиду автоматической сборки мусора, однако, унаследован класс QWidget, написанный на С++ в библиотеке Qt, которая, в свою очередь, имеет тоже специальный механизм особождения памяти. Поэтому, после закрытия виджета, вызывается метод ксласса destroy(), сообщающий механизму сборки Qt о том, что ресурсы виджета можно освободить.

- mousePressEvent. Отлавливает нажатия на виджет в области, которой можно перетаскивать. Если левая клавиша мыши зажата, то флажок moveing виджета устанавливается в True, что означает, что виджет можно перетаскивать. Флажок moveing утанавливается False после того, как клавиша была отущена.

- mouseMoveEvent. При перемещении курсора мыши и зажатой левой клавишей мыши (флажок moveing установлен в True) перемещает виджет, позволяя пользователю «перетаскивать» в удобное для пользователя места на рабочем столе. Пользователю не удасться переместить виджет за видимые границы экрана.

- serialize. Метод, возвращающий данные виджета, при помощи которых можно однозначно восстановить текущее состояние виджета. Для виджета это: список повторяемых событий, список разовых событий.

Класс обладает следующими слотами:

- create_event. Предназначен для отображения окна добавления события. Получает сигнал от клавиши добавления события, а также при двойном нажатии на дату в календаре.

- add_event. Предназначен для проверки данных, введенных пользователем и, в случае верности заполненных полей, добавления события в соответствующих список. Получает сигнал от кнопки «добавить событие» в окне добавления события.

- del_event. Предназначен для удаления события. Получает сигнал от кнопки «удалить событие» в окне редактирования событий.

- show_help. Предназначен для отображения окна справочной информации о составлении событий. Получает сигнал от кнопки «справка» в окне добавления события.

- configure. Предназначен для отображения окна управления событиями. Получает сигнал от кнопки конфигурации.

Класс обладает следующими методами:

- timerEvent. Метод запускает сообщение первоначального запуска календаря и отключает таймер. Использование задержки было обусловлено тем, что сообщение первоначального запуска календаря отображается в заметке, появляющейся рядом с виджетом календаря, однако, координаты виджета при первоначальной отрисовке не инициализировались и заметка располагалась в центре экрана.

- on_activate. Метод, вызываемый при двойном нажатии на дате в календаре. Автоматически заполняет год, месяц, день месяца значениями сегодняшнего дня, устанавливает тип события в «событие» и отображает окно добавления события. Этот метод обеспечивает быстрое и удобное добавление события в календарь.

- update_events. Метод, обновляющий отображение событий в календаре. Осуществляет обход собыйтий в списках повторяющихся событий и разовых событий, получая их даты на промежутке от сегодня-30 дней до сегодня+366 дней, заполняет список дат с описаниями событий и выделяет в календаре даты путем изменения параметра шрифта на «жирный подчеркнутый».

- near_events_text. Метод, возвращающий текст о предстоящих событиях. Этот текст используется в первоначальном сообщении календаря, в специальной заметке. Если ближайших событий нет, то возвращает «на ближайшие дни событий нет».

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

- refresh_ev_list. Метод, содержащий повторяющийся функционал. Вызывается для обновления списка событий в окне редактирования событий.

Также, для осуществления функционала календаря, а также для задания особых условий дат, в пакете Calendar был создан класс события - Event. Данный класс содержит данные о условиях наступления событий и содержит следующие методы:

- match. Метод, возвращающий True, если дата, переданная параметром в этот метод, соответствует условиям наступления события.

- get_dates. Метод, возвращающий список кортежей даты и описания события для текущего события на промежутке времени, переданного в параметрах. Иными словами, метод возвращает все даты, когда наступит событие, на промежутке, переданному в параметры методу. Список дат возвращается потому, что некоторые события могут содержать особые условия, например «третий понедельник», который, соответственно, есть в каждом месяце каждого года, и, таким образом, метод, при параметрах (сегодня - 30, сегодня + 366) вернет 13 дат.

- __eq__. Перегружаемый метод класса Object, возвращает True, если события эквивалентны.

- __ne__. Перегружаемый метод класса Object, возвразает not __eq__

- __str__. Перегружаемый метод класса Object, возвращает строковое представление события. Перегрузка метода была необходима для наглядного отображения события и его условий наступления в списке событий окна редактирования событий.

Виджет календаря оформлен визуально в виде привычного большинству пользователей перекидного календаря. Виджет выполняет функции календаря и программы, уведомляющей о событиях, которые были добавлены пользователем. Окно добавления события предоставляет пользователю широкий выбор условий для создания события, вместе с тем, оставляя простым добавления события: для добавления дня рождения достаточно выбрать тип события «день рождения», заполнить поля года, месяца (числом), дня месяца, описание события и нажать клавишу «добавить»! Обозначенная дата сразу будет отмечена в календаре, а при клике на ней, будет выведена заметка с описанием и количеством лет, исполняющихся имениннику. Для предоставления информации о заполнении полей событий создана справочная информация, окно с которой вызывается путем нажатия клавиши «справка» в окне создания события. При запуске, календарь уведомляет пользователя о предстоящих событиях, позволяя ему быть в курсе предстоящий событий. Удобное добавление события по двойному клику на дате значительно увеличивает скорость добавления события, повышая удобство работы с виджетом. Выделение дат с событиями подчеркнутым жирным шрифтом позволяет информировать пользователя о событиях, но при этом не перегружать интерфейс цветовыми маркерами дней. Кнопка управления событиями позволяет быстро просмотреть списки событий и удалить ненужные события.

3.5 Сервер

Серверная часть легкореализуема и полностью кросс-платформенна ввиду того, что использует только стандартную библиотеку python. Сервер выдает сервисные сообщения в консоль, в которой был запущен. По умолчанию, сервер работает на порту 33333, однако, ввиду интерпритируемости языка python, порт может быть быстро сменен (для избежания конфликтов системы). Поток сервера содержит основной цикл исполнения, называемый mainloop. В этом цикле сервер извлекает соединение из очереди на сокете, получает данные, разбивает данные на код, логин, пароль, данные.

На сервере организована автомитическая регистрация: если такого пользователя не существовало, то сервер создает каталог пользователя и записывает его пароль. Если такой пользователь существовал, то сервер вернет сообщение о неверном пароле. Ввиду python-ограничений на один исполняемый на процессоре поток, не велось распараллеливание потоков обработки подключений на сервере - для этого рекомендуется использовать серверы-балансировщики, запускать несколько инстансов сервера на разных портах, а балансировщиками перенаправлять на соответствующие порты.

Заключение

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

Также, был более глубоко изучен язык Python, библиотека Qt и связки языка Python с библиотекой Qt PyQt. Были изучены тонкости работы языка python при использовании библиотеки Qt, закреплены уже известные знания по работе с данными технологиями, особенности кросс-платформенной разработки приложения. Был получен колоссальный опыт в построении пользовательских интерфейсов - UI и работы с пользователями, тестирующими приложение на добровольной основе. Гибкость языка Python и скорость работы и компактность Qt позволили созать приложение суммарым размером в 1.37МиБ с учетом изображений и аудиофайлов, а при работе, несмотря на ресурсоемкость Python, потребляющим всего 19МиБ ОЗУ при трех запущенных виджетах (часы, календарь, заметка), и потребляющим менее 1% ресурсов CPU.

Список использованных источников

1. Python: Python v3.2.5 documentation. URL: https://docs.python.org/3.2/index.html (дата обращения 3.06.2014)

2. PyQt: PyQt Class Reference. URL: http://pyqt.sourceforge.net/Docs/PyQt4/classes.html (дата обращения 5.06.2014)

3. Qt: Qt4.8 documentation. URL: http://qt-project.org/doc/qt-4.8/ (дата обращения 5.06.2014)

Приложение

Код программы

CWM.pyw

import sys

import os

from PyQt4 import QtGui

from PyQt4 import QtCore

from platform import system

import locale

class CWM (QtGui.QWidget):

«» «CWM»"»

def __init__(self, parent=None, app=None):

«» «Инициализация»"»

QtGui.QWidget.__init__(self, parent)

self.app = app

self.name = 'CWM'

self.widget_list = []

self.login = ''

self.password = ''

self.host = '192.168.0.1'

self.max_size = QtGui.QDesktopWidget().availableGeometry().size()

self.tray_icon = QtGui.QSystemTrayIcon (QtGui.QIcon («icon.xpm»))

self.tray_menu = QtGui.QMenu()

self.add_wgt_menu = QtGui.QMenu('Добавить')

for w in filter (lambda x: not x.startswith ('__'), os.listdir («widgets»)):

act = QtGui.QAction (w.capitalize(), self)

act.setStatusTip («Виджет % s»% w)

QtCore.QObject.connect (act, QtCore.SIGNAL («triggered()»), self, QtCore.SLOT («addWidgetSlt()»))

self.add_wgt_menu.addAction(act)

self.tray_menu.addMenu (self.add_wgt_menu)

act = QtGui.QAction («Активировать», self)

act.setStatusTip («Список»)

QtCore.QObject.connect (act, QtCore.SIGNAL («triggered()»), self, QtCore.SLOT («ontop()»))

self.tray_menu.addAction(act)

act = QtGui.QAction («Залогинится», self)

act.setStatusTip («Указать логин, пароль, хост»)

QtCore.QObject.connect (act, QtCore.SIGNAL («triggered()»), self, QtCore.SLOT («show_connect_diag()»))

self.tray_menu.addAction(act)

act = QtGui.QAction («Выход», self)

act.setStatusTip («Завершить работу приложения»)

QtCore.QObject.connect (act, QtCore.SIGNAL («triggered()»), self, QtCore.SLOT («exit()»))

self.tray_menu.addAction(act)

self.tray_icon.setContextMenu (self.tray_menu)

QtCore.QObject.connect (self.tray_icon, QtCore.SIGNAL («activated(QSystemTrayIcon: ActivationReason)»), self, QtCore.SLOT («ontop()»))

self.tray_icon.show()

self.setToolTip ('Менеджер виджетов')

self.trayMessage ('Привет!', 'Виджет менеджер успешно запущен;)')

# диалог задания логина

self.connect_diag = QtGui.QWidget()

self.connect_diag.setWindowTitle('Логин')

self.connect_diag.setLayout (QtGui.QVBoxLayout())

layout = QtGui.QHBoxLayout()

layout.addWidget (QtGui.QLabel('Хост'))

layout.addSpacing(15)

self.cd_host = QtGui.QLineEdit()

if self.host:

self.cd_host.setText (self.host)

layout.addWidget (self.cd_host)

self.connect_diag.layout().addLayout(layout)

layout = QtGui.QHBoxLayout()

layout.addWidget (QtGui.QLabel('Логин'))

layout.addSpacing(7)

self.cd_login = QtGui.QLineEdit()

if self.login:

self.cd_login.setText (self.login)

layout.addWidget (self.cd_login)

self.connect_diag.layout().addLayout(layout)

layout = QtGui.QHBoxLayout()

layout.addWidget (QtGui.QLabel('Пароль'))

self.cd_password = QtGui.QLineEdit()

if self.password:

self.cd_password.setText (self.password)

layout.addWidget (self.cd_password)

self.connect_diag.layout().addLayout(layout)

btn = QtGui.QPushButton('Сохранить')

self.connect_diag.layout().addWidget(btn)

QtCore.QObject.connect (btn, QtCore.SIGNAL («clicked()»), self.save_login)

def save_login(self):

self.login = self.cd_login.text()

self.password = self.cd_password.text()

self.host = self.cd_host.text()

self.connect_diag.hide()

@QtCore.pyqtSlot()

def ontop(self):

self.activateWindow()

@QtCore.pyqtSlot()

def addWidgetSlt(self):

self.addWidget (QtCore.QObject.sender(self).text())

@QtCore.pyqtSlot()

def exit(self):

if len (self.widget_list):

with open ('data.txt', 'w') as f:

f.write (self.serialize())

f.flush()

app.exit()

def addWidget (self, widget_name, widget_data=None):

«»«Виджет будет добавлен, если его пакет находится

в каталоге widgets, имя пакета строчными буквами,

имя класса - с прописной буквы строчными:

пример: находится в каталоге widgets/clock,

имя виджета Clock»"»

try:

constr = eval (widget_name.capitalize())

wgt = constr (self, data=widget_data)

self.widget_list.append(wgt)

return wgt

except Exception as e:

self.trayMessage ('Ошибка', 'Ошибка добавления виджета ' + widget_name,

QtGui.QSystemTrayIcon. Warning)

print(e)

def trayMessage (self, title, text, icon=QtGui.QSystemTrayIcon. Information):

self.tray_icon.showMessage (title, text, icon)

def getWidget (self, widget_name):

«»«Возвращает первый в списке запущенный виджет с

именем типа виджета widget_name»"»

for w in self.widget_list:

if w.name == widget_name:

return w

def serialize(self):

«»«Сериализация. Ввиду того, что это PyQt,

стандартные методы не подходят

(c object'ты не сериализуются)""»

with open ('login.txt', 'w') as lf:

lf.write (self.host + '\n')

lf.write (self.login + '\n')

lf.write (self.password + '\n')

return '\x04'.join(['\x05'.join([repr (s.x()), repr (s.y()), s.serialize()]) for s in filter (lambda x: not x.minion, self.widget_list)])

@QtCore.pyqtSlot()

def show_connect_diag(self):

self.connect_diag.show()

def load(self):

«» «Десериализация. Считывание файла-конфига»"»

try:

with open ('login.txt') as lf:

self.host = lf.readline()

self.login = lf.readline()

self.password = lf.readline()

if self.host:

self.cd_host.setText (self.host)

if self.login:

self.cd_login.setText (self.login)

if self.password:

self.cd_password.setText (self.password)

with open ('data.txt') as f:

wgt_datas = f.read().split ('\x04')

for wgt_data in wgt_datas:

wx, wy, wgt_data = wgt_data.split ('\x05')

wgt_name = wgt_data.split ('\x03') [0]

wgt = self.addWidget (wgt_name, wgt_data)

wx = eval(wx)

wy = eval(wy)

# проверим, не находится ли виджет за границами экрана

if wx < 0:

wx = 0

if wx > (self.max_size.width() - wgt.width()):

wx = self.max_size.width() - wgt.width()

if wy < 0:

wy = 0

if wy > (self.max_size.height() - wgt.height()):

wy = self.max_size.height() - wgt.height()

wgt.move (wx, wy)

except Exception as e:

print(e)

if __name__ == '__main__':

oslist = ['Windows', 'Linux']

if system() not in oslist:

machine = -1

print («CWM не будет работать на неизвестной ему ОС\n»

«Проверьте переменные окружения, где указано имя ОС,\n»

«если вы их изменяли.\n»

«Поддерживаемые ОС:» + ', '.join(oslist))

exit(1)

locale.setlocale (locale.LC_ALL, «)

app = QtGui.QApplication (sys.argv)

app.setQuitOnLastWindowClosed(False)

# импорт всех пакетов, что находятся в widgets

for widget in filter (lambda x: not x.startswith ('__'), os.listdir («widgets»)):

exec («from widgets.%s import *"% widget)

cwm = CWM (app=app) # создаем экземпляр менеджера виджетов

cwm.load()

sys.exit (app.exec_())

widgets/clock/__init__.py

«»»

Виджет часов

«»»

from PyQt4 import QtCore, QtGui

import datetime

from math import cos, sin, pi

from platform import system

class Clock (QtGui.QWidget):

«» «Часы»"»

def __init__(self, parent, data=None):

«» «Инициализация»"»

QtGui.QWidget.__init__(self, parent)

self.name = 'Clock'

self.wm = parent

# если пришли данные - восстановим

if data:

data = data.split ('\x03')

self.show_notific = eval (data[1])

self.show_tray_notific = eval (data[2])

self.alarms = eval (data[3])

self.delta = eval (data[4])

else:

self.alarms = {}

self.show_notific = True

self.show_tray_notific = True

self.delta = datetime.datetime.now() - datetime.datetime.now().utcnow()

self.ldelta = datetime.datetime.now() - datetime.datetime.now().utcnow()

self.grabpoint = None

self.moveing = None

self.minion = False

# Управление будильниками

self.dt_picker_wdg = QtGui.QWidget()

self.dt_picker_wdg.setWindowTitle ('Управление будильником')

self.dt_picker_wdg.resize (400, 500)

self.dt_picker_wdg.setLayout (QtGui.QVBoxLayout())

self.al_list = QtGui.QListView()

self.al_model = QtGui.QStandardItemModel (self.al_list)

self.al_list.setModel (self.al_model)

self.dt_picker_wdg.layout().addWidget (self.al_list)

clndr = QtGui.QCalendarWidget()

clndr.setVerticalHeaderFormat (QtGui.QCalendarWidget. NoVerticalHeader)

clndr.setFirstDayOfWeek (QtCore. Qt. Monday)

self.dt_edit = QtGui.QDateTimeEdit()

self.dt_edit.setCalendarPopup(True)

self.dt_edit.setCalendarWidget(clndr)

self.dt_picker_wdg.layout().addWidget (self.dt_edit)

self.cmnt_edit = QtGui.QLineEdit()

self.cmnt_edit.setText ('Введите коментарий')

self.dt_picker_wdg.layout().addWidget (self.cmnt_edit)

dt_pkr_wgt_ok = QtGui.QPushButton()

dt_pkr_wgt_ok.setText ('Создать будильник')

self.dt_picker_wdg.layout().addWidget (dt_pkr_wgt_ok)

QtCore.QObject.connect (dt_pkr_wgt_ok, QtCore.SIGNAL («clicked()»), self, QtCore.SLOT ('dt_pick_ok()'))

dt_pkr_wgt_del = QtGui.QPushButton()

dt_pkr_wgt_del.setText ('Удалить будильник')

self.dt_picker_wdg.layout().addWidget (dt_pkr_wgt_del)

QtCore.QObject.connect (dt_pkr_wgt_del, QtCore.SIGNAL («clicked()»), self, QtCore.SLOT ('dt_pick_del()'))

# Выбор часового пояса

self.d_picker_wdg = QtGui.QWidget()

self.d_picker_wdg.setWindowTitle ('Выберите часовой пояс')

self.d_picker_wdg.resize (200, 40)

self.d_picker_wdg.setLayout (QtGui.QVBoxLayout())

self.d_edit = QtGui.QComboBox()

for i in range (14, -14, -1):

self.d_edit.addItem ('UTC % s % d % s'% ('+' if i >= 0 else «, i, '(Локальное)' if (self.ldelta.seconds // 3600 == i) else «), i)

self.d_picker_wdg.layout().addWidget (self.d_edit)

d_pkr_wgt_ok = QtGui.QPushButton()

d_pkr_wgt_ok.setText ('Задать пояс')

self.d_picker_wdg.layout().addWidget (d_pkr_wgt_ok)

QtCore.QObject.connect (d_pkr_wgt_ok, QtCore.SIGNAL («clicked()»), self, QtCore.SLOT ('d_pick_ok()'))

self.alarmsnd_path = «widgets/clock/analogue_alarm.wav»

if system() == 'Windows':

self.alarmsnd = QtGui.QSound (self.alarmsnd_path)

self.hpen = QtGui.QPen (QtGui.QColor (30, 30, 30, 255), 6,

QtCore. Qt. SolidLine, QtCore. Qt. RoundCap,

QtCore. Qt. RoundJoin)

self.mpen = QtGui.QPen (QtGui.QColor (50, 50, 50, 255), 4,

QtCore. Qt. SolidLine, QtCore. Qt. RoundCap,

QtCore. Qt. RoundJoin)

self.setWindowFlags (QtCore. Qt. Window | QtCore. Qt. FramelessWindowHint)

self.setWindowTitle («Clock widget»)

self.resize (240, 240)

self.bg = QtGui.QPixmap («widgets/clock/bg.png»)

pal = self.palette()

pal.setBrush (QtGui.QPalette. Normal, QtGui.QPalette. Window, QtGui.QBrush (self.bg))

pal.setBrush (QtGui.QPalette. Inactive, QtGui.QPalette. Window, QtGui.QBrush (self.bg))

self.setPalette(pal)

self.setMask (self.bg.mask())

self.cb = QtGui.QPushButton(self)

self.cb.resize (20, 20)

self.cb.setIcon (QtGui.QIcon (QtGui.QPixmap («widgets/clock/cb.png»)))

self.cb.move (200, 00)

self.cfg_b = QtGui.QPushButton(self)

self.cfg_b.resize (20, 20)

self.cfg_b.setIcon (QtGui.QIcon (QtGui.QPixmap («widgets/clock/cfg_b.png»)))

self.cfg_b.move (200, 20)

self.db = QtGui.QPushButton(self)

self.db.resize (20, 20)

self.db.setIcon (QtGui.QIcon (QtGui.QPixmap («widgets/clock/db.png»)))

self.db.move (180, 00)

QtCore.QObject.connect (self.cfg_b, QtCore.SIGNAL («clicked()»), self, QtCore.SLOT ('edit_alarms()'))

QtCore.QObject.connect (self.db, QtCore.SIGNAL («clicked()»), self, QtCore.SLOT ('change_delta()'))

QtCore.QObject.connect (self.cb, QtCore.SIGNAL («clicked()»), self, QtCore.SLOT («exit()»))

self.show()

self.startTimer(10000)

def paintEvent (self, event):

«» «Отрисовка стрелок»"»

dnow = datetime.datetime.now()

time = dnow.utcnow() + self.delta

hhangle = - (time.hour + time.minute/60)*pi/6 + pi/2

mhangle = - (time.minute + time.second/60)*pi/30 + pi/2

painter = QtGui.QPainter()

painter.begin(self)

painter.setRenderHint (QtGui.QPainter. Antialiasing, True)

painter.setPen (self.hpen)

if time!= dnow:

painter.drawText (93, 160, «UTC % s % d»% («+» if self.delta.seconds >= 0 else «, self.delta.seconds // 3600))

painter.drawLine (110 - cos(hhangle)*5, 110 + sin(hhangle)*5, 110 + cos(hhangle)*45, 110 - sin(hhangle)*45)

painter.setPen (self.mpen)

painter.drawLine (110 - cos(mhangle)*6, 110 + sin(mhangle)*6, 110 + cos(mhangle)*60, 110 - sin(mhangle)*60)

painter.end()

def timerEvent (self, *args, **kwargs):

self.update()

t = datetime.datetime.today()

alarms = []

for comm, dt in self.alarms.items():

if t >= dt:

alarms.append(comm)

for comm in alarms:

self.alarms.pop(comm)

if len(alarms):

text = «Будильник % s <b>%s</b> сработал % s!'% ('и» if len(alarms) > 1 else «, ', '.join(alarms), 'и' if len(alarms) > 1 else «)

if self.show_notific:

wgt = self.wm.addWidget ('Note', '\x03'.join([repr('Note'), repr(text)]))

wgt.activateWindow()

if self.show_tray_notific:

self.wm.trayMessage ('Внимание!', text.replace ('<b>', '\'').replace ('</b>', '\''))

self.alarm()

self.del_alarm(comm)

@QtCore.pyqtSlot()

def edit_alarms(self):


Подобные документы

  • Программа смены обоев рабочего стола, принцип ее работы. Основные виды обоев для рабочего стола. Существующие программы и их преимущества. Разработка приложения для смены обоев рабочего стола с использованием функций программы Delphi 7, листинг программы.

    контрольная работа [3,8 M], добавлен 17.11.2012

  • Аппаратные и программные средства для разработки веб-сайта. Ознакомление с характеристиками мобильных устройств фирмы Nexus. Установка логотипа сайта. Создание главной страницы. Активация слайдера и панели виджетов. Конфигурирование настроек слайдера.

    дипломная работа [11,2 M], добавлен 10.10.2016

  • Элементы рабочего стола. Общие приемы работы с окнами. Главное и контекстное меню. Создание и переименование папок. Удаление и восстановление информации. Копирование информации на съемные носители. Настройка Рабочего стола. Настройка панели задач.

    учебное пособие [346,4 K], добавлен 20.08.2010

  • Анализ видов существующих корпоративных порталов. Разработка архитектуры и структуры корпоративного портала в соответствии с требованиями. Установка и настройка программного обеспечения. Общие настройки портала, управление меню и настройка виджетов.

    дипломная работа [4,8 M], добавлен 19.01.2017

  • Реализация шаблона проектирования c основными принципами GUI. Обзор простых Swing-виджетов. Первая программа и добавление кнопки. Диспетчер компоновки Layout Manager. Установка размера компонента. Создание объекта Swinq в потоке обработки событий и меню.

    презентация [491,3 K], добавлен 26.10.2013

  • Проектирование структур данных и пользовательского интерфейса. Разработка руководства системного программиста и пользователя. Основные элементы организации работы менеджера по работе с клиентами. Характеристика программного обеспечения ООО "Доминион+".

    курсовая работа [1,7 M], добавлен 14.10.2012

  • Стандартные компоненты Windows XP. Главное меню, панель задач, оформление рабочего стола и значки рабочего стола. Требования к минимальной конфигурации, необходимой для установки Windows XP на платформе Intel. Удаленный доступ к рабочему столу.

    курсовая работа [1,1 M], добавлен 14.01.2015

  • D-Series как система автоматизации телевещательного процесса, используемая современными телестудиями. Портирование компонентов системы для работы на операционных системах Windows. Проверка корректного подключения плагинов и ручного режима воспроизведения.

    дипломная работа [2,3 M], добавлен 21.09.2016

  • Разработка и реализация автоматизированного рабочего места для менеджера по продажам компьютерной техники. Требования к функциональным характеристика программного изделия. Стадии и этапы разработки. Эксплуатационная документация, руководство оператора.

    курсовая работа [686,9 K], добавлен 19.05.2014

  • Определение общих требований к организации автоматизированного рабочего места. Создание модели автоматизированного рабочего места менеджера фирмы "Информстиль". Разработка базы данных и описание алгоритма программы по учету продаж вычислительной техники.

    дипломная работа [2,9 M], добавлен 03.07.2015

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.