Gui-додатки на perl за допомогою wxwidgets

Розглянуто основи написання GUI-додатків за допомогою wxWidgets

Написання GUI-додатків на Perl нічим не відрізняється від написання на інших динамічних мовами. Все залежить від якості обгорток над оригінальними бібліотеками та їх своєчасного оновлення.

Чому wxWidgets?

wxWidgets є по-справжньому крос-платформних GUI-інструментарієм. На відміну від, наприклад, Qt. який теж начебто є крос-платформних, wxWidget на запускаються платформах використовує рідні бібліотеки, а не намагається їх емулювати. Таким чином додатки виглядають не Cовсем однаково, але зовсім звично для своєї графічної оболонки.

Налаштування оточення

Для розробки я використовую платформу GNU / Linux. Тому далі наведено установка wxWidgets саме для моєї ОС. Найпростіше встановлювати бібліотеки з дистрибутивних пакетів, на прикладі Debian:

Звичайно, завжди можна встановити і з CPAN, але тоді доведеться багато компілювати і можна наштовхнутися на несумісність версій.

перше додаток

Стандартним першим додатком буде вікно на якому написано "Hello, world!":

Wx :: Frame це вікно, у якого може бути змінено розмір, у нього може бути статусний рядок, а також меню. Тобто це вікно загального призначення. Крім Wx :: Frame існує також Wx :: Dialog і інші. Для додавання візуальних елементів можна скористатися різними класами і методами wxWidgets. Наприклад, щоб додати кнопку, яка закриває додаток, напишемо наступний код:

Всі методи, події і т.д. добре описані в документації wxWidgets. Не будемо на цьому детально зупинятися. Розглянемо загальний підхід в написанні GUI-додатків.

Генератори XML-інтерфейсу

Для невеликого додатки це цілком допустимо, також як і для простого Perl-скрипта можна все записати в один файл. Однак це дуже незручно для великих додатків з великою кількістю вікон, діалогів, складною логікою.

Для графічних додатків застосовують ті ж самі методи, що й для веб-додатків - MVC, або поділ бізнес-логіки, відображення і управління. Так само можна вчинити і з GUI-програмою.

Для побудови інтерфейсу краще скористатися спеціальними програмами, які генерують XML-налаштування (XRC-файли), які, будучи завантаженими в додатку, перетворюються в графічний інтерфейс. Це набагато легше підтримувати і простіше змінювати.

Для wxWidgets існує кілька таких генераторів. Найбільш повним є wxFormBuilder. Він дозволяє створювати всілякі елементи, вказувати їх розташування на вікнах і т.д.

Наприклад, XRC-файл для попереднього додатки може виглядати так:

Тепер завантажимо цю конфігурацію в додатку:

Для того, щоб дістати об'єкт Wx :: Frame. використовуємо метод LoadFrame:

А для того, щоб дістати об'єкт кнопки, спочатку отримуємо її id по імені:

А потім прив'язуємо подія.

Завжди варто зрозумілим чином називати всі елементи, а не залишати щось на зразок m_Button_1. це зробить керуючий код істотно зрозуміліше.

Поділ на класи

Як і будь-який Perl-додаток, поділ на окремі пакети і класи спрощує розуміння коду, робить можливим тестування окремих класів, а також дозволяє легко наслідувати і змінювати поведінку графічних елементів.

Розділимо наш додаток на кілька складових.

Основний клас додатки

Завдання основого класу виконати завантаження налаштувань, створити основне вікно і показати його.

Клас основного вікна

Завдання цього класу налаштувати свого вікна, тобто прописати всі події, в даному випадку обробити натискання на кнопку CloseButton.

скрипт запуску

Скрипт запуску app.pl є вхідний точкою для запуску програми.

За допомогою такої декомпозиції кожен клас займається своєю справою, а структура додатка виглядає наступним чином:

Можна у кожного класу зробити якийсь унікальний префікс, наприклад GUI, щоб їх відрізняти від звичайних Perl-класів, які будуть займатися логікою програми.

Генератори Perl-коду

wxFormBuilder. як було вже зазначено, може генерувати XML-представлення, однак він дозволяє гененіровать і код. На жаль, з коробки немає підтримки генерації Perl-коду. Однак, розробники Padre реалізували власний генератор Perl-коду з файлу проекту wxFormBuilder. Для цього будуть потрібні два модуля: FBP і FBP :: Perl. Написавши найпростіший скрипт для створення класів, отримаємо на виході дерево файлів, де кожен - це окреме вікно:

Плюс цього підходу ще й в тому, що немає необхідності вручну прив'язувати сигнали до елементів. Вказавши в wxFormBuilder назву обробника, PBP :: Perl правильно згенерує відповідний код. Ось як, наприклад, виглядає клас основної форми:

Як же використовувати ці класи? Додавати в них функціонал не варто, тому як вони автоматично генеруються з файлу проекту. Найбільш правильним рішенням буде успадкувати від сгененірованного класу і там вже імплементувати потрібний код. Крім того, має сенс генерувати класи з певним префіксом, щоб було зрозуміло, які класи автоматичні, а які написані вручну.

