|
|
ОБ’ЄКТНО ОРІЄНТОВАНЕ ПРОГРАМУВАННЯ Електронний посібник |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Модуль 7 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7. Консоль. Файлова система. Графічний інтерфейс
користувача 7.1. Основи вводу-виводу. Робота с консоллю та
файловою системою 7.2. Робота з базами даних. JDBC. Entity Classes 7.3. Створення графічного інтерфейсу користувача 7.4. Обробка подій від інтерфейсних
елементів 7.5. Тонке налагодження інтерфейсу користувача
Потік
вводу даних з консолі можна організувати одним з двох способів:
У цьому випадку дані, що вводяться з консолі,
зчитуються з стандартного потоку вводу, якому відповідає змінна System.in з
пакету java.lang. Іншими словами, змінна System.in посилається
на стандартний потік вводу, яким, за замовчуванням, вважається клавіатура. У
мові Java для реалізації операцій вводу з консолі
використовується клас InputStreamReader. Цей клас є
підкласом абстрактного базового класу Reader і призначений для
конвертування байт в символи. Щоб
отримати об’єкт типу InputStreamReader, потрібно створити
екземпляр цього типу за наступною загальною формою:
тут
У випадку консолі, цим потоком виступає System.in. Отже,
для потоку System.in, щоб створити
екземпляр (об’єкт) типу InputStreamReader,
потрібно викликати наступний конструктор
В
пакеті java.lang реалізовано дві змінні, що зв’язані з потоком запису
даних на консоль:
Для
роботи з виведенням на консоль розроблено спеціальний клас PrintStream, який є похідним від класу OutputStream. У цьому класі основними є
методи print() та println(). Щоб
створити потік виводу, зв’язаний з консоллю, потрібно оголосити екземпляр
класу PrintStream. При
створенні екземпляру потрібно зв’язати його з відповідним потоком як показано
в наступному прикладі:
Результат
виконання програми: Hello world! Some error... Як відомо, з консоллю зв’язана стандартна змінна System.in. Щоб прочитати символи з консолі без буферизації, можна
використати можливості класу InputStreamReader. Клас InputStreamReader є підкласом
абстрактного класу Reader. Клас InputStreamReader призначений
для конвертування байт у символи. Основним методом класу
InputStreamReader є метод read(), який
має дві перевантажені реалізації. Перша
реалізація має наступну загальну форму
У цьому випадку метод повертає код введеного символу з консолі. Загальна форма другої
реалізації методу наступна
Тут метод заповнює масив ac типу char[] введеними значеннями
символів з консолі.
Параметр count задає кількість символів, які потрібно вставити у масив ac. Для масиву ac попередьно
має бути виділена пам’ять. Другий варіант методу повертає кількість символів, що можуть бути прочитані. Щоб реалізувати
буферизацію під
час читання символів
з консолі, потрібно екземпляр класу InputStreamReader помістити
в оболонку об’єкту класу BufferedReader. У цьому випадку загальна форма
конструктора класу BufferedReader наступна
Тут потік_читання_введених_даних
– деякий потік даних (файл, консоль тощо). У випадку консолі тут задається екземпляр класу InputStreamReader (дивіться
попередній пункт). Такий підхід
реалізує патерн
Декоратор (Decorator). У патерні
Декоратор екземпляр одного класу
служить оболонкою для екземпляру
іншого класу. Таким чином
відбувається нашаровування
об’єктів. Нехай задано
символьний (текстовий) файл, який потрібно вивести на консоль. Читання рядків
з файлу можна реалізувати з допомогою методу read() класу FileReader. Рядок з файлу читається у наперед визначену ділянку пам’яті – буфер. Щоб визначити
кінець файлу, потрібно використати метод ready() класу FileReader. Якщо кінець файлу, то метод повертає false.
Нехай задано деякий рядок типу String. Потрібно
записати цей рядок у файл
шляхом використання перенаправлення
потоку виводу у файл.
Фрагмент програмного коду, що
здійснює перенаправлення
потоку з рядка в файл, наведено нижче
За цим прикладом можна реалізувати функцію, яка записує масив рядків у файл.
В основі JDBC лежить концепція
так званих драйверів, що дозволяють отримувати з'єднання з базою даних
за спеціально описаним URL. Драйвери можуть завантажуватись динамічно (під час роботи програми). Завантажившись,
драйвер сам реєструє себе й викликається автоматично, коли програма вимагає
URL, що містить протокол, за який драйвер "відповідає". JDBC API містить
два основні типи інтерфейсів: перший – для розробників застосунків і другий
(нижчого рівня) – для розробників драйверів. З'єднання з базою
даних описується класом, що реалізує інтерфейс java.sql.Connection.
Маючи з'єднання з базою даних, можна створювати
об'єкти типу Statement, використовувані для
здійснення запитів до бази даних мовою SQL. Існують такі види
типів Statement, що відрізняються своїм призначенням:
Клас java.sql.ResultSet дозволяє легко обробляти результати запитів.
Цей приклад
використовує вільний драйвер JDBC для MySQL, який легко встановлюється в більшості
дистрибутивів Linux через стандартні репозиторії:
Для реалізації
графічного інтерфейсу (GUI) в Java існують два
основні пакети класів:
Перевагами першого
є простота використання, інтерфейс подібний до інтерфейсу операційної системи
та дещо краща швидкодія, оскільки базується на засобах ОС, щоправда має
обмежений набір графічних елементів. Другий пакет Swing реалізує власний Java-інтерфейс.
Цей пакет створювався на основі AWT, і має набагато більше можливостей та
більшу кількість графічних елементів. Swing-компоненти ще називають полегшеними (англ. lightweight), оскільки
вони написані повністю на Java і, через це платформонезалежні. Принципи роботи із
обома пакетами схожі, тож опанувавши роботу з одним, робота з іншим не матиме
труднощів. Swing містить великий набір
компонентів для розробки графічного інтерфейсу користувача (GUI). Оскільки Swing – це повніший інструментарій ніж AWT, тому основну
увагу ми приділимо саме йому. Робота з AWT компонентами майже аналогічна,
щоправда їх дещо менше. Для розрізнення компонентів інструментаріїв,
компоненти Swing містять літеру "J"
спереду назви (JButton, JPanel тощо). Назви AWT-компонентів не мають цієї
літери спереду. Swing та AWT є частиною JFC (Java
Foundation Classes),
що в свою чергу становить левову частку стандартної платформи Java. Класи Swing розміщуються
в пакеті javax.swing та його підпакетах. Суфікс
-х прийнято ставити для нестандартних розширень, проте конкретно ці
пакети є стандартними, починаючи з JDK 1.2. Вікно верхнього
рівня (таке що не містить в середині іншого вікна) в мові Java
називається фреймом (frame – каркас). У бібліотеці
AWT для цього вікна призначений клас Frame, а в бібліотеці Swing – JFrame. Наступний код
демонструє, як можна створити фрейм розміром 300×200 пікселів:
Проте розміщувати
увесь код в main() поганий
стиль, оскільки, наприклад, коли вам доведеться додавати нові фрейми та інші
елементи, код може стати доволі заплутаним. Крім того, метод main
статичний і потрібно враховувати деякі особливості роботи у статичному
контексті. Тому в main() часто намагаються
залишити лише найнеобхідніше. І взагалі, якщо якийсь графічний елемент
потребує значного коду, то бажано роботу з ним розмістити окремо. В нашому
випадку всю роботу з фреймом можна доручити класу, який розширюватиме клас JFrame. Наступний
переписаний код робить те ж саме, що і попередній. На перший погляд може
здатися, що такий спосіб є доволі незручним, насправді ж у великих проєктах це виправдано.
Програма
складається з двох класів, хоча метод MyFrame() можна б було розмістити і в класі SimpleFrame. Проте, на думку багатьох
програмістів, краще відділяти клас, який запускає програму на виконання, від
класу, в якому описується інтерфейс користувача. Одною з причин такого є
краща читабельність коду програми. Фрейм – це контейнер, в який поміщають всі інші компоненти
(меню, кнопки, прапорці та інші елементи графічного елемента). Сам клас JFrame, який реалізує фрейм
складається з чотирьох областей (pane), що
накладаються одна на одну: коренева область (root pane), область шару (layered pane), прозора область (glass pane) та область вмісту (content
pane). Перші три застосовують для створення та
обслуговування меню. Для роботи з графічними елементами застосовується
область вмісту, в яку і додають компоненти. Додати компонент можна наступним
чином:
Щоправда напряму у
фреймі додавати компоненти не прийнято. Для цього використовується
спеціальний компонент-контейнер – панель (panel),
що додається до фрейму. Після цього в панель можна додавати різні графічні
компоненти. Для початку
спробуємо намалювати прямокутник. Щоб додати відповідну панель, в якій буде здійснюватись малювання, необхідно:
Натиснення кнопки,
закриття вікна, клацання мишкою – все це є прикладами подій,
які отримує операційна система і передає відповідній програмі на обробку.
Програміст повинен передбачити як потрібно обробляти дані події. Розглянемо
як обробка подій реалізовується в Java. В Java запропонована, так звана, модель делегування подій (event delegation model). Джерело події (event
source) породжує подію, після чого вона
передається в обробник подій (event listener – дослівно слухач події). При цьому будь-який
об’єкт може бути призначеним як обробник деякої події. Така модель доволі
гнучка, оскільки кожен програміст може вибрати зручний для нього спосіб
обробки події (де саме її обробляти), проте інколи текст програми може бути
дещо заплутаним для тих хто не звик до такої моделі. Інформація про
подію інкапсулюється в об’єкті події (event object). Всі події
описуються підкласами java.util.EventObject. Як приклади, можна
навести підкласи ActionEvent та WindowEvent. Перші об’єкти породжують кнопки, а другі вікна. Джерела подій
містять методи, які дозволяють зв’язати його з обробниками подій. Коли
виникає подія, джерело повідомляє про неї усіх зареєстрованих обробників.
Обробники подій на основі інформації у об’єкті події визначає як реагувати на
ту чи іншу подію.
Сказане демонструє
наступний фрагмент програми:
Клас, який
реалізовуватиме інтерфейс ActionListener
повинен мати метод actionPerformed() який
в якості параметру отримуватиме об’єкт ActionEvent.
Реалізувати такий
механізм можна кількома способами. Часто також замість створення окремого класу
обробника використовують внутрішні класи і навіть внутрішні
анонімні класи. Також в якості обробника події може виступати і сам
клас, в якому описується графічний інтерфейс користувача. Класи-адаптери
являють собою пусту реалізацію інтерфейсів-слухачів, що мають більше
одного методу. Їх імена складаються із імені події і слова Adapter. Наприклад, для дії з мишею є два
класи-адаптери. Виглядають вони дуже просто:
Замість того щоб
реалізувати інтерфейс, можна розширять ці класи. Крім вже згадуваних трьох
класів, існують ще класи ComponentAdapter, ContainerAdapter, FocusAdapter
і KeyAdapter.
Вперше продемонстровано
Sun Microsystems на Міжнародній конференції Java-розробників
JavaOne у травні 2007. JavaFX містить у собі
набір утиліт, за допомогою яких веб-розробники та дизайнери можуть швидко
створювати та надавати розвинуті інтернет-застосунки для десктопів, мобільних
пристроїв, телебачення та інших платформ. JavaFX складається з JavaFX Script і JavaFX Mobile.
Починаючи з випуску JavaFX 2.0 забезпечено
можливість створення JavaFX-застосунків,
написаних цілком мовою Java. Для розробки застосунків доступний багатий
графічний і мультимедійний API, що спрощує створення візуальних програм.
Цікавою особливістю
є те, що вигляд та поведінку програм, написаних на JavaFX, можно налаштовувати за допомогою каскадних таблиць стилів
(CSS – Cascading Style Sheets). Цей підхід, який історично був першим
застосований для веб-сайтів, дозволяє відокремити зовнішній вигляд програм
(інтерфейс користувача) від реалізації, що дозволяє програмістам
концентруватись на кодуванні. Турбота про графічний інтерфейс тепер лежить на
плечах графічних дизайнерів, які налаштовують зовнішній вигляд за допомогою
скриптової мови FXML та технології CSS, а програмісти зосереджені на розробці
бізнес-логіки додатка. Нижче наведено вигляд додатку із різними
налаштуваннями CSS. Існує два шляхи
створення інтерфейсу користувача з JavaFX:
використовувати файл розмітки FXML чи програмувати все на Java. Для більшості випадків ми будемо
використовувати XML (.fxml). Цей спосіб більше
підходить для збереження роздільності контролера та представлення один від
іншого. В подальшому, ми зможемо використовувати графічний Scene Builder для візуального
редагування нашого XML. А це означає, що нам не потрібно працювати з XML
напряму. Також потрібно
створити основний Java клас, який запускає
наш додаток з RootLayout.fxml. Створений клас
MainApp.java наслідує клас Application
та вміщує два методи. Це базова структура, що потрібна для для запуску JavaFX додатку. Для
нас важливий метод start(Stage primaryStage). Він автоматично викликається коли додаток
запускається з методу main. Як бачите, метод start(...) приймає екземпляр
класу Stage в ролі параметра. На рисунку знизу представлена
структура будь-якого JavaFX додатку:
Це наче театральна
п'єса: Stage є основним контейнером, який, як правило,
представляє вікно з рамками та стандартними кнопками закрити, мінімізувати та
максимізувати. Всередину Stage додається Scene,
яка, звичайно, може бути замінена іншою Scene. Всередину Scene
вже додаються стандартні компоненти типу AnchorPane, TextBox та
інші. Якщо додаток не
може знайти вказаного fxml файлу, ви отримаєте
наступне повідомлення про помилку:
Для вирішення
проблеми перевірте правильність шляхів до файлу та правильність написання
його назви. Детально створення
і функціонування JavaFX-додатків описані в офіційній
документації Java – https://college.page.link/hCHs. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||