Харківський патентно-комп'ютерний коледж Відділення «Розробка програмного забезпечення»
Предметно-циклова комісія «Програмування»
Дипломний проект
молодшого спеціаліста
на тему «Кросплатформовий клієнт-серверний додаток для видаленого моніторингу та управління персональним комп’ютером — TDM»
Виконав студент IV курсу групи П-11
спеціальності 5.5 010 301
«Розробка програмного забезпечення»
напряму підготовки 50 103
" Програмна інженерія" Супрун А.Ю.
Керівник Луценко С.С.
Харків — 2015 року
Реферат
Дипломна робота складається __ сторінок, __ рисунків, __ діаграм та __ додатків.
Об'єкт дослідження — «Кросплатформовий клієнт-серверний додаток для видаленого моніторингу та управління персональним комп’ютером — TDM» .
Мета роботи — проаналізувати специфіку діяльності систем віддлаленого моніторингу та управління комп’ютером та розробити таку систему.
У технічному завданні визначені вимоги до дипломного проекту, до надійності. Вказано призначення розробки, необхідні функціональні характеристики та вимоги до вхідних та вихідних даних. Визначені необхідні умови експлуатації, параметри технічних засобів. Описані етапи розробки програмноro продукту, порядок контролю та приймання.
У першому розділі пояснювальної записки проаналізовано існуючі технології розробки систем моніторингу і управління та різноманітність мов програмування. Також було обгрунтовано вибір технології та мов програмування для розробки.
У другому розділі пояснювальної записки спроектовано структуру додатку, розроблено базу даних. Також було розроблено UML-діаграми та алгоритм виконання функцій додатку.
У третьому розділі пояснювальної записки розраховано економічну ефективність використання системи. У четвертому розділі пояснювальної записки розглянуто питання охорони праці та техніки безпеки. У програмі та методиці тестування наведено результати тестування програмного продукту.
У керівництві оператора представлено опис виконання програми та повідомлення оператору.
Ключові слова: СИСТЕМА УПРАВЛІННЯ ТА МОНІТОРИНГУ, АВТОМАТИЗОВАНА СИСТЕМА, ВІДДАЛЕНЕ КЕРУВАННЯ.
Зміст
- Технічне завдання
- Вступ
- 1. Теоретичний розділ
- 1.1 Аналіз предметної області
- 1.2 Аналіз технології та мов програмування
- 1.3 Обґрунтування вибору технологій та мов програмування
- 2. Проектний розділ
- 2.1 Розробка структури додатку
- 2.2 Робота с XML, JSON та WebSocket
- 2.3 Алгоритм функціонування
- 3. Охорона праці
- 3.1 Загальні питання охорони праці
- 3.2 Гігієна праці та виробнича санітарія
- 3.3 Організація робочого простору
- 3.4 Електробезпека в приміщеннях з ЕОМ
- 3.5 Пожежна безпека
- Висновки
- Додатки
- Перелік посилань
Вступ
Бурхливий розвиток інформаційних технологій і вдосконалення комп’ютерної техніки призвели до глобальної інтеграції їх в усі сфери людської діяльності. Не є винятком і сфера віддаленного моніторингу та управління комп’ютером.
Моніторинг — це процес систематичного або безперервного збору інформації про параметри складного об'єкта або процесу для визначення тенденцій зміни параметрів. Цінність інформації визначається її достовірністю та оперативністю, з якою можливо отримати доступ до неї та провести необхідний аналіз даних. Актуальність і необхідність моніторингу зумовлена економічною доцільністю.
Своєчасне виявлення відхилення від норми показників дозволяє проводити профілактичні заходи, що в рази дешевше за відновлення працездатності системи після її відмови. Окрім цього, завчасне виявлення неполадок дозволяє мінімізувати час простою виробничого процесу, що також суттєво позначається на економічній ефективності підприємства.
Отже, моніторинг технічних об'єктів є надзвичайно важливою і необхідною частиною сучасного процесу ефективного виробництва. Очевидно, що сучасна система моніторингу має бути універсальною і легко пристосовуватись до різних умов роботи і працювати з широким рядом вимірювальних параметрів, швидко монтуватись і за необхідності модернізуватись і розширюватись.
Щоб задовольнити наведені вимоги і не бути територіально прив’язаним до об'єкту контролю створюються системи віддаленого моніторингу, в яких датчики, що отримують первинну інформацію, знаходяться безпосередньо на об'єктах, стан яких контролюється, а робоче місце і оператор може знаходитись в іншому місці.
Необхідність моніторингу продиктована сучасними умовами ринку. З кожним днем виробничі і інші системи, що використовуються, стають складнішими. Кількість зв’язків в системах збільшується за експоненціальним законом. Зростає кількість і вірогідність виникнення збоїв, неправильної роботи устаткування, похибок у алгоритмах опрацювання різних ситуацій і просто вихід з ладу, що характеризується відхиленням інформативних показників від норми.
Переваги віддаленого моніторингу об'єктів через Internet:
керуюча система не прив’язана просторово до виконавчих пристроїв і датчиків, внаслідок чого з’являється можливість створення розподіленої системи моніторингу;
у більшості випадків відсутня необхідність прокладки додаткової кабельної мережі для зв’язку компонентів системи.
Донедавна єдиним можливим способом підключення електронних пристроїв до мережі Internet було використання спеціального комп’ютера (gateway computer), що займається трансляцією даних з Internet у внутрішню мережу керуючої системи відповідно до певного протоколу, а також, можливо, реалізує в собі частина функцій контролера.
Але на сьогоднішній день, у зв’язку з значним розвитком і великою популярністю мікроконтролерної техніки, стало можливим створення систем віддаленого керування й моніторингу без використання спеціальних комп’ютерів.
клієнт серверний кросплатформований моніторинг
1. Теоретичний розділ
1.1 Аналіз предметної області
Система віддаленого моніторингу являє собою спеціалізований додаток, що призначений для нагляду за комп’ютером та його керуванням, коли користувач знаходиться на деякій відстані від нього.
Така система призначена для визначення працездатності комп’ютера та виправлення проблем, якщо вони з’являються, без необхідності мати фізичний доступ до машини.
Характерними рисами популярних систем моніторингу є те, що вони дозволяють проглядати дані про комп’ютер у зручній адаптованій формі. Це дозволяє використовувати подібні програми не тільки спеціалістам, а й будь-якій людини. Ця система також має можливість виконувати будь-які команди на стороні серверу, завдяки чому управління віддаленим комп’ютером становиться дуже простою справою.
Усі сучасні аналоги не схожі на «кросплатформовий клієнт-серверний додаток для віддаленого моніторингу та управління персональним комп’ютером — TDM», тому що зазвичай дають доступ до командної строки серверу або до його робочого столу. TDM дозволяє моніторити та керувати завдяки спеціального файлу-шаблону, який адаптується до зручної для людини форми, що дозволяє користуватися додатком будь-кому.
Аналогів такої програми знайдено не було. Ця система віддаленого моніторингу використовує значно менше системних ресурсів, ніж схожі додатки, тому що їй не потрібно давати доступ до робочого столу комп’ютера.
Звичайно, така система має свої недоліки:
у непередбачених випадках оператор не зможе виправити проблему, використовуючи цей додаток;
систему можна використовувати виключно на комп’ютерах, що використовують операційну систему GNU/Linux.
Основними вимогами, які ставляться користувачами до систем моніторингу є:
зрозумілий інтерфейс та зручна система навігації;
надійність та неможливість керування сервером третіми особами;
можливість кастомізувати інтерфейс.
Системи віддаленого моніторингу стали дуже важливими з розвитком інформаційних технологій. Ця тема є дуже актуальною на даний момент, тому що віддалений моніторинг та управління дозволяють будь-якому користувачу наглядати за сервером без фізичного доступу та допомоги системного адміністратору.
1.2 Аналіз технології та мов програмування
Програмування поступово впроваджується в усі сфери нашого життя. Хоча більшість сучасних мов програмування схожі між собою, спроби вивчити їх всі одночасно так чи інакше закінчуються провалом. Цілком закономірно, що з часом із загальної маси починають виділятися найбільш продумані та ефективні мови, що дозволяють одночасно вирішувати найбільшу кількість актуальних завдань. Сьогодні цими мовами можна вважати JAVA, C# і С++. Швидше за все коли-небудь на їх зміну прийде щось ще більш універсальне, але зараз саме ці мови можна називати основою сучасного програмування.
Для свого проекту я обрав саме мову C++. Вона має ряд переваг, які потрібні для написання додатку. Ось перелік цих переваг:
програми, що написані на мові С++, є кросплатформенними, що дозволяє компілювати додатки як під операційну систему Windows, так і для GNU/Linux, Android та багато інших;
мова С++ є найбільш низькорівневою, виключаючи мову Assebmler та С. Завдяки цьому від додатків, написаних з використанням цієї мови, можна домогтися найбільшої швидкодії;
велика аудиторія користувачів дозволяє швидко отримати поміч чи консультацію у мережі Інтернет, що в багато разів спрощує розробку.
Мова Java має свої переваги, але і недоліки, через які я не став використовувати її для розробки. Ось вони:
висока ресурсоємкість. Так як сервер моего додатку в більшості випадків буде знаходитися на видалених серверах, він повинен використовувати якнайменше ресурсів комп’ютера;
так як код на мові Java компілюється не у машинні коди, а у байт-код, а потім виконується у віртуальній машині, швидкодія програм залишає бажати кращого.
Як і Java, мова С# також має схожі недоліки:
ресурсоємкість додатків на цій мові також дуже сильно програє програмам на С++, що було моїм основним критерієм вибору мови програмування.
додатки на C# не кросплатформенні, тобто їх можна запустити тільки на операційній системі Windows. Мій додаток повинен запускатися також на операційних системах GNU/Linux та Android. Через це розробка додатку з використанням цієї мови стала неможливою.
1.3 Обґрунтування вибору технологій та мов програмування
При написанні дипломного проекту був використаний фреймворк Qt.
Qt — це кросс-платформенна бібліотека C++ класів для створення графічних призначених для користувача інтерфейсів (GUI) від фірми Digia. Ця бібліотека повністю об'єктно-орієнтована, що забезпечує легке розширення можливостей і створення нових компонентів. Вона підтримує величезну кількість платформ, таких як Windows 95/98/NT/2000, Linux, Sun Solaris, HP-UX, Digital Unix, IBM AIX, SGI IRIX, Android, Mac OS X, iOS і багато інших. З моменту першої появи комерційної версії Qt у 1996 році з’явилося декілька сотень відомих по всьому світу застосувань. Найвідомішою розробкою на базі Qt являється десктоп менеджер для X Windows що називається, як вже багато хто здогадався KDE.
Для бібліотеки створення GUI об'єктно-орієнтована мова є єдино придатним засобом, а стандартна об'єктна модель C++ забезпечує ефективну і швидку розробку програм, нарощування необмежених можливостей і швидку модернізацію. Природно через це в якості базової мови для бібліотеки вибраний C++. Але на додаток до можливостей самої мови у бібліотеці Qt додані декілька хороших можливостей:
потужний механізм комунікації між об'єктами за допомогою сигналів і слотів;
механізм створення властивостей об'єктів, які не підтримує комплятор C++;
підтримку подій і фільтрів подій;
переклад рядків для підтримки інтернаціоналізації;
підтримку внутрішніх таймерів, які дозволяють інтегрувати багато завдань для подієвих GUI;
ієрархічні дерева об'єктів, що є свого роду генеалогічними деревами: «прадідусь — дідусь — татко — синок», призначене для організації внутрішньої взаємодії в «натуральному» виді;
" покажчики, що охороняються", які автоматично встановлюються в NULL при видаленні об'єкту, на який веде посилання.
Усі ці можливості реалізовані у вигляді спеціальних класів C++. Поява нових сучасних вимог до призначених для користувача інтерфейсів спричиняє за собою і поява нових нестандартних механізмів, які сама мова програмування забезпечити не здатна, а лише після створення спеціалізованих класів.
Qt використовує C++ з кількома нестандартними розширеннями, які реалізовуються за допомогою додаткового препроцесора, котрий генерує стандартний код на C++ перед компіляцією. Qt також може використовуватись і в інших мовах програмування через спеціальні розроблені прив’язки. Qt працює на усіх основних програмних і апаратних платформах, а також має чудову підтримку інтернаціоналізації. До функцій не пов’язаних з ГКІ, входять, зокрема, АРІ до доступу до баз даних SQL, парсингу XML, управління потоками, роботи з мережами, а також уніфіковані багатоплатформові функції для роботи з файлами.
Розповсюджується на умовах ліцензії GNU Lesser General Public License, і є вільним програмним забезпеченням.
2. Проектний розділ
2.1 Розробка структури додатку
При розробці проекту було проведене детальне опрацювання його структури.
Структура додатку — це його внутрішній устрій, його «кістяк», розташування розділів, підрозділів, додаткових матеріалів. І першочерговим завданням дизайнера є створення чіткого порядку з хаотичного скупчення інформації.
З позиції розробника, структуру сайту умовно можна поділити на два рівні: логічний і фізичний.
На логічному рівні структура сайту є сукупністю елементів керування, які об'єднані між собою єдиним дизайном, стилем і посиланнями.
На фізичному рівні структура сайту є впорядкованим набором файлів різного типу (XML-файли, зображення, код). Продумана і зручна файлова структура допомагає розробнику оптимізувати свою роботу, а також буде зрозумілою для інших фахівців, що працюють над проектом.
Кожет окремий клас повинен мати 2 файла: заголовочний та вихідний код. Також програма має основну частину, що міститься у файлі main. cpp.
Зовнішній вигляд кожного додатку є унікальним, проте в усіх програмах можна знайти спільні за функціональністю частини. Майже в будь-якому додатку першою відкривається головна форма, де розташовані основні елементи керування. Її розробці приділяють особливу увагу, оскільки дослідження показали, що люди не здатні читати інформацію, що відображається на моніторі, так уважно, як книжки або журнали. Вони зазвичай лише поверхово переглядають її, наприклад, як рекламу. Якщо головна форма містить те, що шукає відвідувач, він буде користуватися програмою далі, а якщо ні - буде шукати аналоги, яких в Інтернеті дуже багато.
Щоб забезпечити швидкий перехід до основних функцій додатку, створюють меню програми. Воно має бути зручним, помітним і зрозумілим, інакше користувач не знатиме, як перейти до потрібного розділу, і закриє додаток. Пункти меню мають бути чітко відділені один від одного.
Елементи керування дозволяють відкривають деякі форми та змінювати налаштування додатку, а також виконувати деякі дії.
Розробка структури додатку складається з:
визначення початкових даних;
визначення вимог до зовнішнього вигляду та функціональності;
формування файлової структури;
створення дизайн-макету головної форми;
затвердження концепції дизайну;
визначення завдань програмування;
написання коду.
При розробці дипломного проекту було проведено детальне опрацювання структури програми.
Структура додатку представлена у вигляді двох частин: клієнтської та серверної. Серверна частина дозволяє клієнтам підключатись до серверу та отримувати необхідні дані, задавати шаблон та фон для клієнтскої частини, встановлювати пароль для підключення.
Клієнтська частина доступна усім користувачам та дозволяє добавляти чи видаляти сервера зі списку, а також підключатися до них. Вона обробляє шаблон з сервера та показує його у формі, зрозумілій для людини. Також клієнтська частина дозволяє передавати на сервер команди, що будуть виконані, та записувати отримані дані до файлу.
Структура додатку має бути логічною та зручною.
2.2 Робота с XML, JSON та WebSocket
WebSocket — це протокол, що забезпечує двонаправлений повнодуплексний канал зв’язку через один TCP-сокет. WebSocket спроектовано для втілення у веб-браузерах та веб-серверах, але може також використовуватись будь-яким клієнт-серверним застосунком. Прикладний програмний інтерфейс WebSocket був стандартизований W3C, крім того протокол WebSocket стандартизований IETF як RFC 6455. Зв’язок здійснюється через 80-ий TCP-порт, а отже, його можна застосовувати в тих середовищах, де блокуються всі інші веб-з'єднання через фаєрвол.
Розширювана мова розмітки (англ. Extensible Markup Language, скорочено XML) — запропонований консорціумом World Wide Web (W3C) стандарт побудови мов розмітки ієрархічно структурованих даних для обміну між різними застосунками, зокрема, через Інтернет. Є спрощеною підмножиною мови розмітки SGML. XML документ складається із текстових знаків, і придатний до читання людиною.
Стандарт XML визначає набір базових лексичних та синтаксичних правил для побудови мови описання інформації шляхом застосування простих тегів. Цей формат достатньо гнучкий для того, аби бути придатним для застосування в різних галузях. Іншими словами, запропонований стандарт визначає метамову, на основі якої, шляхом запровадження обмежень на структуру та зміст документів визначаються специфічні, предметно-орієнтовані мови розмітки даних.
JSON (англ. JavaScript Object Notation, укр. об'єктний запис JavaScript, вимовляється джейсон) — це текстовий формат обміну даними між комп’ютерами. JSON базується на тексті, і може бути з легкістю прочитаним людиною. Формат дозволяє описувати об'єкти та інші структури даних. Цей формат головним чином використовується для передачі структурованої інформації через мережу (завдяки процесу, що називають серіалізацією).
Розробив і популяризував формат Дуглас Крокфорд.
JSON знайшов своє головне призначення у написанні веб-програм, а саме при використанні технології AJAX. JSON виступає як заміна XML під час асинхронної передачі структурованої інформації між клієнтом та сервером. При цьому перевагою JSON перед XML є те, що він дозволяє складні структури в атрибутах, займає менше місця і прямо інтерпретується за допомогою JavaScript в об'єкти.
Усі ці технології використовувались завдяки вбудованим у Qt класам, таким як QXmlDocument, QJsonDocument, QWebSocket, QWebSocketServer.
2.3 Алгоритм функціонування
UML (англ. Unified Modeling Language) — уніфікована мова моделювання, використовується у парадигмі об'єктно-орієнтованого програмування. Є невід'ємною частиною уніфікованого процесу розробки програмного забезпечення. UML є мовою широкого профілю, це відкритий стандарт, що використовує графічні позначення для створення абстрактної моделі системи, яку називають UML-моделлю. UML був створений для визначення, візуалізації, проектування й документування в основному програмних систем. UML не є мовою програмування, але в засобах виконання UML-моделей як інтерпретованого коду можлива кодогенерація.
Діаграма кламсів — статичне представлення структури моделі. Відображає статичні (декларативні) елементи, такі як: класи, типи даних, їх зміст та відношення. Діаграма класів, також, може містити позначення для пакетів та може містити позначення для вкладених пакетів. Також, діаграма класів може містити позначення деяких елементів поведінки, однак їх динаміка розкривається в інших типах діаграм. Діаграма класів (class diagram) служить для представлення статичної структури моделі системи в термінології класів об'єктно-орієнтованого програмування. На цій діаграмі показують класи, інтерфейси, об'єкти й кооперації, а також їхні відносини.
На рисунку А.1 (додаток А) приведена UML діаграма класів додатку. Програма складається з чотирьох дочірніх класів. Кожен клас має свої функції.
Клас Monitor є основним та відповідає за побудову клієнтської частини додатку. Клас має поля для елементів керування, списку елементів шаблону, списку серверів та інші. Також клас включає функції для обробки усіх подій.
Клас MyServer відповідає за роботу серверної частини додатку. Має поля для зберігання пароля, файлу фона на файлу шаблона. Включає фукнціі для обробки надходячих запросів та підключення клієнтів.
Класи ClickableLabel та Panel є допоміжними та являють собою кастомізований елемент керування Qt: QLabel. Клас ClickableLabel є елементом керування, дочірнім від Qlabel, що дозволяє оброблювани натискання. Клас Panel є дочірнім від ClickableLabel та дозволяє задавати стиль оформлення і фон елементу.
Діаграма прецедентів — в UML, діаграма, на якій зображено відношення між акторами та прецедентами в системі. Також, перекладається як діаграма варіантів використання.
У мові UML є кілька стандартних видів відношень між акторами і варіантами використання:
асоціації (англ. association relationship);
включення (англ. include relationship);
розширення (англ. extend relationship);
узагальнення (англ. generalization relationship).
При цьому загальні властивості варіантів використання можуть бути представлені трьома різними способами, а саме — за допомогою відношень включення, розширення і узагальнення.
Відношення асоціації - одне з фундаментальних понять у мові UML і в тій чи іншій мірі використовується при побудові всіх графічних моделей систем у формі канонічних діаграм.
Діаграма прецедентів наведена у додатку А, рисунок А.2.
Розглянемо діаграму на рисунку А.2 докладніше. Вона описує зовнішню взаємодію межі системи. Як видно, зовнішня межа складається з трьох акторів і шести прецедентів. Актори мають імена «Адміністратор», «Користувач» та «Сервер».
Діаграма діяльності (англ. Activity diagram) — UML-діаграма, на якій показано розкладання деякої діяльності на її складові частини. Під діяльністю розуміється специфікація виконуваної поведінки у вигляді координованого послідовного і паралельного виконання підлеглих елементів — вкладених видів діяльності та окремих дій, з'єднаних між собою потоками, які йдуть від виходів одного вузла до входів іншого.
На рисунку А.3 (додаток А) приведена UML діаграма діяльності додатку.
У даній діаграмі зображується послідовність дій користувача при використанні програми. Чорний круг — це початок процесу (початковий стан). Прямокутники з заокругленнями — це дії, які виконує користувач і програма. Ромби — це рішення, які виконує тільки програма. Чорний круг з обведенням — це закінчення процесу.
Після запуску програми перевіряється параметр «-s». Якщо він наявний — запускається серверна частина програми, що перевіряє наявність та коректність паролю та файлів шаблону и фону. Якщо вони некоректні - програма завершується, інакше сервер починає роботу та чекає підключення клієнту. При отриманні запиту від клієнта програма перевіряє правильність паролю та тип запиту і відповідає на нього, якщо пароль вірній, або віддає помилку, якщо пароль невірний.
При відсутності параметру «-s» запускається клієнтська частина програми, де користувач може додати сервер, підключитись до серверу, або вийти. При підключенні до серверу програма перевіряє пароль та можливість цієї дії, якщо це можливо — іде підключення до серверу, отримання шаблону, його адаптація та показ користувачу.
3. Охорона праці
3.1 Загальні питання охорони праці
Всесвітня організація охорони здоров’я ще в 1989 р. дійшла висновку, що робота з використанням персональних комп’ютерів (ПЕОМ) супроводжується зоровим і нервово-емоційним напруженням, негативними зрушеннями в кістково-м'язовій системі людини. Слабкі рівні неіонізуючих й іонізуючих випромінювань, що створюються відеодисплейними терміналами (ВДТ) на електронно-променевих трубках, несуть загрозу збільшення онкопатологій, негативного впливу на вагітних і плід. У всіх розвинених країнах, у тому числі в країнах Європейської спільноти, існують сотні документів, які регламентують вимоги не тільки до комп’ютерів, а й до організації робочих місць з їх використанням. Таким чином, безконтрольне використання комп’ютерної техніки може призвести до негативного впливу на здоров’я користувачів комп’ютерів, особливо дітей.
Широкомасштабні заходи, спрямовані на поліпшення здоров’я людей, повинні здійснюватись на кожному підприємстві у встановленому законодавчому порядку. Суворе додержання умов гігієни та фізіології праці є не тільки особистою справою людини, але й колективу, оскільки порушення принципів гігієни позначається не тільки на здоров'ї порушника, але й інших членів колективу.
Особи, допущені до роботи з комп’ютерною технікою зазнають впливу небезпечних і шкідливих виробничих факторів, таких як монотонність, підвищена температура зовнішнього середовища, відсутність або недостатня освітленість робочої зони, електричний струм, статистична електрика та інших. Основними питаннями з охороні праці на підприємстві є питання про освітленість, гігієну праці, організацію робочого місця, виробничого середовища, протипожежний захист, електробезпеку.
3.2 Гігієна праці та виробнича санітарія
Робітникові часто доводиться працювати у несприятливих умовах при високій або надто низькій температурі повітря, підвищеній вологості, на протягах, у приміщеннях з підвищеною кількістю пилу або пари отруйних речовин. Усі ці фактори можуть призвести до професійних захворювань дихальних органів, очей, шкіри та й усього організму. Постійні струси (вібрація) і шуми, що виникають у приміщеннях, де працюють робітники, також спричинюють до деяких видів захворювань. Щоб запобігти тимчасовим або хронічним професійним захворюванням, слід додержуватись правил гігієни праці на виробництві.
Гігієна праці - галузь профілактичної медицини, що вивчає умови збереження здоров’я на робочому місті й заходи, які сприяють цьому. Основні завдання гігієни праці:
вивчати вплив на людину метеорологічних умов і розробляє засоби і способи забезпечення комфортних умов праці;
вивчати вплив на організм людини небезпечних і токсичних речовин, що виділяються в навколишнє середовище, і розробляє засоби захисту;
вивчати вплив шуму, вібрації, іонізуючого випромінювання на організм людини і розробляє засоби захисту від цих чинників;
займатися питаннями освітлення робочих місць;
давати обґрунтування санітарним нормам;
займатися створенням індивідуальних засобів захисту;
займатися створенням індивідуальних засобів захисту;
розробляти засоби і методи контролю умов праці;
організовувати санітарно-побутове забезпечення.
При роботі на комп’ютерах, до складу яких входять відеодисплейні термінали, на працівників можуть діяти наступні шкідливі фізичні та психофізіологічні виробничі фактори. Фізичні:
підвищений рівень шуму (від вентилятора мікропроцесора та плат);
високий рівень напруги в електричній мережі, торкання до якої може викликати нещасний випадок;
підвищений рівень статичної електрики;
підвищений рівень електромагнітного випромінювання;
підвищений рівень напруженості електричного поля;
пряма і відбита від екрана бляклість;
несприятливе розподілення яскравості об'єктів в полі зору.
Психофізіологічні:
фізичні перевантаження статичної та динамічної дії;
нервово-психічні перевантаження (розумове перенапруження, перенапруження зорових аналізаторів, монотонність праці, емоційні перевантаження).
Таблиця 4.1 — Параметри метеорологічних умов виробничого середовища
|
Параметр | Фактичне значення | Значення по СН-245−71 чи державному стандарту | Висновок | |
| | | | |
Шум, дБ | | 38−86 | В межах допустимих значень | |
Освітленість (загальна), Лк | | 300−500 | В межах допустимих значень | |
Значення К.П.О., % | | 1,5−100 | В межах допустимих значень | |
Загазованість (концентрація і вид газу), мг/м3 | Азот 4,9 Аміак 11 Озон 0,04 Свинець 0,01 Хлор 0,8 | Азот 5 Аміак 20 Озон 0,1 Свинець 0,01 Хлор 1 | В межах допустимих значень | |
Температура повітря,°С взимку влітку | 21−23 22−24 | 21−24 22−25 | В межах допустимих значень | |
Відносна вологість, % | 40−55 | 40−60 | В межах допустимих значень | |
Швидкість руху повітря, м/с | 0,1−0,15 | 0,1−0,2 | В межах допустимих значень | |
|
3.3 Організація робочого простору
В даний час практично кожне робоче місце оснащене комп’ютерною та іншою технікою, тому особливе значення має правильне розміщення робочого місця працівника.
При розміщенні робочих місць з ПЕОМ відстань між робочими столами з відеомоніторами (у напрямі тилу поверхні одного відеомонітора і екрану іншого відеомонітора), повинна бути не менше 2,0 м, а відстань між бічними поверхнями відеомоніторів — не менше 1,2 м.
Робочі місця з ПЕОМ в приміщеннях з джерелами шкідливих виробничих факторів повинні розміщуватися в ізольованих кабінах з організованим повітрообміном.
Робочі місця з ПЕОМ при виконанні творчої роботи, що вимагає значного розумового напруження або високої концентрації уваги, рекомендується ізолювати один від одного перегородками висотою 1,5 — 2,0 м.
Екран відеомонітора повинен знаходитися від очей користувача на відстані 600−700 мм, але не ближче 500 мм з урахуванням розмірів алфавітно-цифрових знаків і символів.
Розміщення дисплеїв і допоміжних пристроїв на робочому місці має забезпечувати людині можливість приймати оптимальну робочу позу. При цьому слід виходити з положення, що найбільш негативний вплив на організм має не стільки сама поза, скільки час, протягом якого людина в ній знаходиться.
Робочі місця з дисплеями повинні проектуватися таким чином, щоб параметри основного обладнання були регульованими. Робочі місця без регульованої висоти клавіатури, висоти і віддаленості екрану не підходять для тривалої й безперервної роботи. Оптимально, коли можливо регулювати висоту і нахил робочої поверхні, висоту, нахил, поворот і віддаленість дисплея:
висота клавіатури (середній ряд над підлогою) 70−85 см;
центр екрану монітора над підлогою 90−115 см;
нахил екрану назад по відношенню до горизонтальної площини 88−105 градусів;
відстань між екраном і краєм столу 50−75 см. Для зменшення ризику появи відображень на поверхні екрану дисплея вона повинна перебувати під прямим кутом до вікна.
Вікна не повинні розташовуватися ні позаду операторів, ні перед ними. Глибина простору для ніг повинна становити: від краю столу не менше 60 см на рівні колін і 80 см на рівні ступень.
Розташування предметів в виробничому приміщенні повинно відповідати НАОП 0.00−1.31−99 (рисунок 4.1).
1 — комп’ютеризоване робоче місце з ПК та ЖК-монітором;
2 — сонцезахисні жалюзі;
3 — шафи для зберігання документації та фахової літератури.
Рисунок 4.1 — План виробничого приміщення з комп’ютеризованими робочими місцями.
3.4 Електробезпека в приміщеннях з ЕОМ
Вимоги електробезпеки і пожежної безпеки у приміщеннях, де встановлені ВДТ ЕОМ і ПЕОМ, відображені у ДНАОП 0.00−1.31−99: ЕОМ і все устаткування для обслуговування, ремонту та налагодження роботи їх, електропроводи і кабелі мають відповідати електробезпеці зони за ПВЕ та мати апаратуру захисту від струму короткого замикання.
Необхідно забезпечити неможливість виникнення джерела загорання внаслідок короткого замикання та перевантаження проводів шляхом переходу на негорючу ізоляцію.
Лінії електромережі ВДТ ЕОМ і ПЕОМ виконуються як окрема групова трипровідна мережа шляхом прокладання фазового, нульового робочого та нульового захисного провідників (заземлення або занулення), причому площі перерізу нульового робочого і нульового захисного провідника повинні бути не меншими за площу перерізу фазового провідника.
При одночасному використанні понад п’яти ПЕОМ на помітному місці встановлюється аварійний резервний вимикач, який в разі небезпеки повністю знеструмлює електричну мережу (крім освітлення). В такому випадку при використанні трипровідникового захищеного проводу або кабелю в оболонці з негорючого або важкогорючого матеріалу дозволено прокладати їх без металевих труб та гнучких металевих рукавів.
Електромережі для під'єднання ВДГ, ЕОМ і ПЕОМ оснащуються справжніми штепсельними з'єднаннями та електророзетками, які, крім контактів фазового і нульового робочого провідників, мають спеціальні контакти для під'єднання нульового захисного провідника, що під'єднаний раніше ніж вони. Порядок роз'єднання при відімкненні мережі має бути зворотним. Заборонено приєднувати обладнання до звичайної двопровідної електричної мережі, зокрема з використанням перехідних пристроїв. Електромережі штепсельних з'єднань та електричних розеток необхідно виконувати за магістральною схемою, по 3−6 в одному колі. При розташуванні їх уздовж стін провідники прокладають по підлозі в металевих трубах і гнучких металевих рукавах, а при розташуванні їх у центрі приміщення прокладають у каналах або під знімною підлогою в металевих рукавах. При цьому не дозволяється використовувати провід і кабель в ізоляції з вулканізованої гуми та інші матеріали, що містять сірку. Металеві трубки і гнучкі металеві рукави повинні бути заземлені відповідно до ДНАОП 0.001.21−98. Неприпустимо використовувати функціональне заземлення для під'єднання захисного заземлення.
Штепсельні з'єднання або електричні розетки для напруги 12 і 36 В мають бути пофарбовані в колір, відрізняється від їхнього кольору для напруги 127 і 220 В.
Плити знімної підлоги повинні бути важкогорючими, з межею вогнестійкості не меншою за 30 хвилин, або негорючими і виконані з матеріалів, які під час горіння не виділяють шкідливих токсичних речовин і газів, що сприяють корозії. Простір під ними розділяють негорючими діафрагмами на відсіки площею не більшою за 250 м² з межею вогнестійкості не меншою за 45 хв. Простір під підлогою має бути оснащений системою пожежної сигналізації та засобами пожежогасіння відповідно до вимог пожежного захисту з використанням димових пожежних сповіщувачів.
3.5 Пожежна безпека
Пожежна безпека на підприємстві - це один з важливих факторів збереження вашої робочої території і життя персоналу. На жаль, більшість підприємців підходять до цього питання не дуже серйозно. Вішають вогнегасники, пожежні сигналізації, малюють плани евакуації не для того, щоб дійсно захистити себе від можливої майбутньої біди, а для перевірок. І тільки якщо, дійсно, щось станеться на площах підприємств, тільки тоді власники фірм по-справжньому ставляться до цього серйозніше, не обходять даний момент стороною, але часом це відбувається вже пізно.
Пожежна безпека на підприємстві - це не тільки ряд стандартних вимог. Будь своє або орендоване приміщення, має бути готове до стану бойової готовності, а не покладатися на справа випадку. Збитки від пожеж небезпечні і значні тим, що осередок загоряння не зафіксуєш відразу без допоміжних засобів і гасити полум’я досить складно. У будь-якому приміщенні, не важливо, воно ваше особисте або орендоване, потрібно встановлювати всі потрібні системи пожежогасіння.
Для того, щоб повністю була активною пожежна безпека на підприємстві, потрібно першою справою встановлювати пожежну сигналізацію. Завдання встановленого обладнання — оповістити людей, що працюють на даній території про пожежу або можливому невеликому загорянні. У деяких випадках існує автоматичне гасіння пожежі. Також всі приміщення зобов’язана бути забезпечене вогнегасниками, які повинні розставлятися на вільних видних місцях. До них додається інструкція по користуванню. Бажано, щоб працюючий персонал прочитав правила користування вогнегасником до того моменту, коли доведеться його використовувати в дії, інакше це може призвести до плачевних ситуацій. Важливо знати, що вогнегасник потрібно зберігати в місцях, захищених від прямих сонячних променів. І одне з головних правил — це план евакуації, що включає в себе всі входи і виходи, вікна, розташування вогнегасників на тому чи іншому поверсі, пожежні сходи, електрощитові.
У випадку пожежі треба використовувати план евакуації (рисунок 4.2).
Рисунок 4.2 — План евакуації людей
Здавалося б, навіщо він потрібний, особливо тим, хто в даному приміщенні вже працює досить довго і пройшов би по ньому із закритими очима.
Але на практиці часто трапляються випадки, коли в знайомому місці при пожежі людина не змогла зорієнтуватися. Правила пожежної безпеки на підприємстві для всіх однакові і повинні виконуватися відповідно до вимог.
Висновки
Створюючи додаток, у першу чергу розглядалася практична користь. Після вибори теми для дипломного проекту почався аналіз предметної області та не було знайдено зручних аналогів цієї програми. Саме це породило ентузіазм для створення зручного, простого та корисного додатку, який зміг бі використовувати кожний — від домогосподарки до системного адміністратору.
При створенні додатку для дипломного проекту за мету бралося закріплення знань мови C++ та фреймворку Qt, що й було реалізовано у повній мірі: у коді програми є спадкування класів, інкапсуляція, ссилання, реалізація сигналів та слотів Qt. Були створені декілька дочірніх класів від стандартних у фреймворку, що були кастомізовані та підведені під конкретні потреби.
У процесі створення додатку були виктористані такі технології, як WebSocket, XML та JSON. Вони використовуються не тільки у С++, тому будуть корисними дальніше. Наприклад, технологія WebSocket — для зручного побудування зв’язку кліент-сервер у будь-якій мові, XML — для храніння даних у зручному для розбіру форматі, а JSON — для передачі даних між клієнтами або клієнтом та сервером.
Також, створуючи додаток, було прочитано багато літератури, присвяченій побудові зручного для користувача інтерфейсу, який був би інтуітивно зрозумілим та приємним у роботі, а також підбору кольорів, що будуть приємними для ока людини та розташовувати оператора до програми.
При написанні дипломного проекту була також використана система контролю версій Git, що допомагала у розробці: вона дозволяє швидко перемикатись між версіями програми, відміняти зміни, які вийшли невдалими та зберігати проект на віддаленому сервері.
Дипломний проект виконаний у відповідності з вимогами до оформлення програмної та текстової документації.
Отже, написання цього додатку — дуже гарний досвід у програмуванні, створенні інтерфейсів, роботі з технологією клієнт-сервер і фреймворком Qt.
Додатки
Додаток А. UML-діаграми
Рисунок А.1 — Діаграма класів Рисунок А.2 — Діаграма прецедентів Рисунок А.3 — Діаграма діяльності
Додаток Б
Код програми.
// файл main. cpp:
#include
#include
#include
#include
#include «monitor. h»
int main (int argc, char *argv []) {
// відключаємо відображення некритичних помилок
qputenv («QT_LOGGING_RULES», «qt.network. ssl. warning=false»);
QApplication a (argc, argv);
Monitor* w;
bool isServer = false;
QString password;
QString templateFilename;
QString bgFilename = «» ;
// парсимо аргументи
for (int i = 1; i < argc; i++) {
QString arg = argv [i];
if (arg == «-t» || arg == «—template») {
templateFilename = QString (argv [i + 1]). trimmed ();
i++;
} else if (arg == «-p» || arg == «—password») {
password = QString (argv [i + 1]). trimmed ();
} else if (arg == «-b» || arg == «—background») {
bgFilename = QString (argv [i + 1]). trimmed ();
} else if (arg == «-s» || arg == «—server») {
isServer = true;
} else {
qDebug () << «Неизвестный параметр: «<< arg;
return 0;
}
}
if (! isServer) {
// запускаємо кліент, якщо не було аргумента — s
w = new Monitor ();
QString logDir = w->logDir;
QDir dir (logDir);
if (! dir. exists ())
dir. mkdir (logDir);
w->show ();
} else {
// перевіряємо аргументи
if (password. isEmpty ()) {
qDebug () << «Укажите пароль. «;
return 0;
}
if (templateFilename. isEmpty ()) {
qDebug () << «Укажите шаблон. «;
return 0;
}
QFile tplFile (templateFilename);
if (! tplFile. exists ()) {
qDebug () << «Неверный файл шаблона. «;
return 0;
}
QFile bgfile (bgFilename);
if (bgFilename! = «» &&! bgfile. exists ()) {
qDebug () << «Неверный файл фона. «;
return 0;
}
// запускаємо сервер
qDebug () << «Сервер запущен. «;
// зчитуємо фон та шаблон
QByteArray data;
QFile tdata (templateFilename);
tdata. open (QIODevice: ReadOnly);
data = tdata. readAll ();
tdata. close ();
QByteArray bg;
if (bgFilename! = «») {
QFile bgdata (bgFilename);
bgdata. open (QIODevice: ReadOnly);
bg = bgdata. readAll ();
bgdata. close ();
}
// створюємо сервер
MyServer* server;
if (bgFilename! = «»)
server = new MyServer (64 178, password, data, bg);
else
server = new MyServer (64 178, password, data);
Q_UNUSED (server);
}
return a. exec ();
}
// файл monitor. h
#ifndef MONITOR_H
#define MONITOR_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class Monitor: public QMainWindow {
Q_OBJECT
public:
Monitor (QWidget *parent = 0);
// директорія для логів
QString logDir = QStandardPaths: writableLocation (QStandardPaths: HomeLocation) + «/. TDM-log/» ;
QString logFileName = «» ;
~Monitor ();
private:
// текстові значення
QMap> values;
// кнопки
QMap buttons;
// списки
QMap> commands;
// графіки
QVector>> graphs;
// список серверів
QMap serverList;
// сервери
QVector servers;<\/p><p>// підключений сервер<\/p><p>Server* currentServer;<\/p><p>QWidget* cWidget;<\/p><p>QWidget* templateParent;<\/p><p>QVBoxLayout* mainLayout;<\/p><p>ClickableLabel* addButton;<\/p><p>Panel* addServerPanel;<\/p><p>QLabel* addServerNameLabel;<\/p><p>QLineEdit* addServerNameEdit;<\/p><p>QLabel* addServerIpLabel;<\/p><p>QLineEdit* addServerIpEdit;<\/p><p>QLabel* addServerPasswordLabel;<\/p><p>QLineEdit* addServerPasswordEdit;<\/p><p>ClickableLabel* addServerSaveButton;<\/p><p>ClickableLabel* addServerCancelButton;<\/p><p>QTimer* updateTimer;<\/p><p>QLabel* loadingLabel;<\/p><p>bool bg = false;<\/p><p>// інтервал оновлення<\/p><p>int updateInterval = 2500;<\/p><p>// фон<\/p><p>QByteArray background;<\/p><p>QWebSocket* mainSocket;<\/p><p>private slots:<\/p><p>void buttonClicked (); // кнопка користувача натиснута<\/p><p>void selectClicked (int index); // обраний один з елементів списку<\/p><p>void addButtonClicked (); // кнопка додавання серверу<\/p><p>void cancelAdd (); // відміна додавання серверу<\/p><p>void saveButtonClicked (); // кнопка збереження серверу<\/p><p>void saveAndAdd (); // зберегти сервер<\/p><p>void serverClicked (); // підключитися до серверу<\/p><p>void templateCame (QByteArray templateData); // отриманий шаблон<\/p><p>void serverAnswered (QString message); // сервер відповів<\/p><p>void socketSuccess (); // відключення встановлене<\/p><p>void socketError (); // помилка підключення<\/p><p>void updateInfo (); // створення сокету<\/p><p>void updateStart (); // відправка запиту на оновлення<\/p><p>void updateCame (QString message); // прийшло оновлення<\/p><p>void getBackground (); // відправка запиту на фон<\/p><p>void gotBackground (QByteArray data); // фон прийшов<\/p><p>void gotBackgroundError (QString data); // фон не прийшов<\/p><p>private:<\/p><p>void loadTemplate (QByteArray content); // завантаження шаблону<\/p><p>void saveServers (); // збереження списку серверів<\/p><p>void loadServers (); // завантаження списку серверів<\/p><p>void startUpdateTimer (); // початок оновлення<\/p><p>bool eventFilter (QObject *sender, QEvent *event);<\/p><p>void keyReleaseEvent (QKeyEvent *event);<\/p><p>void paintControls (); // малювання елементів керування<\/p><p>void applyBackground (); // встановлення фону<\/p><p>private:<\/p><p>bool loading = false;<\/p><p>bool templateLoaded = false;<\/p><p>bool backgroundLoaded = false;<\/p><p>bool connected = false;<\/p><p>bool firstLoad = true;<\/p><p>};<\/p><p>#endif // MONITOR_H<\/p><p>// файл monitor. cpp:<\/p><p>#include <QtCore><\/p><p>#include <QtWidgets><\/p><p>#include <QtXml><\/p><p>#include <QtWebSockets><\/p><p>#include <QJsonDocument><\/p><p>#include «monitor. h» <\/p><p>#include «panel. h» <\/p><p>#include «clickablelabel. h» <\/p><p>#include <math. h><\/p><p>double roundDouble (double doValue, int nPrecision) {<\/p><p>static const double doBase = 10.0;<\/p><p>double doComplete5, doComplete5i;<\/p><p>doComplete5 = doValue * pow (doBase, (double) (nPrecision + 1));<\/p><p>if (doValue < 0.0)<\/p><p>doComplete5 — = 5.0;<\/p><p>else<\/p><p>doComplete5 += 5.0;<\/p><p>doComplete5 /= doBase;<\/p><p>modf (doComplete5, &doComplete5i);<\/p><p>return doComplete5i / pow (doBase, (double) nPrecision);<\/p><p>}<\/p><p>QDataStream& operator>> (QDataStream& stream, Server& server) {<\/p><p>stream >> server. ip >> server. password >> server. name;<\/p><p>return stream;<\/p><p>}<\/p><p>QDataStream& operator<< (QDataStream& stream, const Server& server) {<\/p><p>stream << server. ip << server. password << server. name;<\/p><p>return stream;<\/p><p>}<\/p><p>void Monitor: saveServers () QIODevice: Truncate);<\/p><p>QDataStream stream (&file);<\/p><p>stream. setVersion (QDataStream: Qt5_2);<\/p><p>stream << servers;<\/p><p>file. close ();<\/p><p>void Monitor: loadServers () {<\/p><p>QString configPath = QStandardPaths: writableLocation (QStandardPaths: AppDataLocation) + «/» ;<\/p><p>QDir configDir (configPath);<\/p><p>if (! configDir. exists ())<\/p><p>configDir. mkdir (configPath);<\/p><p>QFile file (configPath + «servers. dat»);<\/p><p>if (! file. exists ()) return;<\/p><p>QVector<Server> tempServers;<\/p><p>servers = tempServers;<\/p><p>file. open (QIODevice: ReadOnly);<\/p><p>QDataStream stream (&file);<\/p><p>stream. setVersion (QDataStream: Qt5_2);<\/p><p>stream >> tempServers;<\/p><p>file. close ();<\/p><p>if (tempServers. length () > 0) {<\/p><p>loading = true;<\/p><p>for (Server server: tempServers) {<\/p><p>addServerNameEdit->setText (server. name);<\/p><p>addServerIpEdit->setText (server. ip);<\/p><p>addServerPasswordEdit->setText (server. password);<\/p><p>saveAndAdd ();<\/p><p>}<\/p><p>loading = false;<\/p><p>}<\/p><p>}<\/p><p>Monitor: Monitor (QWidget *parent): QMainWindow (parent) {<\/p><p>showMaximized ();<\/p><p>installEventFilter (this);<\/p><p>QDateTime now = QDateTime: currentDateTime ();<\/p><p>logFileName = now. toString (Qt: DefaultLocaleShortDate) +". log" ;<\/p><p>}<\/p><p>void Monitor: paintControls () <\/p><p>templateParent = new QWidget (this);<\/p><p>cWidget = new QWidget ();<\/p><p>setCentralWidget (cWidget);<\/p><p>cWidget->show ();<\/p><p>mainLayout = new QVBoxLayout ();<\/p><p>cWidget->setLayout (mainLayout);<\/p><p>mainLayout->setMargin (0);<\/p><p>mainLayout->setAlignment (Qt: AlignTop);<\/p><p>QPixmap addPixmap («: /images/add»);<\/p><p>addButton = new ClickableLabel (this);<\/p><p>addButton->setPixmap (addPixmap. scaled (128, 128));<\/p><p>addButton->setFixedSize (128, 128);<\/p><p>addButton->move (width () — 138, height () — 138);<\/p><p>addButton->setCursor (Qt: PointingHandCursor);<\/p><p>addButton->show ();<\/p><p>connect (addButton, SIGNAL (clicked ()), this, SLOT (addButtonClicked ()));<\/p><p>addServerPanel = new Panel (this);<\/p><p>addServerPanel->setFixedSize (width (), 340);<\/p><p>addServerPanel->move (0, height () — 340);<\/p><p>addServerPanel->setStyleSheet («background: #2c3e50; border: none; border-radius: 0; «);<\/p><p>addServerPanel->setVisible (false);<\/p><p>// Labels<\/p><p>addServerNameLabel = new QLabel (addServerPanel);<\/p><p>addServerNameLabel->setText («Название: «);<\/p><p>addServerNameLabel->setStyleSheet («color: white; font-size: 12px; background: #2c3e50; «);<\/p><p>addServerNameLabel->adjustSize ();<\/p><p>addServerNameLabel->move (30, 30);<\/p><p>addServerNameLabel->show ();<\/p><p>addServerIpLabel = new QLabel (addServerPanel);<\/p><p>addServerIpLabel->setText («IP-адрес: «);<\/p><p>addServerIpLabel->setStyleSheet («color: white; font-size: 32px; background: #2c3e50; «);<\/p><p>addServerIpLabel->adjustSize ();<\/p><p>addServerIpLabel->move (30, 85);<\/p><p>addServerIpLabel->show ();<\/p><p>addServerPasswordLabel = new QLabel (addServerPanel);<\/p><p>addServerPasswordLabel->setText («Пароль: «);<\/p><p>addServerPasswordLabel->setStyleSheet<\/p><p>(«color: white; font-size: 32px; background: #2c3e50; «);<\/p><p>addServerPasswordLabel->adjustSize ();<\/p><p>addServerPasswordLabel->move (30, 140);<\/p><p>addServerPasswordLabel->show ();<\/p><p>// Edits<\/p><p>addServerNameEdit = new QLineEdit (addServerPanel);<\/p><p>addServerNameEdit->setStyleSheet («color: black; font-size: 32px; border-radius: 0; border: 1px solid #ddd; background: white; «);<\/p><p>addServerNameEdit->adjustSize ();<\/p><p>addServerNameEdit->setFixedSize (width () — addServerNameLabel->width () — 70, 43);<\/p><p>addServerNameEdit->move (30 + addServerNameLabel->width () + 10, 26);<\/p><p>addServerNameEdit->show ();<\/p><p>addServerIpEdit = new QLineEdit (addServerPanel);<\/p><p>addServerIpEdit->setStyleSheet («color: black; font-size: 32px; border-radius: 0; border: 1px solid #ddd; background: white; «);<\/p><p>addServerIpEdit->adjustSize ();<\/p><p>addServerIpEdit->setFixedSize (width () — addServerNameLabel->width () — 70, 43);<\/p><p>addServerIpEdit->move (30 + addServerNameLabel->width () + 10, 81);<\/p><p>addServerIpEdit->show ();<\/p><p>QString octet = «(?: [0−1]? [0−9]? [0−9] <\/p><p>void Monitor: loadTemplate (QByteArray content) {<\/p><p>templateParent = new QWidget (this);<\/p><p>templateParent->setGeometry (0, 0, width (), height ());<\/p><p>templateParent->setObjectName («mainWidget»);<\/p><p>templateParent->show ();<\/p><p>QDomDocument xml («content»);<\/p><p>xml. setContent (content);<\/p><p>auto root = xml. documentElement ();<\/p><p>QString bodyStyle = root. attribute («style»);<\/p><p>templateParent->setStyleSheet («QWidget#mainWidget {» + bodyStyle + «}»);<\/p><p>auto elements = root. childNodes ();<\/p><p>auto panelY = 0;<\/p><p>for (int i = 0; i < elements. count (); i++) {<\/p><p>auto element = elements. at (i). toElement ();<\/p><p>auto name = element. nodeName ();<\/p><p>if (name == «panel») {<\/p><p>QString margin = element. attribute («margin»);<\/p><p>QString padding = element. attribute («padding»);<\/p><p>QString style = element. attribute («style»);<\/p><p>QString align = element. attribute («align»);<\/p><p>QString bottom = element. attribute («bottom»);<\/p><p>QString top = element. attribute («top»);<\/p><p>int panelHeight = 0;<\/p><p>Panel* panel = new Panel (templateParent);<\/p><p>panel->setMargin (margin. toInt ());<\/p><p>panel->addStyle (style);<\/p><p>if (align == «center»)<\/p><p>panel->setAlignment (Qt: AlignCenter);<\/p><p>else if (align == «right») {<\/p><p>panel->setAlignment (Qt: AlignRight);<\/p><p>} else {<\/p><p>panel->setAlignment (Qt: AlignLeft);<\/p><p>}<\/p><p>panel->setProperty («padding», padding);<\/p><p>panel->setFixedWidth (this->width () — margin. toInt () * 2);<\/p><p>panel->move (margin. toInt (), panelY + margin. toInt ());<\/p><p>if (bottom! = «») panel->move (panel->x (), height () — bottom. toInt ());<\/p><p>if (top! = «») panel->move (panel->x (), top. toInt ());<\/p><p>int lineY = padding. toInt ();<\/p><p>auto lines = element. childNodes ();<\/p><p>for (int j = 0; j < lines. count (); j++) {<\/p><p>auto _el = lines. at (j). toElement ();<\/p><p>auto _name = _el. nodeName ();<\/p><p>if (_name == «line») {<\/p><p>QString tsize = _el. attribute («tsize»);<\/p><p>QString tcolor = _el. attribute («tcolor»);<\/p><p>QString style = _el. attribute («style»);<\/p><p>int lineWidth = 0;<\/p><p>int lineHeight = tsize. toInt () + 5;<\/p><p>QLabel* line = new QLabel (panel);<\/p><p>line->setStyleSheet (style);<\/p><p>line->setAttribute (Qt: WA_TranslucentBackground);<\/p><p>int textX = 0;<\/p><p>auto texts = _el. childNodes ();<\/p><p>for (int o = 0; o < texts. count (); o++) {<\/p><p>auto _text = texts. at (o). toElement ();<\/p><p>auto _elName = _text. nodeName ();<\/p><p>if (_elName == «text») {<\/p><p>QString id = _text. attribute («id»);<\/p><p>QString color = _text. attribute («color»);<\/p><p>QString log = _text. attribute («log»);<\/p><p>bool bold = (_text. attribute («bold») == «true»? true: false);<\/p><p>QString stylesheet = «font-size: «+ tsize + «px; color: black; «;<\/p><p>if (bold) stylesheet += «font-weight: bold; «;<\/p><p>if (! tcolor. isEmpty ()) stylesheet += «color: «+ tcolor + «; «;<\/p><p>if (! color. isEmpty ()) stylesheet += «color: «+ color + «; «;<\/p><p>QString value = _text. text ();<\/p><p>QString command;<\/p><p>if (value. mid (0, 1) == «{» && value. mid (value. length () — 1, 1) == «}») {<\/p><p>command = value. mid (1, value. length () — 2);<\/p><p>value = «?» ;<\/p><p>}<\/p><p>QLabel* text = new QLabel (line);<\/p><p>text->setText (value);<\/p><p>text->setStyleSheet (stylesheet);<\/p><p>text->setAttribute (Qt: WA_TranslucentBackground);<\/p><p>text->setFixedHeight (tsize. toInt () + 5);<\/p><p>text->move (textX, 0);<\/p><p>text->setProperty («log», log);<\/p><p>text->show ();<\/p><p>if (id! = «» && command! = «») {<\/p><p>QMap<QLabel*, QString> temp;<\/p><p>temp. insert (text, command);<\/p><p>values. insert (id, temp);<\/p><p>}<\/p><p>lineWidth += text->width ();<\/p><p>textX += text->width ();<\/p><p>}<\/p><p>if (_elName == «button») {<\/p><p>QString click = _text. attribute («click»);<\/p><p>QString style = _text. attribute («style»);<\/p><p>QString width = _text. attribute («width»);<\/p><p>bool bold = (_text. attribute («bold») == «true»? true: false);<\/p><p>QString stylesheet = «font-size: «+ QString: number (tsize. toInt () — 10) + «px; «;<\/p><p>if (bold) stylesheet += «font-weight: bold; «;<\/p><p>QString value = _text. text ();<\/p><p>QPushButton* button = new QPushButton (line);<\/p><p>button->setText (value);<\/p><p>button->setStyleSheet (stylesheet + style);<\/p><p>button->adjustSize ();<\/p><p>button->setFixedHeight (tsize. toInt () + 5);<\/p><p>button->move (textX, 0);<\/p><p>button->show ();<\/p><p>if (! width. isEmpty ()) button->setFixedWidth (width. toInt ());<\/p><p>connect (button, SIGNAL (clicked ()), this, SLOT (buttonClicked ()));<\/p><p>if (click! = «») buttons [button] = click;<\/p><p>lineWidth += button->width ();<\/p><p>textX += button->width ();<\/p><p>}<\/p><p>if (_elName == «select») {<\/p><p>QString style = _text. attribute («style»);<\/p><p>QString width = _text. attribute («width»);<\/p><p>width = (width. isEmpty ()?» 100»: width);<\/p><p>QString stylesheet = «font-size: «+ QString: number (tsize. toInt () — 10) + «px; «;<\/p><p>QString itemsStyle = «QComboBox QAbstractItemView: item { padding: 10px; text-align: center; border: 0; padding-left: 10px; outline: none; } QComboBox QAbstractItemView: item: hover { outline: none; border: 0; }» ;<\/p><p>QComboBox* select = new QComboBox (line);<\/p><p>select->setStyleSheet («QComboxBox { «+ stylesheet + style + «} «+ itemsStyle);<\/p><p>select->setFixedHeight (tsize. toInt () + 5);<\/p><p>select->installEventFilter (this);<\/p><p>select->setEditable (false);<\/p><p>select->move (textX, 0);<\/p><p>select->show ();<\/p><p>connect (select, SIGNAL (currentIndexChanged (int)), this, SLOT (selectClicked (int)));<\/p><p>QStyledItemDelegate* itemDelegate = new QStyledItemDelegate ();<\/p><p>select->setItemDelegate (itemDelegate);<\/p><p>if (! width. isEmpty ()) select->setFixedWidth (width. toInt ());<\/p><p>QMap<int, QString> temp;<\/p><p>auto items = _text. childNodes ();<\/p><p>for (int i = 0; i < items. count (); i++) {<\/p><p>auto item = items. at (i). toElement ();<\/p><p>if (item. nodeName ()! = «item») continue;<\/p><p>temp. insert (i, item. attribute («execute»));<\/p><p>select->addItem (item. text ());<\/p><p>}<\/p><p>select->setCurrentIndex (-1);<\/p><p>commands. insert (select, temp);<\/p><p>lineWidth += select->width ();<\/p><p>textX += select->width ();<\/p><p>}<\/p><p>if (_elName == «graph») {<\/p><p>QString color = _text. attribute («color»);<\/p><p>QString linesize = _text. attribute («line»);<\/p><p>QString width = _text. attribute («width»);<\/p><p>QString valuesCount = _text. attribute («values»);<\/p><p>QString fill = _text. attribute («fill»);<\/p><p>QString fillColor = _text. attribute («fillcolor»);<\/p><p>QString gridColor = _text. attribute («gridcolor»);<\/p><p>if (linesize. isEmpty ()) {<\/p><p>QMessageBox: information (this, «Ошибка», «Вы не указали толщину линии в шаблоне.», QMessageBox: Ok);<\/p><p>qApp->exit ();<\/p><p>}<\/p><p>if (width. isEmpty ()) {<\/p><p>QMessageBox: information (this, «Ошибка», «Вы не указали ширину графика в шаблоне.», QMessageBox: Ok);<\/p><p>qApp->exit ();<\/p><p>}<\/p><p>valuesCount = (valuesCount. isEmpty ()?» 20»: valuesCount);<\/p><p>color = (color. isEmpty ()?» black»: color);<\/p><p>linesize = (linesize. isEmpty ()?» !»: linesize);<\/p><p>width = (width. isEmpty ()?» 400»: width);<\/p><p>QGraphicsView* graph = new QGraphicsView (line);<\/p><p>graph->setFixedHeight (tsize. toInt ());<\/p><p>graph->setFixedWidth (width. toInt ());<\/p><p>graph->move (textX, 0);<\/p><p>graph->setAttribute (Qt: WA_TranslucentBackground);<\/p><p>graph->setStyleSheet («border: 0»);<\/p><p>graph->show ();<\/p><p>QMap<QGraphicsView*, QVector<float>> temp;<\/p><p>QVector<float> temparr = {};<\/p><p>graph->setProperty («command», _text. text (). trimmed ());<\/p><p>graph->setProperty («lineColor», color);<\/p><p>graph->setProperty («lineSize», linesize);<\/p><p>graph->setProperty («valuesCount», valuesCount);<\/p><p>graph->setProperty («fill», fill);<\/p><p>graph->setProperty («fillColor», fillColor);<\/p><p>graph->setProperty («gridColor», (gridColor. isEmpty ()?» gray»: gridColor));<\/p><p>temp. insert (graph, temparr);<\/p><p>graphs. push_back (temp);<\/p><p>lineWidth += graph->width ();<\/p><p>textX += graph->width ();<\/p><p>}<\/p><p>}<\/p><p>line->setFixedWidth (lineWidth);<\/p><p>line->setFixedHeight (lineHeight);<\/p><p>if (align == «center»)<\/p><p>line->move (panel->width () / 2 — lineWidth / 2, lineY);<\/p><p>else if (align == «right») {<\/p><p>line->move (panel->width () — lineWidth — padding. toInt (), lineY);<\/p><p>} else {<\/p><p>line->move (padding. toInt (), lineY);<\/p><p>}<\/p><p>line->show ();<\/p><p>lineY += lineHeight;<\/p><p>panelHeight += lineHeight;<\/p><p>}<\/p><p>}<\/p><p>panel->setFixedHeight (panelHeight + padding. toInt () * 2);<\/p><p>panel->show ();<\/p><p>if (bottom == «» && top == «») panelY += panel->height () + margin. toInt ();<\/p><p>}<\/p><p>}<\/p><p>}<\/p><p>void Monitor: buttonClicked () {<\/p><p>QPushButton* button = (QPushButton*) sender ();<\/p><p>if (buttons [button]! = «») {<\/p><p>QString command = buttons [button]; <\/p><p>auto socket = new QWebSocket ();<\/p><p>socket->open (QUrl («ws: // «+ currentServer->ip + «: 64 178»));<\/p><p>connect (socket, &QWebSocket: connected, [=] () {<\/p><p>QJsonObject obj;<\/p><p>obj. insert («command», QJsonValue («execute»));<\/p><p>obj. insert («password», QJsonValue (currentServer->password));<\/p><p>obj. insert («execute», QJsonValue (command));<\/p><p>QJsonDocument doc;<\/p><p>doc. setObject (obj);<\/p><p>socket->sendTextMessage (doc. toJson (). replace («n», «»));<\/p><p>socket->close ();<\/p><p>});<\/p><p>}<\/p><p>}<\/p><p>void Monitor: addButtonClicked () {<\/p><p>addServerPanel->setVisible (true);<\/p><p>}<\/p><p>void Monitor: cancelAdd () {<\/p><p>addServerPanel->setVisible (false);<\/p><p>}<\/p><p>void Monitor: saveButtonClicked () {<\/p><p>saveAndAdd ();<\/p><p>saveServers ();<\/p><p>}<\/p><p>void Monitor: saveAndAdd () {<\/p><p>QString name = addServerNameEdit->text (). trimmed ();<\/p><p>QString ip = addServerIpEdit->text (). trimmed ();<\/p><p>QString password = addServerPasswordEdit->text ();<\/p><p>if (name. isEmpty () || ip. isEmpty () || password. isEmpty ()) {<\/p><p>QMessageBox: information (this, «Ошибка», «Заполните все необходимые поля.», QMessageBox: Ok);<\/p><p>return;<\/p><p>}<\/p><p>servers. append (Server { ip, password, name });<\/p><p>Panel* panel = new Panel ();<\/p><p>panel->setFixedSize (width (), 160);<\/p><p>panel->setCursor (Qt: PointingHandCursor);<\/p><p>panel->addStyle («background: transparent; border: none; border-radius: 0; «);<\/p><p>connect (panel, SIGNAL (clicked ()), this, SLOT (serverClicked ()));<\/p><p>QPixmap serverPixmap («: /images/server»);<\/p><p>QLabel* image = new QLabel (panel);<\/p><p>image->setPixmap (serverPixmap. scaled (128, 128));<\/p><p>image->setAttribute (Qt: WA_TranslucentBackground);<\/p><p>image->move (18, 18);<\/p><p>QLabel* nameLabel = new QLabel (panel);<\/p><p>nameLabel->setText (name);<\/p><p>nameLabel->setStyleSheet («font-size: 34px; font-weight: bold; color: #2c3e50; «);<\/p><p>nameLabel->setAttribute (Qt: WA_TranslucentBackground);<\/p><p>nameLabel->adjustSize ();<\/p><p>nameLabel->move (156, 45);<\/p><p>QLabel* ipLabel = new QLabel (panel);<\/p><p>ipLabel->setText (ip);<\/p><p>ipLabel->setStyleSheet («font-size: 22px; color: #34495e; «);<\/p><p>ipLabel->setAttribute (Qt: WA_TranslucentBackground);<\/p><p>ipLabel->adjustSize ();<\/p><p>ipLabel->move (156, 84);<\/p><p>mainLayout->addWidget (panel);<\/p><p>addServerPanel->setVisible (false);<\/p><p>addServerNameEdit->clear ();<\/p><p>addServerIpEdit->clear ();<\/p><p>addServerPasswordEdit->clear ();<\/p><p>serverList. insert (panel, servers. last ());<\/p><p>}<\/p><p>void Monitor: serverClicked () {<\/p><p>loadingLabel = new QLabel (this);<\/p><p>loadingLabel->setGeometry (0, 0, width (), height ());<\/p><p>loadingLabel->setText («Пожалуйста, подождите. «);<\/p><p>loadingLabel->setStyleSheet («background: #fff; «);<\/p><p>loadingLabel->setAlignment (Qt: AlignCenter);<\/p><p>loadingLabel->show ();<\/p><p>Panel* label = (Panel*) sender ();<\/p><p>currentServer = &serverList [label]; <\/p><p>auto socket = new QWebSocket ();<\/p><p>socket->open (QUrl («ws: // «+ currentServer->ip + «: 64 178»));<\/p><p>connect (socket, SIGNAL (connected ()), this, SLOT (socketSuccess ()));<\/p><p>connect (socket, SIGNAL (error (QAbstractSocket: SocketError)), this, SLOT (socketError ()));<\/p><p>}<\/p><p>void Monitor: socketSuccess () {<\/p><p>loadingLabel->deleteLater ();<\/p><p>getBackground ();<\/p><p>auto socket = (QWebSocket*) sender ();<\/p><p>QJsonObject obj;<\/p><p>obj. insert («command», QJsonValue («get-template»));<\/p><p>obj. insert («password», QJsonValue (currentServer->password));<\/p><p>QJsonDocument doc;<\/p><p>doc. setObject (obj);<\/p><p>socket->sendTextMessage (doc. toJson (). replace («n», «»));<\/p><p>connect (socket, SIGNAL (textMessageReceived (QString)), this, SLOT (serverAnswered (QString)));<\/p><p>connect (socket, SIGNAL (binaryMessageReceived (QByteArray)), this, SLOT (templateCame (QByteArray)));<\/p><p>}<\/p><p>void Monitor: socketError () {<\/p><p>loadingLabel->hide ();<\/p><p>if (updateTimer)<\/p><p>updateTimer->stop ();<\/p><p>for (QObject* child: templateParent->children ()) {<\/p><p>((QWidget*) child) — >hide ();<\/p><p>}<\/p><p>templateParent->deleteLater ();<\/p><p>templateParent = new QWidget (this);<\/p><p>if (connected)<\/p><p>paintControls ();<\/p><p>((QWebSocket*) sender ()) — >close ();<\/p><p>QMessageBox: critical (this, «Ошибка», «Нет соединения с сервером.», QMessageBox: Ok);<\/p><p>connected = false;<\/p><p>}<\/p><p>void Monitor: templateCame (QByteArray templateData) {<\/p><p>addButton->setVisible (false);<\/p><p>cWidget->setVisible (false);<\/p><p>loadTemplate (templateData);<\/p><p>templateLoaded = true;<\/p><p>startUpdateTimer ();<\/p><p>connected = true;<\/p><p>if (backgroundLoaded)<\/p><p>applyBackground ();<\/p><p>}<\/p><p>void Monitor: startUpdateTimer () {<\/p><p>updateTimer->singleShot (2500, this, SLOT (updateInfo ()));<\/p><p>}<\/p><p>void Monitor: updateInfo () {<\/p><p>mainSocket = new QWebSocket ();<\/p><p>mainSocket->open (QUrl («ws: // «+ currentServer->ip + «: 64 178»));<\/p><p>connect (mainSocket, SIGNAL (connected ()), this, SLOT (updateStart ()));<\/p><p>connect (mainSocket, SIGNAL (textMessageReceived (QString)), this, SLOT (updateCame (QString)));<\/p><p>updateTimer->singleShot (2500, this, SLOT (updateInfo ()));<\/p><p>}<\/p><p>void Monitor: updateStart () {<\/p><p>auto socket = (QWebSocket*) sender ();<\/p><p>QJsonObject obj;<\/p><p>obj. insert («command», QJsonValue («update»));<\/p><p>obj. insert («password», QJsonValue (currentServer->password));<\/p><p>obj. insert («count», QJsonValue (values. count () + graphs. count ()));<\/p><p>int fi = 0;<\/p><p>for (fi = 0; fi < values. count (); fi++) {<\/p><p>QString command = values. values (). at (fi). values (). at (0);<\/p><p>obj. insert («execute» + QString: number (fi), QJsonValue (command));<\/p><p>}<\/p><p>for (int i = 0; i < graphs. count (); i++) {<\/p><p>QString command = graphs. at (i). keys (). at (0) — >property («command»). toString ();<\/p><p>obj. insert («execute» + QString: number (i + fi), QJsonValue (command));<\/p><p>}<\/p><p>QJsonDocument doc;<\/p><p>doc. setObject (obj);<\/p><p>socket->sendTextMessage (doc. toJson (). replace («n», «»));<\/p><p>}<\/p><p>void Monitor: updateCame (QString message) {<\/p><p>QJsonObject doc = QJsonDocument: fromJson (message. toUtf8 ()). object ();<\/p><p>QDateTime now = QDateTime: currentDateTime ();<\/p><p>QFile logFile (logDir + logFileName);<\/p><p>logFile. open (QIODevice: WriteOnly | QIODevice: Append);<\/p><p>logFile. write (QString («[=== «+ now. toString (Qt: SystemLocaleLongDate) + «===] n»). toStdString (). c_str ());<\/p><p>QString logString = «» ;<\/p><p>if (doc [» success» ]. toBool () == true) {<\/p><p>int count = doc [» count» ]. toInt ();<\/p><p>for (int i = 0; i < count; i++) {<\/p><p>QString value = doc [» execute» + QString: number (i)]. toString (). trimmed ();<\/p><p>if (values. count () >= (i + 1)) {<\/p><p>QLabel* label = values. values (). at (i). keys (). at (0);<\/p><p>label->setText (value);<\/p><p>auto line = (QLabel*) label->parentWidget ();<\/p><p>auto children = line->children ();<\/p><p>int x = 0;<\/p><p>for (QObject* _child: children) {<\/p><p>auto child = (QLabel*) _child;<\/p><p>child->adjustSize ();<\/p><p>child->move (x, child->geometry (). y ());<\/p><p>x += child->width ();<\/p><p>}<\/p><p>line->setFixedWidth (x);<\/p><p>if (! label->property («log»). toString (). isEmpty ()) {<\/p><p>logString += label->property («log»). toString () + «» + value + «n» ;<\/p><p>}<\/p><p>auto _parent = (Panel*) line->parentWidget ();<\/p><p>auto _aligment = ((Panel*) line->parentWidget ()) — >alignment ();<\/p><p>if (_aligment == Qt: AlignCenter)<\/p><p>line->move (_parent->width () / 2 — line->width () / 2, line->geometry (). y ());<\/p><p>else if (_aligment == Qt: AlignRight) {<\/p><p>line->move (_parent->width () — line->width () — _parent->property («padding»). toString (). toInt (), line->geometry (). y ());<\/p><p>} else {<\/p><p>line->move (_parent->property («padding»). toString (). toInt (), line->geometry (). y ());<\/p><p>}<\/p><p>} else {<\/p><p>QGraphicsView* graphParent = graphs. at (i — values. count ()). keys (). at (0);<\/p><p>QVector<float>* graphValues = &graphs [i — values. count ()] [graphParent]; <\/p><p>int graphHeight = graphParent->height ();<\/p><p>int graphWidth = graphParent->width ();<\/p><p>int valuesCount = graphParent->property («valuesCount»). toString (). toInt ();<\/p><p>graphValues->push_back (value. toFloat ());<\/p><p>if (graphValues->count () > valuesCount) {<\/p><p>graphValues->removeFirst ();<\/p><p>}<\/p><p>float maxValue = 0, minValue = 0;<\/p><p>maxValue = minValue = graphValues->at (0);<\/p><p>for (float value: *graphValues) {<\/p><p>if (maxValue < value)<\/p><p>maxValue = value;<\/p><p>if (minValue > value)<\/p><p>minValue = value;<\/p><p>}<\/p><p>float highestPoint = maxValue / 0.9;<\/p><p>float lowestPoint = minValue * 0.9;<\/p><p>QGraphicsScene* scene = new QGraphicsScene (graphParent);<\/p><p>scene->setSceneRect (0, 0, graphWidth — 2, graphHeight — 2); <\/p><p>QPen pen;<\/p><p>pen. setColor (QColor (graphParent->property («lineColor»). toString ()));<\/p><p>pen. setWidth (graphParent->property («lineSize»). toInt ());<\/p><p>QPolygonF poly;<\/p><p>poly. append (QPointF (0, graphHeight));<\/p><p>graphParent->setRenderHint (QPainter: Antialiasing, true);<\/p><p>graphParent->setRenderHint (QPainter: SmoothPixmapTransform, true);<\/p><p>graphParent->setRenderHint (QPainter: HighQualityAntialiasing, true);<\/p><p>float minY = graphHeight * 0.1, height = graphHeight;<\/p><p>int gX = 0, gY = minY + ((graphValues->at (0) — lowestPoint) * 100/ (highestPoint — lowestPoint)) * graphHeight / 100;<\/p><p>for (int i = 0; i < graphValues->count (); i++) {<\/p><p>float current = graphValues->at (i);<\/p><p>float tempX = graphWidth / (valuesCount — 2) * i;<\/p><p>float tempY = minY + ((current — lowestPoint) * 100/ (highestPoint — lowestPoint)) * graphHeight * 0.9/100;<\/p><p>if (graphValues->count () == valuesCount) {<\/p><p>poly. append (QPointF (tempX, height — tempY));<\/p><p>}<\/p><p>scene->addLine (gX, height — gY, tempX, height — tempY, pen);<\/p><p>gX = tempX;<\/p><p>gY = tempY;<\/p><p>}<\/p><p>if (graphValues->count () >= (valuesCount — 1) && ! graphParent->property («fill»). toString (). isEmpty ()) {<\/p><p>QGraphicsPolygonItem* item = new QGraphicsPolygonItem ();<\/p><p>QString fillColor = graphParent->property («fillColor»). toString ();<\/p><p>poly. append (QPointF (graphWidth, graphHeight));<\/p><p>item->setPolygon (poly);<\/p><p>item->setPen (QPen (QColor (0, 0, 0, 0)));<\/p><p>item->setBrush (QBrush (QColor (fillColor. isEmpty ()?» green»: fillColor)));<\/p><p>scene->addItem (item);<\/p><p>}<\/p><p>QColor gridColor (graphParent->property («gridColor»). toString ());<\/p><p>gridColor. setAlpha (0.7);<\/p><p>QPen gridPen;<\/p><p>pen. setColor (gridColor);<\/p><p>gridPen. setWidthF (0.14);<\/p><p>for (int i = 0; i < valuesCount; i++) {<\/p><p>float gridX = graphWidth / (valuesCount — 2) * i;<\/p><p>scene->addLine (gridX, 0, gridX, graphHeight, gridPen);<\/p><p>}<\/p><p>for (int i = 1; i < 11; i++)<\/p><p>scene->addLine (0, graphHeight * i / 10, graphWidth, graphHeight * i / 10, gridPen);<\/p><p>QString maxValueToShow = QString: number (roundDouble (maxValue,<\/p><p>2));<\/p><p>QString minValueToShow = QString: number (roundDouble (minValue,<\/p><p>2));<\/p><p>QFont textFont;<\/p><p>textFont. setPixelSize (graphHeight * 0.18);<\/p><p>// top value<\/p><p>QPolygonF topValue;<\/p><p>topValue. append (QPointF (graphWidth — graphHeight * 0.1, graphHeight * 0.1));<\/p><p>topValue. append (QPointF (graphWidth — graphHeight * 0.1, graphHeight * 0.3));<\/p><p>topValue. append (QPointF (graphWidth * 0.85 — graphHeight * 0.1, graphHeight * 0.3));<\/p><p>topValue. append (QPointF (graphWidth * 0.85 — graphHeight * 0.1, graphHeight * 0.1));<\/p><p>QGraphicsPolygonItem* topValueItem = new QGraphicsPolygonItem ();<\/p><p>topValueItem->setPolygon (topValue);<\/p><p>topValueItem->setPen (gridPen);<\/p><p>topValueItem->setBrush (QBrush (QColor («black»)));<\/p><p>scene->addItem (topValueItem);<\/p><p>QGraphicsTextItem* topValueText = new QGraphicsTextItem (maxValueToShow);<\/p><p>topValueText->setFont (textFont);<\/p><p>topValueText->setDefaultTextColor (QColor («white»));<\/p><p>topValueText->adjustSize ();<\/p><p>QRectF topRegion = topValueText->boundingRect ();<\/p><p>float topRegionWidth = topRegion. width ();<\/p><p>float topRegionHeight = topRegion. height ();<\/p><p>topValueText->setPos (graphWidth * 0.85 — graphHeight * 0.1 + graphWidth * 0.15/2 — topRegionWidth / 2, graphHeight * 0.1 + graphHeight * 0.2/2 — topRegionHeight / 2);<\/p><p>scene->addItem (topValueText);<\/p><p>// bottom value<\/p><p>QPolygonF bottomValue;<\/p><p>bottomValue. append (QPointF (graphWidth — graphHeight * 0.1, graphHeight * 0.9));<\/p><p>bottomValue. append (QPointF (graphWidth — graphHeight * 0.1, graphHeight * 0.7));<\/p><p>bottomValue. append (QPointF (graphWidth * 0.85 — graphHeight * 0.1, graphHeight * 0.7));<\/p><p>bottomValue. append (QPointF (graphWidth * 0.85 — graphHeight * 0.1, graphHeight * 0.9));<\/p><p>QGraphicsPolygonItem* bottomValueItem = new QGraphicsPolygonItem ();<\/p><p>bottomValueItem->setPolygon (bottomValue);<\/p><p>bottomValueItem->setPen (gridPen);<\/p><p>bottomValueItem->setBrush (QBrush (QColor («black»)));<\/p><p>scene->addItem (bottomValueItem);<\/p><p>QGraphicsTextItem* bottomValueText = new QGraphicsTextItem (minValueToShow);<\/p><p>bottomValueText->setFont (textFont);<\/p><p>bottomValueText->setDefaultTextColor (QColor («white»));<\/p><p>bottomValueText->adjustSize ();<\/p><p>QRectF bottomRegion = bottomValueText->boundingRect ();<\/p><p>float bottomRegionWidth = bottomRegion. width ();<\/p><p>float bottomRegionHeight = bottomRegion. height ();<\/p><p>bottomValueText->setPos (graphWidth * 0.85 — graphHeight * 0.1 + graphWidth * 0.15/2 — bottomRegionWidth / 2, graphHeight * 0.7 + graphHeight * 0.2/2 — bottomRegionHeight / 2);<\/p><p>scene->addItem (bottomValueText);<\/p><p>graphParent->setScene (scene);<\/p><p>}<\/p><p>}<\/p><p>}<\/p><p>logFile. write (QString (logString + «nn»). toStdString (). c_str ());<\/p><p>logFile. close ();<\/p><p>((QWebSocket*) sender ()) — >close ();<\/p><p>}<\/p><p>void Monitor: getBackground () {<\/p><p>auto socket = new QWebSocket ();<\/p><p>socket->open (QUrl («ws: // «+ currentServer->ip + «: 64 178»));<\/p><p>connect (socket, &QWebSocket: connected, [=] () {<\/p><p>QJsonObject obj;<\/p><p>obj. insert («command», QJsonValue («get-background»));<\/p><p>obj. insert («password», QJsonValue (currentServer->password));<\/p><p>QJsonDocument doc;<\/p><p>doc. setObject (obj);<\/p><p>socket->sendTextMessage (doc. toJson ());<\/p><p>});<\/p><p>connect (socket, SIGNAL (binaryMessageReceived (QByteArray)), this, SLOT (gotBackground (QByteArray)));<\/p><p>}<\/p><p>void Monitor: gotBackground (QByteArray data) {<\/p><p>backgroundLoaded = true;<\/p><p>bg = true;<\/p><p>background = data;<\/p><p>((QWebSocket*) sender ()) — >close ();<\/p><p>if (templateLoaded)<\/p><p>applyBackground ();<\/p><p>}<\/p><p>void Monitor: gotBackgroundError (QString data) {<\/p><p>bg = false;<\/p><p>Q_UNUSED (data);<\/p><p>}<\/p><p>void Monitor: serverAnswered (QString message) {<\/p><p>QJsonObject doc = QJsonDocument: fromJson (message. toUtf8 ()). object ();<\/p><p>if (doc [» success» ]. toBool () == false) {<\/p><p>QMessageBox: critical (this, «Ошибка», «Ошибка подключения: проверьте пароль.», QMessageBox: Ok);<\/p><p>}<\/p><p>((QWebSocket*) sender ()) — >close ();<\/p><p>}<\/p><p>void Monitor: selectClicked (int index) {<\/p><p>QComboBox* select = (QComboBox*) sender ();<\/p><p>QString command = commands. value (select). value (index);<\/p><p>auto socket = new QWebSocket ();<\/p><p>socket->open (QUrl («ws: // «+ currentServer->ip + «: 64 178»));<\/p><p>connect (socket, &QWebSocket: connected, [=] () {<\/p><p>QJsonObject obj;<\/p><p>obj. insert («command», QJsonValue («execute»));<\/p><p>obj. insert («password», QJsonValue (currentServer->password));<\/p><p>obj. insert («execute», QJsonValue (command));<\/p><p>QJsonDocument doc;<\/p><p>doc. setObject (obj);<\/p><p>socket->sendTextMessage (doc. toJson (). replace («n», «»));<\/p><p>socket->close ();<\/p><p>});<\/p><p>select->setCurrentIndex (-1);<\/p><p>select->clearFocus ();<\/p><p>}<\/p><p>void Monitor: applyBackground () {<\/p><p>QLabel* backgroundLabel = new QLabel (templateParent);<\/p><p>backgroundLabel->setGeometry (0, 0, width (), height ());<\/p><p>QPixmap px;<\/p><p>px. loadFromData (background, «jpg»);<\/p><p>backgroundLabel->setPixmap (px. scaled (width (), height ()));<\/p><p>backgroundLabel->lower ();<\/p><p>backgroundLabel->show ();<\/p><p>}<\/p><p>bool Monitor: eventFilter (QObject *sender, QEvent *event) {<\/p><p>if (event->type () == QEvent: ActivationChange) {<\/p><p>if (firstLoad) {<\/p><p>paintControls ();<\/p><p>firstLoad = false;<\/p><p>}<\/p><p>}<\/p><p>return QMainWindow: eventFilter (sender, event);<\/p><p>}<\/p><p>void Monitor: keyReleaseEvent (QKeyEvent *event) {<\/p><p>if (((QKeyEvent*) event) — >key () == Qt: Key_Back) {<\/p><p>if (! connected) {<\/p><p>qApp->quit ();<\/p><p>return;<\/p><p>}<\/p><p>if (updateTimer)<\/p><p>updateTimer->stop ();<\/p><p>for (QObject* child: templateParent->children ()) {<\/p><p>((QWidget*) child) — >hide ();<\/p><p>}<\/p><p>templateParent->deleteLater ();<\/p><p>templateParent = new QWidget (this);<\/p><p>paintControls ();<\/p><p>mainSocket->close ();<\/p><p>connected = false;<\/p><p>event->accept ();<\/p><p>return;<\/p><p>}<\/p><p>}<\/p><p>Monitor: ~Monitor () {<\/p><p>}<\/p><p>// файл clickablelabel. h<\/p><p>#ifndef CLICKABLELABEL<\/p><p>#define CLICKABLELABEL<\/p><p>#include <QLabel><\/p><p>#include <QMouseEvent><\/p><p>class ClickableLabel: public QLabel {<\/p><p>Q_OBJECT<\/p><p>public:<\/p><p>ClickableLabel (QWidget* parent = 0);<\/p><p>~ClickableLabel () {}<\/p><p>signals:<\/p><p>void clicked ();<\/p><p>protected:<\/p><p>void mousePressEvent (QMouseEvent * event);<\/p><p>};<\/p><p>#endif // CLICKABLELABEL<\/p><p>// файл clickablelabel. cpp<\/p><p>#include «clickablelabel. h» <\/p><p>ClickableLabel: ClickableLabel (QWidget* parent): QLabel (parent) {<\/p><p>}<\/p><p>void ClickableLabel: mousePressEvent (QMouseEvent* /*event*/) {<\/p><p>emit clicked ();<\/p><p>}<\/p><p>// файл myserver. h<\/p><p>#ifndef MYSERVER<\/p><p>#define MYSERVER<\/p><p>#include <QtCore><\/p><p>#include <QtNetwork><\/p><p>#include <QtWebSockets><\/p><p>#include <QJsonDocument><\/p><p>class MyServer: public QObject {<\/p><p>Q_OBJECT<\/p><p>public:<\/p><p>explicit MyServer (int port, QString password, QByteArray templateData, QByteArray bg = «») {<\/p><p>server = new QWebSocketServer («TDM Server», QWebSocketServer: NonSecureMode, this);<\/p><p>server->listen (QHostAddress: Any, port);<\/p><p>this->templateData = templateData;<\/p><p>this->password = password;<\/p><p>if (bg! = «») {<\/p><p>this->bg = true;<\/p><p>this->background = bg;<\/p><p>}<\/p><p>connect (server, SIGNAL (newConnection ()), this, SLOT (clientConnected ()));<\/p><p>}<\/p><p>~MyServer () {}<\/p><p>private:<\/p><p>QWebSocketServer* server;<\/p><p>QByteArray templateData;<\/p><p>QByteArray background;<\/p><p>QString password;<\/p><p>private slots:<\/p><p>void clientConnected () {<\/p><p>QWebSocket* clientSocket = server->nextPendingConnection ();<\/p><p>connect (clientSocket, SIGNAL (textMessageReceived (QString)), this, SLOT (slotReadClient (QString)));<\/p><p>}<\/p><p>void slotReadClient (QString message) {<\/p><p>QWebSocket* clientSocket = (QWebSocket*) sender ();<\/p><p>QJsonDocument doc = QJsonDocument: fromJson (message. toUtf8 ());<\/p><p>auto command = doc. object () [» command» ]. toString ();<\/p><p>auto pass = doc. object () [» password» ]. toString ();<\/p><p>if (pass! = password) {<\/p><p>clientSocket->sendTextMessage («{success: false, error: «Wrong password» }»);<\/p><p>return;<\/p><p>}<\/p><p>if (command == «get-background» && bg) {<\/p><p>clientSocket->sendBinaryMessage (background);<\/p><p>} else if (command == «get-background» &&! bg) {<\/p><p>clientSocket->sendTextMessage («{success: false, error: «No background. «}»);<\/p><p>}<\/p><p>if (command == «get-template») {<\/p><p>clientSocket->sendBinaryMessage (templateData);<\/p><p>}<\/p><p>if (command == «update») {<\/p><p>auto count = doc. object () [» count» ]. toInt ();<\/p><p>QString answer;<\/p><p>QJsonDocument json;<\/p><p>QJsonObject obj;<\/p><p>obj [» success» ] = QJsonValue (true);<\/p><p>obj [» count» ] = QJsonValue (count);<\/p><p>for (int i = 0; i < count; i++) {<\/p><p>auto execute = doc. object () [» execute» + QString: number (i)]. toString ();<\/p><p>QProcess* process = new QProcess ();<\/p><p>process->start («/bin/bash», QStringList () << «-c» <<<\/p><p>» echo $ («+ execute + «)»);<\/p><p>process->waitForFinished (1000);<\/p><p>auto value = process->readAll (). trimmed ();<\/p><p>obj [» execute» + QString: number (i)] = QJsonValue (value. toStdString (). c_str ());<\/p><p>}<\/p><p>json. setObject (obj);<\/p><p>answer = json. toJson ();<\/p><p>clientSocket->sendTextMessage (answer);<\/p><p>}<\/p><p>if (command == «execute») {<\/p><p>auto execute = doc. object () [» execute» ]. toString ();<\/p><p>QProcess* process = new QProcess ();<\/p><p>process->start («/bin/bash», QStringList () << «-c» << execute);<\/p><p>}<\/p><p>}<\/p><p>};<\/p><p>#endif // MYSERVER<\/p><p>// файл panel. h<\/p><p>#ifndef PANEL_H<\/p><p>#define PANEL_H<\/p><p>#include <QMainWindow><\/p><p>#include <QLabel><\/p><p>#include <clickablelabel. h><\/p><p>class Panel: public ClickableLabel {<\/p><p>Q_OBJECT<\/p><p>public:<\/p><p>Panel (QWidget *parent = 0);<\/p><p>void addStyle (QString style);<\/p><p>void setHoverBackground (QString bg);<\/p><p>~Panel ();<\/p><p>private:<\/p><p>QString style;<\/p><p>};<\/p><p>#endif // PANEL_H<\/p><p>// файл panel. cpp<\/p><p>#include <QtCore><\/p><p>#include <QtWidgets><\/p><p>#include «panel. h» <\/p><p>Panel: Panel (QWidget *parent): ClickableLabel (parent) {<\/p><p>style = «Panel { border: 1px solid #444; background: #777; border-radius: 25px; }» ;<\/p><p>setStyleSheet (style);<\/p><p>}<\/p><p>void Panel: addStyle (QString style) {<\/p><p>this->style = this->style. mid (0, this->style. length () — 1);<\/p><p>this->style += style + «}» ;<\/p><p>setStyleSheet (this->style);<\/p><p>}<\/p><p>Panel: ~Panel () {<\/p><p>}<\/p><p>// файл TDM. pro<\/p><p>QT += core gui xml websockets<\/p><p>greaterThan (QT_MAJOR_VERSION,<\/p><p>4): QT += widgets<\/p><p>TARGET = TDM<\/p><p>TEMPLATE = app<\/p><p>SOURCES += main. cpp<\/p><p>monitor. cpp <\/p><p>panel. cpp <\/p><p>clickablelabel. cpp<\/p><p>HEADERS += monitor. h <\/p><p>panel. h <\/p><p>other. h <\/p><p>clickablelabel. h <\/p><p>myserver. h<\/p><p>DISTFILES += default. tpl<\/p><p>CONFIG += C++11<\/p><p>RESOURCES += resources. qrc<\/p><p>LIBS += - L/usr/lib/i386-linux-gnu/mesa<\/p><p>В даному експлуатаційному документі наведено керівництво оператора щодо застосування та експлуатації додатку «кросплатформовий клієнт-серверний додаток для віддаленого моніторингу та управління персональним комп’ютером — TDM» .<\/p><p>У даному програмному документі, в розділі «Призначення програми» вказані відомості про призначення програми та інформація, достатня для розуміння функцій додатку та його експлуатації.<\/p><p>В розділі «Умови виконання програми» зазначено умови, необхідні для роботи додатку (мінімальний склад апаратних і програмних засобів тощо).<\/p><p>В даному програмному документі, в розділі «Виконання програми» вказана послідовність дій оператора, що забезпечують завантаження, запуск, виконання і завершення програми, наведений опис функцій, формату і можливих варіантів команд, за допомогою яких оператор здійснює завантаження і управляє виконанням програми, а також відповіді програми на ці команди.<\/p><p>У розділі «Повідомлення оператору» наведено тексти повідомлень, що видаються в ході виконання програми, опис їх змісту та відповідні дії оператора.<\/p><p>1 ПРИЗНАЧЕННЯ ПРОГРАМИ Додаток під назвою «кросплатформовий клієнт-серверний додаток для віддаленого моніторингу та управління персональним комп’ютером — TDM» призначений для віддаленого нагляду за комп’ютером без наявності фізичного доступу, для управління та виправлення помилок, що можуть виникати на комп’ютері, а також для ведення статистики деяких даних.<\/p><p>2 УМОВИ ВИКОНАННЯ ПРОГРАМИ Програма складається з клієнтської та серверної частин, кожна з яких має свои вимоги до програмної та апаратної частини.<\/p><p>Мінімальна конфігурація для клієнтської частини:<\/p><p>комп'ютер або смартфон з операційною системою Android 3.2 (або быльше) чи Windows XP (або більше);<\/p><p>процесор з тактовою частотою 1 ГГц;<\/p><p>512 Мб оперативної пам’яті;<\/p><p>монітор або дісплей з розрішенням 854×480.<\/p><p>Мінімальна конфігурація для серверної частини:<\/p><p>комп'ютер з операційною системою на базі GNU/Linux;<\/p><p>процесор з тактовою частотою 0.6 ГГц;<\/p><p>128 Мб оперативної пам’яті.<\/p><p>3 ВИКОНАННЯ ПРОГРАМИ Робота з серверною частиною програми починається з її запуском через термінал. Для того, чтоб запустити додаток у режимі серверу, треба вказати аргумент «-s». Також оператор повинен вказати такі аргументи, як: пароль для входу («-p»), файл шаблону («-t»), файл-картинка з фоном («-b»). Після цього сервер запускається та починає приймати з'єднання клієнтів.<\/p><p>Рисунок 3.1 — Запуск серверу Робота з клієнтською частиною програми починається з того, що робітник повинен запустити додаток. Перше, що він побачить на екрані - список серверів, якщо вони вже були додані, та кнопку з піктограмую «Додати». При натисканні на кнопку відкривається спеціальна форма для додавання серверу, де оператор повинен заповнити три поля: IP-адрес серверу, пароль для підключення та назва серверу. Під полями на формі знаходяться дві кнопки з піктограмами «Зберегти» та «Закрити», зправа наліво.<\/p><p>Рисунок 3.2 — Головний екран клієнтської частини При натисканні на один з серверів, додаток спробує підключитись до нього. Якщо йому це вдасться, оператор побачить шаблон у зрозумілій для людини формі, тобто фон та елементи керування. Дальніше використання програми залежить тільки вид шаблону, що був вказаний на сервері.<\/p><p>Рисунок 3.3 — Адаптований шаблон<\/p><p>4 ПОВІДОМЛЕННЯ ОПЕРАТОРУ Якщо користувач робить некоректні дії, то в програмі будуть виводитися підказки та попередження. Наприклад, при додаванні інформації, якщо будут введені некоректні дані - йому буде виедена на єкран відповідна підказка.<\/p><p>Рисунок 4.1 — Помилка при невірному паролі<\/p><p>Рисунок 4.2 — Підключення до серверу, що не відповідає<\/p><p>Рисунок 4.3 — У шаблоні не вказана товщина лінії для графіку<\/p><H1><b><i><b><i>Перелік посилань<\/b><\/i><\/H1><p><\/b><\/i>1. Задушко П.І. Основи Qt: створення мультиплатформового додатку. — К.: НМК ВО, 2013. — 176 с.<\/p><H1>2. ГОСТ 7.1−84. Библиографическое описание документа. Общие требования и правила составления.<\/H1><p>3. Ільдар Хабибулин. Самовчитель з XML. — К.: Наук. Думка, 2011. — 542 с.<\/p><p>4. Елементи інформатики: довідник, В. С. Височанський, А.І. Кардаш, В.С. Костєв, В.В. Черняхівський. — К.: Наук. Думка, 2012. — 224 с.<\/p><H1>5. Задрозький А. В. Технологія кліент-сервер. — Л.: Книга, 2014. — 164 с.<\/H1><p>6. Околевич В. В. Qt 5 на прикладах. — К.: Новий дім, 2009. — 311 с.<\/p><H1>7. Шеховцов В. А. Операційні системи. — Л.: Теза, 2011. — 221 с.<\/H1><p>8. Литвиненко Н. А. Технология программирования на С++. К.: Наук. Думка, 2013. — 401 с.<\/p><p>9. Азов В.І. С++: кросплатформова розробка. — Д.: Пристань, 2012. — 144 с.<\/p><p>10. Рамбо Д.І. UML 2.0. Объектно-ориентированное моделирование и разработка. — П.: Пітер, 2008. — 287 с.<\/p><p>11. Васильчук М. В. та ін. Основи охорони праці. — К.: Просвіта, 2009. — 208 с.<\/p><H1>12. Бойчик I.М. Економіка підприємства. — К.: Атіка, 2004. — 480 с.<\/H1>