Ось так виглядає реалізація обробника події OnClick в дочірньому класі:

Проект з використанням згенерованих класів виглядає наступним чином:

simple.fbp це файл проекту wxFormBuilder, а generate.pl - скрипт для генерації.

Модуль MyApp.pm доведеться теж написати вручну, але його код гранично простий:

А app.pl залишається тим же, що і в разі використання XML-вистави.

поділ логіки

Як уже згадувалося, при написанні графічних програм розділяється власне уявлення і логіка самого додатка. Ідеально, якщо додаток буде реалізовано таким чином, що заміна графічної бібліотеки інший, або ж веб-додатком, або консольним варіантом не спричинить будь-яких або, як мінім, ніяких серйозних змін.

Наприклад, якщо в додатку необхідно зробити запит до веб-сайту для отримання якихось даних, варто виділити це в окремий клас, що не залежить від графічної бібліотеки. Це дозволить набагато простіше його протестувати стандартними засобами. У разі тестування графічних програм це зробити набагато складніше.

Втім, тестувати графічні інтерфейси теж можна і потрібно, як наприклад, за допомогою Selenium тестують і веб-додатки. Для X11 є набір інструментів Xnee. який дозволяє записувати сценарії, а потім виконувати їх в автоматичному режимі.

блокування

Якщо писати серйозні програми на wxWidgets. незабаром ви зіткнетеся з тим, що при виконанні вимагають часу завдань активне вікно блокується і як ніби завмирає. Вся справа в блокуванні. Під час виконання вашого коду wxWidgets чекає, поки він закінчиться.

Стандартним способом вирішення цієї проблеми є використання тредов (потоків, ниток), коли завдання, які необхідно виконати на задньому фоні, виконуються в окремому потоці. У цьому випадку вікно не блокується, а після завершення завдання основне вікно отримує відповідь і обробляє його.

Крім потоків можливе використання асинхронних фреймворків по типу POE. На Linux можливе використання wxGTK. а разом з ним AnyEvent. В цьому випадку доведеться писати подієво-орієнтований код з усіма перевагами і недоліками останнього.

Також можливе виконання фонових завдань в окремому процесі за допомогою wxExecute. але це більше підходить для запуску сторонніх додатків.

Виконання завдань в окремому потоці

Найпоширеніший і простий спосіб виконати завдання у фоновому режимі - використовувати потоки. Щоб використовувати потоки з Wx. необхідно, по-перше, переконатися, що perl зібраний з підтримкою threads:

А по-друге, підключити Прагма threads ДО підключення Wx (це варто зробити також в скрипті запуску додатка):

Наприклад, при натисканні на кнопку, ми хочемо виконати якийсь код і оповістити головне додаток про результат. Скелет такого додатка буде виглядати наступним чином:

Змінні з тегом shared необхідні для обміну даними між потоками, так як потоки виконуються одночасно, і використання звичайних змінних небезпечно. Wx сам простежить, що змінні оголошені як shared. убезпечивши таким чином програміста.

У цьому додатку при натисненні на кнопку реєструється обробник завершення події, далі створюється потік для виконання роботи. Коли потік завершується, він сигналізує головному додатком про свої результати. Головне додаток в обробнику, зареєстрованому раніше, отримує дані і виробляє якісь дії для відображення результату.

Проектуючи код таким чином, тобто виконуючи код у фоновому режимі, можна писати звичайні Perl-модулі абсолютно незалежно від графічної бібліотеки.

приклад програми

Для прикладу, напишемо програму, яку отримує від MetaCPAN десять останніх завантажених модулів і відображає їх у вигляді списку.

Спочатку реалізуємо модель, тобто основу програми. У нашому випадку це модуль, який буде отримувати останні додані дистрибутиви. Він може виглядати наступним чином:

Більш докладно про те, як працювати з API MetaCPAN, можна почитати в документації. Там же є безліч прикладів.

відображення

Графічне додаток буде являти собою одне єдине вікно з кнопкою Fetch і списком. При натисканні на кнопку в окремому потоці створюємо об'єкт класу ModulesFetcher і повертаємо результат. Головне графічне додаток обробляє результат і заповнює список.

Скелет всього програми вже описувався нами вище, тому тут покажемо тільки приклад використання стороннього модуля:

У методі work викликається метод fetch на об'єкті моделі, потім результат перетворюється в shared -змінного, і створюється сигнал головного вікна з передачею результату.

У методі done запитуємо отримані дані у події за допомогою методу GetData і потім в циклі додаємо їх в об'єкт списку. Перед цим не забуваємо очистити старі дані.

Писати графічні додатки на Perl можна цілком успішно. За допомогою бібліотеки wxWidgets це ще й просто. Правильно розділяючи модель і відображення, можна домогтися переносимості між різними графічними бібліотеками, а також спростити реалізацію.

Схожі статті