Skip to content

5. Графічні інтерфейси

Тут ми пропонуємо показати, як створювати графічні інтерфейси за допомогою JAVA. Спочатку розглянемо базові класи, які дозволяють нам створювати графічний інтерфейс. На початковому етапі ми не використовуватимемо жодних інструментів автоматичного генерування. Потім ми скористаємося JBuilder — інструментом розробки від Borland/Inprise, що полегшує розробку Java-додатків, зокрема створення графічних інтерфейсів.

5.1. Основи графічних інтерфейсів

5.1.1. Просте вікно

Розглянемо такий код:


// імпортовані класи
import javax.swing.*;
import java.awt.*;
    
    // клас форми
  public class form1 extends JFrame {
    
      // конструктор
      public form1() {
            // заголовок вікна
            this.setTitle("Mon premier formulaire");
            // розміри вікна
            this.setSize(new Dimension(300,100));
      }//конструктор
  
      // тестова функція
      public static void main(String[] args) {
            // відображається форма
            new form1().setVisible(true);
      }
  }//клас

Виконання наведеного вище коду відображає таке вікно:

Image

Графічний інтерфейс зазвичай походить від базового класу JFrame:


  public class form1 extends JFrame {

Базовий клас JFrame визначає базове вікно з кнопками закриття, збільшення/зменшення, регулювання розміру тощо... та обробляє події, пов'язані з цими графічними об'єктами. Тут ми спеціалізуємо базовий клас, задаючи йому заголовок, а також ширину (300 пікселів) і висоту (100 пікселів). Це робиться в його конструкторі:


      // конструктор
      public form1() {
            // заголовок вікна
            this.setTitle("Mon premier formulaire");
            // розміри вікна
            this.setSize(new Dimension(300,100));
      }//конструктор

Заголовок вікна задається методом setTitle, а його розміри — методом setSize. Цей метод приймає як параметр об’єкт Dimension(largeur,hauteur), де largeur та hauteur — це ширина та висота вікна, виражені в пікселях.

Метод main запускає графічний додаток наступним чином:


            new form1().setVisible(true);

Потім створюється форма типу form1 (new form1()) і відображається (setVisible(true)), після чого програма починає очікувати подій, що відбуваються у формі (клацання, переміщення миші, ...) і запускає ті, які підтримує форма. У даному випадку наша форма не підтримує інших подій, окрім тих, що обробляються базовим класом JFrame (натискання кнопок закриття, збільшення/зменшення, зміна розміру вікна, переміщення вікна тощо).

Під час тестування цієї програми, запустивши її з вікна DOS за допомогою команди:

java form1

для запуску файлу form1.class, можна помітити, що при закритті вікна, яке було відображено, «контроль» у вікні DOS не повертається, ніби програма не завершилася. Це дійсно так. Виконання програми відбувається наступним чином:

  • спочатку запускається перший потік виконання для виконання методу main
  • коли цей метод створює форму та відображає її, створюється другий потік для управління саме подіями, пов’язаними з цією формою
  • після цього, у нашому прикладі, потік методу main завершується, і залишається лише потік виконання графічного інтерфейсу.
  • Коли вікно закривається, воно зникає, але не зупиняє потік, у якому воно виконувалося
  • Наразі доводиться зупиняти цей потік, натиснувши Ctrl-C у вікні командного рядка, з якого було запущено виконання програми.

Перевіримо наявність двох окремих потоків: одного, в якому виконується метод main, та іншого, в якому виконується графічне вікно:


// імпортовані класи
import javax.swing.*;
import java.awt.*;
import java.io.*;

// клас форми
 public class form1 extends JFrame {
    
// конструктор
 public form1() {
   // заголовок вікна
   this.setTitle("Mon premier formulaire");
   // розміри вікна
   this.setSize(new Dimension(300,100));
}//конструктор
  
// тестова функція
 public static void main(String[] args) {
   // моніторинг
   System.out.println("Début du thread main");
   // відображається форма
   new form1().setVisible(true);
   // відстеження
   System.out.println("Fin du thread main");  
}//головна
}//клас

Виконання дає такі результати:

Image

Можна помітити, що потік main завершився, тоді як вікно все ще відображається. Закриття вікна не призводить до завершення потоку, в якому воно виконувалося. Щоб зупинити цей потік, потрібно знову натиснути Ctrl-C у вікні DOS.

На завершення цього прикладу зазначимо імпортовані пакети:

  • javax.swing для класу JFrame
  • java.awt для класу Dimension

5.1.2. Обробка події

У попередньому прикладі нам потрібно самостійно обробляти закриття вікна, щоб у разі його закриття зупинити роботу програми, чого наразі не відбувається. Для цього нам потрібно створити об’єкт, який «прислухається» до подій, що відбуваються у вікні, та виявляє подію «закриття вікна». Цей об’єкт називається «слухачем» або обробником подій. Існують різні типи обробників для різних подій, що можуть відбуватися з компонентами графічного інтерфейсу. Для компонента JFrame слухач називається WindowListener і є інтерфейсом, що визначає такі методи (див. документацію Java)

Підсумок методів
 
void
windowActivated(WindowEvent e)
          Вікно стає активним
 
void
windowClosed(WindowEvent e)
          Вікно було закрито
 
void
windowClosing(WindowEvent e)
          Користувач або програма ініціювали закриття вікна
 
void
windowDeactivated(WindowEvent e)
          Вікно більше не є активним
 
void
windowDeiconified(WindowEvent e)
          Вікно переходить зі згорнутого стану в нормальний
 
void
windowIconified(WindowEvent e)
          Вікно переходить зі звичайного стану в згорнутий
 
void
windowOpened(WindowEvent e)
          Вікно стає видимим вперше
 

Отже, існує сім подій, які можна обробляти. Усі обробники отримують як параметр об’єкт типу WindowEvent, про який ми поки що не знаємо. Подія, яка нас тут цікавить, — це закриття вікна, яке має оброблятися методом windowClosing. Для обробки цієї події можна створити об’єкт Windowlistener за допомогою анонімного класу таким чином:


   // створення обробника подій
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//визначення win

Наш менеджер подій, що реалізує інтерфейс WindowListener, повинен визначити всі сім методів цього інтерфейсу. Оскільки ми хочемо обробляти лише закриття вікна, ми визначаємо код лише для методу windowClosing. Коли відбудуться інші події, ми отримаємо про це повідомлення, але нічого не робитимемо. Що ми зробимо, коли отримаємо повідомлення про те, що вікно закривається (windowClosing)? Ми зупинимо роботу програми:


     public void windowClosing(WindowEvent e){System.exit(0);}

Ми маємо об’єкт, здатний обробляти події вікна загалом. Як пов’язати його з конкретним вікном? Клас JFrame має метод addWindowListener(WindowListener win), який дозволяє пов’язати обробник подій «вікна» з певним вікном. Отже, тут, у конструкторі вікна, ми напишемо:


   // створення обробника подій
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//визначення win
    // цей обробник подій буде обробляти події поточного вікна
   this.addWindowListener(win);

Повна програма виглядає наступним чином:


// імпортовані класи
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// клас форми
 public class form2 extends JFrame {
    
// конструктор
 public form2() {
   // заголовок вікна
   this.setTitle("Mon premier formulaire");
   // розміри вікна
   this.setSize(new Dimension(300,100));
   // створення обробника подій
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//визначення win
   // цей обробник подій буде обробляти події поточного вікна
   this.addWindowListener(win);
}//конструктор
  
// тестова функція
 public static void main(String[] args) {
   // відображаємо форму
   new form2().setVisible(true);
}//main
}//клас

Пакет java.awt.event містить інтерфейс WindowListener. Коли запускаємо цю програму і закриваємо вікно, що з’явилося, у вікні DOS, де було запущено програму, бачимо, що виконання програми завершилося, чого раніше не було.

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

  • визначення обробника подій
  • прив’язка обробника до вікна

у нашому прикладі може виглядати так:


   // створення обробника подій
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//визначення win
   // цей обробник подій буде обробляти події поточного вікна
   this.addWindowListener(win);

Тут ми використовуємо анонімний клас, який походить від класу WindowAdapter і перевизначає його метод windowClosing. Тоді програма виглядає так:


// імпортовані класи
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// клас форми
 public class form2 extends JFrame {
    
// конструктор
 public form2() {
   // заголовок вікна
   this.setTitle("Mon premier formulaire");
   // розміри вікна
   this.setSize(new Dimension(300,100));
   // створення обробника подій
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//визначення win
   // цей обробник подій буде обробляти події поточного вікна
   this.addWindowListener(win); }//конструктор
  
// тестова функція
 public static void main(String[] args) {
   // відображаємо форму
   new form2().setVisible(true);
}//main
}//клас

Він дає ті самі результати, що й попередня програма, але простіший у написанні.

5.1.3. Форма з кнопкою

Тепер додамо до нашого вікна кнопку:


// імпортовані класи
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// клас форми
 public class form3 extends JFrame {
 
     // кнопка
  JButton btnTest=null;
  Container conteneur=null;
  
  // конструктор
  public form3() {
     // заголовок вікна
    this.setTitle("Formulaire avec bouton");
     // розміри вікна
    this.setSize(new Dimension(300,100));
    // створення обробника подій
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//визначення win
     // цей обробник подій буде обробляти події поточного вікна
    this.addWindowListener(win);
     // отримуємо контейнер вікна
    conteneur=this.getContentPane();
     // вибираємо менеджер форматування компонентів у цьому контейнері
    conteneur.setLayout(new FlowLayout());
    // створюємо кнопку
    btnTest=new JButton();
    // встановлюємо його напис
    btnTest.setText("Test");
    // додаємо кнопку до контейнера
    conteneur.add(btnTest);
  }//конструктор
  
  // тестова функція
 public static void main(String[] args) {
    // відображаємо форму
   new form3().setVisible(true);
}//main
}//клас

Вікно JFrame має контейнер, у який можна розміщувати графічні компоненти (кнопки, прапорці, випадаючі списки тощо). Цей контейнер доступний через метод getContentPane класу JFrame:


  Container conteneur=null;
..........
     // отримано контейнер вікна
    conteneur=this.getContentPane();

Кожен компонент розміщується в контейнері за допомогою методу add класу Container. Отже, щоб розмістити компонент C у попередньому об’єкті conteneur, слід написати:

conteneur.add(C)

Де саме цей компонент розміщується в контейнері? Існують різні менеджери розміщення компонентів із назвою XXXLayout, причому XXX, наприклад, дорівнює Border, Flow, ... Кожен менеджер розміщення має свої особливості. Наприклад, менеджер FlowLayout розміщує компоненти в рядках, починаючи з верхньої частини форми. Коли рядок заповнено, компоненти розміщуються в наступному рядку. Щоб прив’язати менеджер форматування до вікна JFrame, використовується метод setLayout класу JFrame у такій формі:

    setLayout(objet XXXLayout);

Отже, у нашому прикладі, щоб прив’язати обробник типу FlowLayout до вікна, ми написали:


     // вибір менеджера форматування компонентів у цьому контейнері
    conteneur.setLayout(new FlowLayout());

Можна не використовувати менеджер розмітки і написати:

    setLayout(null);

У цьому випадку потрібно вказати точні координати компонента в контейнері у вигляді (x, y, ширина, висота), де (x, y) — це координати лівого верхнього кута компонента в контейнері. Саме цей метод ми будемо використовувати найчастіше надалі.

Тепер ми знаємо, як розміщуються компоненти у контейнері (add) і де (setLayout). Залишається з’ясувати, які

компоненти, які можна розмістити в контейнері. Тут ми розміщуємо кнопку, реалізовану класом javax.swing.JButton:



  JButton btnTest=null;
..........
     // створюємо кнопку
    btnTest=new JButton();
    // встановлюємо його напис
    btnTest.setText("Test");
    // додаємо кнопку до контейнера
    conteneur.add(btnTest);

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

Image

Якщо змінити розмір наведеної вище форми, автоматично запускається менеджер розміщення контейнера, який перерозміщує компоненти:

Image

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


// вибираємо менеджер форматування компонентів у цьому контейнері
conteneur.setLayout(null);
    // створюємо кнопку
btnTest=new JButton();
    // встановлюємо його напис
btnTest.setText("Test");
    // визначаємо його розташування та розміри
btnTest.setBounds(10,20,100,20);
     // додаємо кнопку до контейнера
conteneur.add(btnTest);

Тут ми явно розміщуємо кнопку в точці (10,20) форми та встановлюємо її розміри: 100 пікселів завширшки та 20 пікселів у висоту. Нове вікно виглядає так:

Image

Якщо змінити розмір вікна, кнопка залишиться на тому самому місці.

Image

Якщо натиснути на кнопку Test, нічого не відбудеться. Адже ми ще не прив’язали до кнопки обробника подій. Щоб дізнатися, які типи обробників подій доступні для певного компонента, можна пошукати в визначенні його класу методи addXXXListener, які дозволяють прив’язати до компонента обробник подій. Клас javax.swing.JButton походить від класу javax.swing.AbstractButton, у якому містяться такі методи:

Зведена інформація про методи
 
void
addActionListener(ActionListener l)
 
void
addChangeListener(ChangeListener l)
 
void
addItemListener(ItemListener l)
 

Тут потрібно ознайомитися з документацією, щоб дізнатися, який обробник подій обробляє натискання кнопки. Це інтерфейс ActionListener. Він визначає лише один метод:

Короткий опис методів
 
void
actionPerformed(ActionEvent e)
 

Метод отримує параметр ActionEvent, який ми поки що проігноруємо. Щоб обробити натискання кнопки btntest у нашій програмі, спочатку прив’язуємо до неї обробник подій:


        btnTest.addActionListener(new ActionListener()
         {
                public void actionPerformed(ActionEvent evt){
                  btnTest_clic(evt);
              }
            }//анонімний клас
    );//обробник подій

Тут метод actionPerformed посилається на метод btnTest_clic, який ми визначаємо наступним чином:


public void btnTest_clic(ActionEvent evt){
  // відстеження консолі
System.out.println("clic sur bouton");
}//btnTest_click

Кожного разу, коли користувач натискає кнопку Test, на консолі виводиться повідомлення. Це ілюструє наступний приклад виконання:

Image

Повний код програми виглядає так:


// імпортовані класи
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// клас форми
 public class form4 extends JFrame {
 
     // кнопка
  JButton btnTest=null;
  Container conteneur=null;
  
  // конструктор
  public form4() {
     // заголовок вікна
    this.setTitle("Formulaire avec bouton");
     // розміри вікна
    this.setSize(new Dimension(300,100));
    // створення обробника подій
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//визначення win
     // цей обробник подій буде обробляти події поточного вікна
    this.addWindowListener(win);
     // отримуємо контейнер вікна
    conteneur=this.getContentPane();
     // вибираємо менеджер форматування компонентів у цьому контейнері
    conteneur.setLayout(null);
    // створюємо кнопку
    btnTest=new JButton();
    // встановлюємо його напис
    btnTest.setText("Test");
    // встановлюємо його розташування та розміри
    btnTest.setBounds(10,20,100,20);
     // прив'язуємо до неї обробник подій
    btnTest.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt){
              btnTest_clic(evt);
          }
        }//анонімний клас
    );//обробник події
     // додаємо кнопку до контейнера
    conteneur.add(btnTest);
  }//конструктор

    public void btnTest_clic(ActionEvent evt){
       // відстеження консолі
    System.out.println("clic sur bouton");
  }//btnTest_click
    
  // тестова функція
 public static void main(String[] args) {
    // відображення форми
   new form4().setVisible(true);
}//головна
}//клас

5.1.4. Керувачі подій

Основними компонентами Swing, які ми розглянемо, є вікна (JFrame), кнопки (JButton), прапорці (JCheckBox), перемикачі (JButtonRadio), випадаючі списки (JComboBox), списки (JList), повзунки (JScrollBar), мітки (JLabel), однорядкові поля введення (JTextField) або багаторядкові (JTextArea), меню (JMenuBar), елементи меню (JMenuItem).

У наведених нижче таблицях наведено перелік деяких обробників подій та подій, з якими вони пов’язані.

Обробник
Компонент(и)
Метод реєстрації
Подія
ActionListener
JButton, JCheckbox, JButtonRadio, JMenuItem
public void addActionListener(ActionListener)
натискання на кнопку, прапорець, перемикач, пункт меню
 
JTextField
ItemListener
JComboBox, JList
public void addItemListener(ItemListener)
Вибраний елемент змінився
InputMethodListener
JTextField, JTextArea
public void addMethodInputListener(InputMethodListener)
текст у полі введення змінився або курсор введення змінив своє положення
CaretListener
JTextField, JTextArea
public void addcaretListener(CaretListener)
Курсор введення змінив своє положення
AdjustmentListener
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
значення регулятора змінилося
MouseMotionListener
 
public void addMouseMotionListener(MouseMotionListener)
миша перемістилася
WindowListener
JFrame
public void addWindowlistener(WindowListener)
подія вікна
MouseListener
 
public void addMouselistener(MouseListener)
події миші (клацання, вхід/вихід з області компонента, натискання кнопки, відпускання)
FocusListener
 
public void addFocuslistener(FocusListener)
подія focus (отримано, втрачено)
KeyListener
 
public void addKeylistener(KeyListener)
подія клавіатури (натискання, утримання, відпускання клавіші)
Компонент
Метод реєстрації обробників подій
JButton
public void addActionListener(ActionListener)
JCheckbox
public void addItemListener(ItemListener)
JCheckboxMenuItem
public void addItemListener(ItemListener)
JComboBox
public void addItemListener(ItemListener)
public void addActionListener(ActionListener)
Container
public void addContainerListener(ContainerListener)
JComponent
public void addComponentListener(ComponentListener)
public void addFocusListener(FocusListener)
public void addKeyListener(KeyListener)
public void addMouseListener(MouseListener)
public void addMouseMotionListener(MouseMotionListener)
JFrame
public void addWindowlistener(WindowListener)
JList
public void addItemListener(ItemListener)
JMenuItem
public void addActionListener(ActionListener)
JPanel
як контейнер
JScrollPane
як контейнер
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
JTextComponent
public void addInputMethodListener(InputMethodListener)
public void addCaretListener(CaretListener)
JTextArea
comme JTextComponent
JTextField
як JTextComponent
public void addActionListener(ActionListener)

Усі компоненти, крім тих, що мають тип TextXXX, оскільки вони є похідними від класу JComponent, також мають методи, пов’язані з цим класом.

5.1.5. Методи обробників подій

У наступній таблиці наведено перелік методів, які повинні реалізовувати різні обробники подій.

Інтерфейс
Методи
ActionListener
public void actionPerformed(ActionEvent)
AdjustmentListener
public void adjustmentValueChanged(AdjustmentEvent)
ComponentListener
public void componentHidden(ComponentEvent)
public void componentMoved(ComponentEvent)
public void componentResized(ComponentEvent)
public void componentShown(ComponentEvent)
ContainerListener
public void componentAdded(ContainerEvent)
public void componentRemoved(ContainerEvent)
FocusListener
public void focusGained(FocusEvent)
public void focusLost(FocusEvent)
ItemListener
public void itemStateChanged(ItemEvent)
KeyListener
public void keyPressed(KeyEvent)
public void keyReleased(KeyEvent)
public void keyTyped(KeyEvent)
MouseListener
public void mouseClicked(MouseEvent)
public void mouseEntered(MouseEvent)
public void mouseExited(MouseEvent)
public void mousePressed(MouseEvent)
public void mouseReleased(MouseEvent)
MouseMotionListener
public void mouseDragged(MouseEvent)
public void mouseMoved(MouseEvent)
TextListener
public void textValueChanged(TextEvent)
InputmethodListener
public void InputMethodTextChanged(InputMethodEvent)
public void caretPositionChanged(InputMethodEvent)
CaretLisetner
public void caretUpdate(CaretEvent)
WindowListener
public void windowActivated(WindowEvent)
public void windowClosed(WindowEvent)
public void windowClosing(WindowEvent)
public void windowDeactivated(WindowEvent)
public void windowDeiconified(WindowEvent)
public void windowIconified(WindowEvent)
public void windowOpened(WindowEvent)

5.1.6. Класи-адаптери

Як ми бачили на прикладі інтерфейсу WindowListener, існують класи з іменем XXXAdapter, які реалізують інтерфейси XXXListener із порожніми методами. Отже, обробник подій, похідний від класу XXXAdapter, може реалізовувати лише частину методів інтерфейсу XXXListener — саме ті, які потрібні додатку.

Припустимо, що потрібно обробляти кліки мишею на компоненті Frame f1. До нього можна прив’язати обробник подій за допомогою:

    f1.addMouseListener(new gestionnaireSouris());

і написати:


    public class gestionnaireSouris implements MouseListener{
         // записуємо 5 методів інтерфейсу MouseListener
        // mouseClicked, ..., mouseReleased)
    }// кінець класу

Оскільки ми хочемо обробляти лише кліки мишею, краще написати:


public class gestionnaireSouris extends MouseAdapter{
        // пишемо лише один метод — той, що обробляє кліки мишею
        public void mouseClicked(MouseEvent evt){

        }
}// кінець класу

У наступній таблиці наведено класи адаптерів різних обробників подій:

Обробник подій
Адаптер
ComponentListener
ComponentAdapter
ContainerListener
ContainerAdapter
FocusListener
FocusAdapter
KeyListener
KeyAdapter
MouseListener
MouseAdapter
MouseMotionListener
MouseMotionAdapter
WindowListener
WindowAdapter

5.1.7. Висновок

Ми щойно розглянули основні поняття створення графічних інтерфейсів у Java:

  • створення вікна
  • створення компонентів
  • прив’язування компонентів до вікна за допомогою менеджера розміщення
  • прив’язування обробників подій до компонентів

Тепер, замість того, щоб створювати графічні інтерфейси «вручну», як це було зроблено щойно, ми будемо використовувати JBuilder — інструмент для розробки на Java від Borland/Inprise у версії 4, а також supérieure.Nous — компоненти бібліотеки java.swing, яку наразі рекомендує компанія Sun, розробник Java.

5.2. Створення графічного інтерфейсу за допомогою JBuilder

5.2.1. Наш перший проєкт у JBuilder

Щоб ознайомитися з JBuilder, створимо дуже простий додаток: порожнє вікно.

  1. Запустіть JBuilder і виберіть опцію «Файл/Новий проект». З’явиться перша сторінка майстра:

Image

  1. Заповніть такі поля:
Назва проєкту
Початок
Це призведе до створення файлу проєкту début.jpr у папці, вказаній у полі «Назва каталогу проєкту»
Кореневий шлях
вкажіть папку, в якій буде створено папку для проекту, що ви збираєтеся створити.
Назва каталогу проекту
вкажіть ім'я папки, куди будуть розміщені всі файли проекту. Ця папка буде створена у каталозі, вказаному в полі «Кореневий шлях»

Вихідні файли (.java, .html, ...), цільові файли (.class, ...) та файли резервних копій можуть зберігатися в різних каталогах. Якщо залишити відповідні поля порожніми, вони будуть розміщені в тому самому каталозі, що й проект.

Створіть [suivant]

  1. На екрані з’явиться підтвердження вибору, зробленого на попередньому кроці

Image

Виконайте [suivant]

  1. На новому екрані вам буде запропоновано вказати параметри вашого проєкту:

Image

Виконайте [terminer]

  1. Переконайтеся, що опція Voir/projet відмічена. У лівому вікні має з’явитися структура вашого проєкту.

Image

  1. Тепер створимо графічний інтерфейс у цьому проєкті. Виберіть опцію Fichier/Nouveau/Application:

Image

У полі classe вкажіть ім’я класу, який буде створено. Тут ми використали те саме ім’я, що й для проєкту.

Виконайте [suivant]

  1. З’явиться наступне вікно:

Image

Клас
interfaceDébut
Це назва класу, що відповідає вікну, яке буде створено
Заголовок
Це текст, який з'явиться у заголовку вікна

Зверніть увагу, що вище ми вказали, щоб вікно було вирівняне по центру екрана під час запуску програми.

Введіть [Terminer]

  1. Саме зараз JBuilder стає у нагоді.
  • Він генерує вихідні файли .java для двох класів, імена яких ми вказали: класу програми та класу графічного інтерфейсу. Ці два файли з’являються у структурі проєкту у лівому вікні

Image

  • Щоб отримати доступ до згенерованого коду для обох класів, достатньо двічі клацнути на відповідному файлі .java. Ми повернемося до згенерованого коду пізніше.
  • Переконайтеся, що опція Voir/Structure відмічена. Вона дозволяє переглянути структуру поточного вибраного класу (подвійне клацання на файлі .java). Ось, наприклад, структура класу début:

Image

Тут можна дізнатися:

  • про імпортовані бібліотеки (imports)

  • що існує конструктор début()

  • що існує статичний метод main()

  • що існує атрибут packFrame

У чому полягає користь доступу до структури класу?

  • Ви отримуєте загальне уявлення про неї. Це корисно, якщо ваш клас є складним.

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

Код, згенерований JBuilder, вже готовий до використання. Виконайте «Виконати/Виконати проект» або F9, і ви отримаєте потрібне вікно:

Image

Крім того, воно коректно закривається при натисканні кнопки закриття вікна. Ми щойно створили наш перший графічний інтерфейс. Ми можемо зберегти наш проект за допомогою опції «Файл/Закрити проекти»:

Image

Натиснувши Tous, ви позначите всі проекти, що знаходяться у вікні вище. OK закриє їх. Якщо ми захочемо за допомогою Провідника Windows перейти до папки нашого проєкту (тієї, яку було вказано майстру на початку налаштування проєкту), то знайдемо там такі файли:

Image

У нашому прикладі ми вказали, щоб усі файли (вихідні .java, цільові .class, резервні .jpr~) знаходилися в тій самій папці, що й файл проекту .jpr.

5.2.2. Файли, згенеровані JBuilder для графічного інтерфейсу

Давайте тепер з цікавістю подивимося, які вихідні файли .java згенерував JBuilder. Важливо вміти читати те, що було згенеровано, оскільки в більшості випадків нам доводиться додавати код до вже згенерованого коду. Почнемо з того, що відкриємо наш проєкт: «Файл»/«Відкрити проєкт» і виберемо проєкт début.jpr. Ми бачимо проект, створений раніше.

5.2.2.1. Головний клас

Переглянемо клас début.java, двічі клацнувши на його назві у вікні зі списком файлів проєкту. Ми бачимо такий код:

import javax.swing.UIManager;
import java.awt.*;

public class début {
  boolean packFrame = false;

   /**Створення програми*/
  public début() {
    interfaceDébut frame = new interfaceDébut();

     //Перевірити фрейми з попередньо визначеними розмірами
     //Стиснути фрейми з бажаними розмірами — наприклад, відповідно до їхнього розташування
    if (packFrame) {
      frame.pack();
    }
    else {
      frame.validate();
    }
    //Вирівняти вікно по центру
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = frame.getSize();
    if (frameSize.height > screenSize.height) {
      frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
      frameSize.width = screenSize.width;
    }
    frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
    frame.setVisible(true);
  }
   /**Основний метод*/
  public static void main(String[] args) {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    new début();
  }
}

Прокоментуємо згенерований код:

  1. функція main визначає зовнішній вигляд вікна (setLookAndFeel) і створює екземпляр класу début.
  2. Потім виконується конструктор début(). Він створює екземпляр frame класу вікна (new interfaceDébut()). Цей екземпляр створюється, але не відображається.
  3. Потім вікно масштабується відповідно до інформації, доступної для кожного з його компонентів (frame.validate). Після цього воно починає своє самостійне існування, відображаючись на екрані та реагуючи на дії користувача.
  4. Вікно центрується на екрані, оскільки це було задано під час налаштування вікна за допомогою майстра.

Давайте подивимося, що вийде, якщо скоротити код début.java до абсолютного мінімуму, як ми це зробили на початку розділу. Створимо новий клас. Виберіть опцію «Файл/Новий клас»:

Image

Назвіть новий клас début2, а [Terminer] перейменуйте. У проєкті з’явиться новий файл:

Image

Файл début2.java спрощується до найпростішого вигляду:

public class début2 {
}

Доповнимо клас наступним чином:

public class début2 {
   // головна функція
  public static void main(String args[]){
    // створює вікно
    new interfaceDébut().show();    // або new interfaceDébut.setVisible(true);
  }//main
}//клас début2

Функція main створює екземпляр вікна interfaceDébut і відображає його (show). Перш ніж запустити наш проект, слід зазначити, що клас, який містить функцію main, що має бути виконана, тепер називається début2. Клацніть правою кнопкою миші на проекті début.jpr і виберіть опцію propriétés, а потім вкладку Exécution:

21

Image

Тут вказано, що головним класом є début (1). Натисніть кнопку (2), щоб вибрати інший головний клас:

Image

Виберіть début2 і вкажіть [OK].

Image

Введіть [OK], щоб підтвердити цей вибір, а потім запустіть проект за допомогою «Виконати/Виконати проект» або F9. Ви отримаєте те саме вікно, що й у класі début, за винятком того, що воно не відцентроване, оскільки тут цього не було зазначено. Надалі ми більше не будемо показувати головний клас, згенерований JBuilder, оскільки він завжди виконує одну й ту саму дію: створює вікно. Відтепер ми зосередимося саме на класі цього вікна.

5.2.2.2. Клас вікна

Тепер розглянемо код, який було згенеровано для класу interfaceDébut:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceDébut extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

  /**Створити фрейм*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Ma première interface graphique avec Jbuilder");
  }
   /**Замінено, щоб ми могли вийти, коли вікно закриється*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
}

5.2.2.2.1. Імпортовані бібліотеки
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

Це бібліотеки java.awt, java.awt.event та javax.swing. Перші дві були єдиними, доступними для створення графічних інтерфейсів у ранніх версіях Java. Бібліотека javax.swing є новішою. У даному випадку вона необхідна для вікна типу JFrame, яке тут використовується.

5.2.2.2.2. Атрибути
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

JPanel — це тип контейнера, у який можна розміщувати компоненти. BorderLayout — це один із типів менеджерів форматування, доступних для розміщення компонентів у контейнері. У всіх наших прикладах ми не будемо використовувати менеджер форматування і самостійно розміщуватимемо компоненти в певному місці контейнера. Для цього ми використовуватимемо менеджер форматування null.

5.2.2.2.3. Конструктор вікна
   /**Створити фрейм*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Ma première interface graphique avec Jbuilder");
  }
  1. Розробник спочатку заявляє, що буде обробляти події у вікні (enableEvents), а потім викликає метод jbInit.
  2. Отримується (getContentPane) контейнер (JPanel) вікна (JFrame)
  3. Визначається менеджер форматування (setLayout)
  4. Розмір вікна встановлено (setSize)
  5. Заголовок вікна встановлено (setTitle)

5.2.2.2.4. Менеджер подій
   /**Замінено, щоб можна було вийти при закритті вікна*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }

Розробник зазначив, що клас оброблятиме події вікна. Цю роботу виконує метод processWindowEvent. Спочатку він передає своєму батьківському класу (JFrame) отриману подію WindowEvent, а потім, якщо це подія WINDOW_CLOSING, викликана натисканням кнопки закриття вікна, програма завершується.

5.2.2.2.5. Висновок

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

5.2.3. Створення графічного інтерфейсу

5.2.3.1. Приклад

У попередньому прикладі ми не розміщували компонентів у вікні. Тепер створимо вікно з кнопкою, написом та полем введення:

Image

Поля такі:

ім'я
тип
роль
1
lblSaisie
JLabel
назва
2
txtSaisie
JTextField
поле введення
3
cmdAfficher
JButton
для відображення вмісту поля введення у діалоговому вікні txtSaisie

Діючи так само, як і в попередньому проєкті, створіть проєкт interface2.jpr, поки що не додаючи компонентів у вікно.

Image

У вікні, показаному вище, виберіть клас interface2.java. Праворуч від цього вікна розташована папка з вкладками:

Image

Вкладка Source надає доступ до вихідного коду класу interface2.java. Вкладка Conception дозволяє візуально побудувати вікно. Виберіть цю вкладку. Перед вами — контейнер вікна, який буде містити компоненти, які ви туди розмістите. Наразі він порожній. У лівому вікні показано структуру класу:

Image

this
позначає вікно
contentPane
його контейнер, у який будуть розміщені компоненти, а також спосіб їхнього розміщення в контейнері (за замовчуванням — BorderLayout)
borderLayout1
екземпляр менеджера форматування

Виберіть об’єкт this. У правій частині екрана з’явиться вікно його властивостей:

Image

Слід звернути увагу на деякі з цих властивостей:

background
для встановлення кольору фону вікна
foreground
для визначення кольору елементів у вікні
JMenuBar
для прив’язки меню до вікна
title
для присвоєння заголовка вікну
resizable
для визначення типу вікна
font
для визначення шрифту тексту у вікні

Поки об’єкт this залишається виділеним, можна змінити розмір контейнера, що відображається на екрані, перетягуючи опорні точки, розташовані навколо контейнера:

Image

Тепер ми готові розміщувати компоненти у вищезазначеному контейнері. Перед цим змінимо менеджер форматування. Виберіть об’єкт contentPane у вікні структури:

Image

Потім у вікні властивостей цього об’єкта виберіть властивість layout і з можливих значень оберіть значення null:

Image

Відсутність менеджера форматування дозволить нам вільно розміщувати компоненти в контейнері. Тепер настав час вибрати ці компоненти.

Коли вибрано панель Conception, компоненти стають доступними у папці з вкладками у верхній частині вікна проектування:

Image

Для побудови графічного інтерфейсу ми маємо компоненти swing (1) та awt (2). Тут ми будемо використовувати компоненти swing. У панелі компонентів, що розташована вище, виберіть компонент JLabel (3), компонент JTextField (4) та компонент JButton (5) і розмістіть їх у контейнері вікна проектування.

Image

Тепер налаштуємо кожен із цих 3 компонентів:

  • мітка (JLabel) jLabel1

Виберіть компонент, щоб відкрити вікно його властивостей. У ньому змініть такі властивості: name: lblSaisie, text: Введення

  • поле введення (JTextField) jTextfield1

Виберіть компонент, щоб відкрити вікно його властивостей. У ньому змініть такі властивості: name: txtSaisie, text: не вказувати нічого

  • кнопка (JButton): name: cmdAfficher, text: Показати

Тепер ми маємо таке вікно:

Image

та таку структуру:

Image

Ми можемо запустити (F9) наш проєкт, щоб отримати перше уявлення про те, як працює це вікно:

Image

Закрийте вікно. Нам залишилося написати процедуру, пов’язану з натисканням кнопки Afficher. Виберіть кнопку, щоб відкрити вікно її властивостей. Воно має дві вкладки: propriétés та événements. Виберіть événements.

Image

У лівій колонці вікна перелічено можливі події для цієї кнопки. Клацання на кнопці відповідає події actionPerformed. У правій колонці вказано назву процедури, яка викликається при виникненні відповідної події. Клацніть на комірку праворуч від події actionPerformed:

Image

JBuilder генерує ім'я за замовчуванням для кожного обробника подій у форматі nomComposant_nomEvénement, наприклад, cmdAfficher_actionPerformed. Можна видалити запропоновану за замовчуванням назву та ввести іншу. Щоб отримати доступ до коду обробника cmdAfficher_actionPerformed, достатньо двічі клацнути на його назві вище. Після цього відбудеться автоматичний перехід до панелі джерельного коду класу, де курсор буде розташований на каркасі коду обробника події:

  void cmdAfficher_actionPerformed(ActionEvent e) {
 }

Залишилося лише доповнити цей код. У цьому випадку ми хочемо відобразити діалогове вікно з вмістом поля txtSaisie:

  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), 
"Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
 }

JOptionPane — це клас бібліотеки javax.swing. Він дозволяє відображати повідомлення з піктограмою або запитувати інформацію у користувача. Тут ми використовуємо статичний метод цього класу:

Image

parentComponent
«батьківський» контейнер діалогового вікна: у даному випадку this.
повідомлення
об’єкт, який потрібно відобразити. У цьому випадку — вміст поля введення
title
заголовок діалогового вікна
messageType
тип повідомлення, яке потрібно відобразити. Визначає піктограму, яка буде відображатися у полі поруч із повідомленням. Можливі значення:
INFORMATION_MESSAGE, QUESTION_MESSAGE, ERROR_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE

Запустимо наш додаток (F9):

Image

Image

5.2.3.2. Код класу вікна

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import javax.swing.event.*;


public class interface2 extends JFrame {
  JPanel contentPane;
  JLabel lblSaisie = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmdAfficher = new JButton();

  /**Створити фрейм*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
    lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }
   /**Замінено, щоб можна було вийти при закритті вікна*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
  }
}

5.2.3.2.1. Атрибути
  JPanel contentPane;
  JLabel lblSaisie = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmdAfficher = new JButton();

Тут знаходиться контейнер з компонентами типу JPanel та три компоненти.

5.2.3.2.2. Виробник
   /**Створити фрейм*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
    lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }

Конструктор interface2 схожий на конструктор попереднього графічного інтерфейсу, який ми розглядали. Відмінності можна помітити в методі jbInit: код побудови вікна залежить від компонентів, розміщених у ньому. Можна використати код з jbInit, додавши до нього власні коментарі:

  private void jbInit() throws Exception  {
       // саме вікно (розмір, заголовок)
this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
         // контейнер компонентів
    contentPane = (JPanel) this.getContentPane();
         // для цього контейнера немає менеджера форматування
    contentPane.setLayout(null);
         // мітка lblSaisie (назва, положення, розмір)
         lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
        // поле введення (позиція, розмір)
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
         // кнопка «Показати» (назва, положення, розмір)
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
         // обробник подій кнопки
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
         // додавання 3 компонентів до контейнера
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }//jbInit

Слід звернути увагу на два моменти:

  • цей код можна було б написати вручну. Це означає, що для створення графічного інтерфейсу можна обійтися без JBuilder.
  • спосіб, у який прив’язано обробник події кнопки cmdAfficher. Обробник події компонента cmdAfficher можна було б оголосити за допомогою cmdAfficher.addActionListener(new обробник()) , де gestionnaire був би класом із публічним методом actionPerformed, відповідальним за обробку кліка на кнопці Afficher. Тут JBuilder використовує як обробник екземпляр анонімного класу:
 new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }

Створюється новий екземпляр інтерфейсу ActionListener, а його метод actionPerformed визначається одразу ж. Цей метод просто викликає метод класу interface2. Все це — лише прийом, що дозволяє визначити в тому самому класі, що й вікно, процедури обробки подій компонентів цього вікна. Можна було б вчинити інакше:

cmdAfficher.addActionListener(this)

через що метод actionPerformed буде шукатися в this, тобто в класі вікна. Другий метод здається простішим, але перший має над ним перевагу: він дозволяє використовувати різні обробники для різних кнопок, тоді як другий метод цього не дозволяє. У останньому випадку, а саме, єдиний метод actionPeformed повинен обробляти кліки різних кнопок і, отже, спочатку визначати, яка саме кнопка спричинила подію, перш ніж приступити до роботи.

5.2.3.2.3. Обробники подій

Тут ми бачимо ті, що вже розглядали:

   /**Замінено, щоб ми могли вийти, коли вікно закрито*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }

     // натискання кнопки «Показати»
  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
  }

5.2.3.3. Conclusion

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

5.2.4. Пошук допомоги

При роботі з Java часто виникає потреба у допомозі, зокрема через дуже велику кількість доступних класів. Тут ми наводимо кілька вказівок щодо пошуку інформації про той чи інший клас. Виберіть у меню пункт «Довідка/Теми довідки».

Image

Екран довідки зазвичай має два вікна:

  • ліве, де вказується, що саме шукається. Воно має три вкладки: Sommaire, Index та Chercher.
  • праве вікно, яке відображає результат пошуку

Доступна довідка щодо використання довідки JBuilder. У довідці JBuilder виберіть пункт «Довідка/Використання довідки». Там вам пояснять, як користуватися довідкою. Наприклад, вам покажуть різні компоненти переглядача довідки:

Image

Давайте детальніше розглянемо сторінки Sommaire та Index.

5.2.4.1. Довідка: Зміст

Image

5.2.4.1.1. Зміст: Вступ до Java

Тут ви знайдете основні елементи Java, але не тільки, як показує перелік тем, що розглядаються в цьому розділі:

Image

5.2.4.1.2. Зміст: Посібники

Якщо вибрати пункт «Посібники» у наведеному вище змісті, у правому вікні з’явиться список доступних посібників:

Image

Базові навчальні посібники особливо цікаві для тих, хто тільки починає освоювати JBuilder. Існує ще багато інших, крім наведених вище, і коли ви хочете розробити додаток, може бути корисно попередньо перевірити, чи немає навчального посібника, який міг би вам допомогти.

5.2.4.1.3. Зміст: JDK

Вибравши опцію Java 2 JDK 1.3, ви отримуєте доступ до всіх бібліотек JDK. Зазвичай це не те місце, де слід шукати, якщо вам потрібна інформація про конкретний клас і ви не знаєте, в якій бібліотеці він знаходиться. Однак ця опція може бути корисною, якщо ви хочете отримати загальне уявлення про бібліотеки Java.

5.2.4.2. Довідка: Індекс

Виберіть вкладку «Індекс» у лівому вікні довідки. Ця опція дозволяє, наприклад, знайти довідку щодо певного класу. Припустимо, ви хочете дізнатися про методи полів введення swing та JTextField. Введіть JTextField у поле введення тексту для пошуку:

Image

Довідка поверне записи індексу, що починаються з введеного тексту:

Image

Залишається лише двічі клацнути на записі, що вас цікавить, у даному випадку — JTextField class. Довідка щодо цього класу відобразиться у правому вікні:

Image

Ви отримаєте повний опис класу.

5.2.5. Деякі компоненти Swing

Тепер ми розглянемо різні варіанти застосування найпоширеніших компонентів swing, щоб ознайомитися з їхніми основними методами та властивостями. Для кожного варіанту застосування ми наведемо графічний інтерфейс та відповідний код, зокрема код обробників подій.

5.2.5.1. Компоненти JLabel та JTextField

Ми вже знайомилися з цими двома компонентами. JLabel — це текстовий компонент, а JTextField — компонент поля введення. Їхні два основні методи — це

String getText()
для отримання вмісту поля введення або тексту мітки
void setText(String unTexte)
для введення unTexte у поле або мітку

Зазвичай для JTextField використовуються такі події:

actionPerformed
позначає, що користувач підтвердив (клавішею Enter) введений текст
caretUpdate
позначає, що користувач перемістив курсор введення
inputMethodChanged
показує, що користувач змінив значення поля введення

Ось приклад, у якому використовується подія caretUpdate для відстеження змін у полі введення:

Image

тип
назва
роль
1
JTextField
txtSaisie
поле введення
2
JTextField
txtControle
відображає текст з 1 у режимі реального часу
3
JButton
cmdEffacer
для очищення полів 1 і 2
4
JButton
cmdQuitter
для виходу з програми

Відповідний код цього додатка такий:

import java.awt.*;
....


public class Cadre1 extends JFrame {
  JPanel contentPane;
  JTextField txtSaisie = new JTextField();
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JTextField txtControle = new JTextField();
  JButton CmdEffacer = new JButton();
  JButton CmdQuitter = new JButton();

  /**Створити фрейм*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
    ....
    txtSaisie.addCaretListener(new javax.swing.event.CaretListener() {
      public void caretUpdate(CaretEvent e) {
        txtSaisie_caretUpdate(e);
      }
    });

...
    CmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdEffacer_actionPerformed(e);
      }
    });
...
    CmdQuitter.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdQuitter_actionPerformed(e);
      }
    });
....
}

   /**Замінено, щоб можна було вийти, коли вікно закрито*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_caretUpdate(CaretEvent e) {
         // курсор введення перемістився
    txtControle.setText(txtSaisie.getText());
  }

  void CmdQuitter_actionPerformed(ActionEvent e) {
        // завершуємо роботу програми
    System.exit(0);
  }

  void CmdEffacer_actionPerformed(ActionEvent e) {
        // очищення вмісту поля введення
    txtSaisie.setText("");
  }
}

Ось приклад виконання:

Image

5.2.5.2. компонент JComboBox

Image

Image

Компонент JComboBox — це випадаючий список, доповнений полем введення: користувач може або вибрати елемент у (2), або ввести текст у (1). За замовчуванням компоненти JComboBox не підлягають редагуванню. Щоб зробити їх редагованими, потрібно явно викликати метод setEditable(true). Щоб дізнатися більше про клас JComboBox, введіть JComboBox в індексі довідки.

Об’єкт JComboBox можна створити різними способами:

new JComboBox()
створює порожній комбо-список
new JComboBox (Object[] items)
створює комбо-поле, що містить масив об’єктів
new JComboBox(Vector items)
те саме з вектором об'єктів

Може здатися дивним, що комбо-поле може містити об’єкти, хоча зазвичай воно містить символьні рядки. Візуально це саме так і буде. Якщо JComboBox містить об’єкт obj, воно відображає рядок obj.toString(). Нагадаємо, що кожен об’єкт має метод toString, успадкований від класу Object, який повертає символьний рядок, що «представляє» цей об’єкт.

Корисні методи класу JCombobox такі:

void addItem(Object unObjet)
додає об’єкт до комбінованого списку
int getItemCount()
повертає кількість елементів у списку
Object getItemAt(int i)
повертає об’єкт № i зі списку
void insertItemAt(Object unObjet, int i)
вставляє unObjet у позицію i комбінованого списку
int getSelectedIndex()
повертає номер вибраного елемента у комбінованому списку
Object getSelectedItem()
повертає об’єкт, вибраний у комбінованому списку
void setSelectedIndex(int i)
вибирає елемент i зі списку
void setSelectedItem(Object unObjet)
вибирає об’єкт, вказаний у комбінованому списку
void removeAllItems()
очищає список
void removeItemAt(int i)
видаляє елемент № i зі списку
void removeItem(Object unObjet)
видаляє вказаний об’єкт зі списку
void setEditable(boolean val)
робить комбінований список доступним для редагування (val=true) або недоступним (val=false)

Під час вибору елемента зі списку, що розгортається, відбувається подія actionPerformed, яку можна використовувати для отримання повідомлення про зміну вибору у комбінованому списку. У наведеному нижче прикладі ми використовуємо цю подію для відображення елемента, який було вибрано зі списку.

Image

Ми наводимо лише відповідний код вікна.

public class Cadre1 extends JFrame {
  JPanel contentPane;
  JComboBox jComboBox1 = new JComboBox();
  JLabel jLabel1 = new JLabel();

   /**Створити фрейм*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // обробка — заповнюється комбінований список
    String[] infos={"un","deux","trois","quatre"};
    for(int i=0;i<infos.length;i++)
      jComboBox1.addItem(infos[i]);
  }
   /**Ініціалізація компонента*/
  private void jbInit() throws Exception  {
        ....

    jComboBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jComboBox1_actionPerformed(e);
      }
    });
       .... 
  }

  void jComboBox1_actionPerformed(ActionEvent e) {
        // було вибрано новий елемент — відображаємо його
    JOptionPane.showMessageDialog(this,jComboBox1.getSelectedItem(),
"actionPerformed",JOptionPane.INFORMATION_MESSAGE);
  }

}

5.2.5.3. компонент JList

Компонент Swing JList є складнішим за його аналог із бібліотеки awt. Існують дві важливі відмінності:

  • вміст списку керується об’єктом, відмінним від самого списку. Тут ми використаємо об’єкт DefaultListModel, який працює так само, як Vector, але, крім того, сповіщає об’єкт JList щоразу, коли його вміст змінюється, щоб візуальне відображення списку також змінювалося.
  • За замовчуванням список не прокручується. Список потрібно помістити в контейнер ScrollPane, який і забезпечує цю прокрутку.

У вихідному коді визначення списку можна виконати таким чином:

      // вектор значень списку 
DefaultlistModel valeurs=new DefaultListModel();
// сам список, до якого прив'язується вектор його значень
  JList jList1 = new JList(valeurs);
     // прокручуваний контейнер, у який поміщається список для створення прокручуваного списку
  JScrollPane jScrollPane1 = new JScrollPane(jList1);

Щоб включити список jList1 у контейнер jScrollPane1, код, згенерований JBuilder, діє інакше:

  • оголошення контейнера в атрибутах вікна
  JScrollPane jScrollPane1 = new JScrollPane();
  • а потім у коді jbInit список пов’язується з контейнером
    jScrollPane1.getViewport().add(jList1, null);

Щоб додати значення до списку JList1, наведеного вище, достатньо додати їх до його вектора значень valeurs:

    // ініціалізація списку
    for(int i=0;i<10;i++)
      valeurs.addElement(""+i);

і тоді з’явиться таке вікно:

Image

Як побудовано цей інтерфейс?

  • вибираємо компонент JScrollPane на сторінці «Swing-контейнери» компонентів і перетягуємо його у вікно, налаштовуючи розмір на потрібний
  • вибираємо компонент JList на сторінці «Swing» у списку компонентів і перетягуємо його в контейнер JScrollPane, де він займає весь простір.

Код, згенерований JBuilder, потрібно дещо доопрацювати, щоб отримати такий код:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  DefaultListModel valeurs=new DefaultListModel();
  JList jList1 = new JList(valeurs);
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel2 = new JLabel();


   /**Створити фрейм*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // обробка
     // включаємо список у scrollPane
    // ініціалізація списку
    for(int i=0;i<10;i++)
      valeurs.addElement(""+i);
  }

   /**Ініціалізація компонента*/
  private void jbInit() throws Exception  {
        ....
         // список jList1 пов'язано з контейнером jcrollPane1
    jScrollPane1.getViewport().add(jList1, null);
  }
   /**Замінено, тому ми можемо вийти, коли вікно закрито*/
  protected void processWindowEvent(WindowEvent e) {
        ....
  }
}

Тепер давайте ознайомимося з основними методами класу JList, знайшовши JList в індексі довідки. Об'єкт JList можна створити різними способами:

Image

Простий метод — це той, який ми використовували: створити порожній DefaultListModel V, а потім пов’язати його зі списком, який потрібно створити, за допомогою new JList(V). Вміст списку керується не об’єктом JList, а об’єктом, що містить значення списку. Якщо вміст було сформовано за допомогою об’єкта DefaultListModel, який базується на класі Vector, для додавання, вставки та видалення елементів зі списку можна використовувати методи класу Vector. Список може бути з одинарним або множинним вибором. Це визначається методом setSelectionMode:

Image

Дізнатися про поточний режим вибору можна за допомогою getSelectionMode:

Image

Вибраний елемент або елементи можна отримати за допомогою таких методів:

Image

Ми знаємо, як пов’язати вектор значень зі списком за допомогою конструктора JList(DefaultListModel). І навпаки, ми можемо отримати об’єкт DefaultListModel зі списку JList за допомогою:

Image

Ми знаємо достатньо, щоб написати таку програму:

Image

Компоненти цього вікна такі:

тип
назва
роль
1
JTextField
txtSaisie
поле введення
2
JList
jList1
список, що міститься в контейнері jScrollPane1
3
JList
jList2
список, що міститься в контейнері jScrollPane2
4
JButton
cmd1To2
переносить вибрані елементи зі списку 1 до списку 2
5
JButton
cmd2To1
виконує зворотну операцію
6
JButton
cmdRaz1
очистити список 1
7
JButton
cmdRaz2
очистити список 2

Користувач вводить текст у поле (1) і підтверджує його. Після цього у полі введення відбувається подія actionPerformed, яка використовується для додавання введеного тексту до списку 1. Ось код, необхідний для цієї першої функції:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**Створити фрейм*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         // Jlist1 розміщено в контейнері jScrollPane1
    jScrollPane1.getViewport().add(jList1, null);
        // Jlist2 розміщено в контейнері jScrollPane2
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**Замінено, щоб ми могли вийти, коли вікно закриється*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
     // текст, введений користувачем, було перевірено
     // його отримуємо, видаливши пробіли на початку та в кінці
    String texte=txtSaisie.getText().trim();
     // якщо він порожній, то він нам не потрібен
    if(texte.equals("")){
      // повідомлення про помилку
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      // кінець
      return;
    }//if
    // якщо він не порожній, додаємо його до значень списку 1
    v1.addElement(texte);
     // і очищаємо поле введення
    txtSaisie.setText("");
  }/// txtSaisie_actionperformed
}//клас

Код для перенесення вибраних елементів з одного списку в інший такий:

  void cmd1To2_actionPerformed(ActionEvent e) {
    // перенесення вибраних елементів зі списку 1 до списку 2
    transfert(jList1,jList2);
  }//cmd1To2

  void cmd2To1_actionPerformed(ActionEvent e) {
    // перенесення вибраних елементів із jList2 до jList1
      transfert(jList2,jList1);
  }//cmd2TO1

  private void transfert(JList L1, JList L2){
      // перенесення вибраних елементів зі списку 1 до списку 2
       // отримуємо масив індексів вибраних елементів у L1
      int[] indices=L1.getSelectedIndices();
      // що робити?
      if (indices.length==0) return;
      // отримуємо значення з L1
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      // та з L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // додаємо до L2 значення, вибрані з L1
        v2.addElement(v1.elementAt(indices[i]));
        // елементи з L1, скопійовані в L2, потрібно видалити з L1
        v1.removeElementAt(indices[i]);
      }//для
  }//перенесення

Код, пов'язаний із кнопками Raz, є надзвичайно простим:

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // очистити список 1
    v1.removeAllElements();
  }//команда Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // очистити список 2
    v2.removeAllElements();
  }///команда Raz2

5.2.5.4. Поля для позначення JCheckBox, перемикачі JButtonRadio

Ми пропонуємо написати таку програму:

Image

Компоненти вікна такі:

тип
назва
роль
1
JButtonRadio
jButtonRadio1
jButtonRadio2
jButtonRadio3
3 перемикачі, що входять до групи buttonGroup1
2
JCheckBox
jCheckBox1
jCheckBox2
jCheckBox3
3 прапорці
3
JList
jList1
список у контейнері jScrollPane1
4
ButtonGroup
buttonGroup1
невидимий компонент — служить для об'єднання 3 перемикачів, щоб коли один із них увімкнеться, інші вимкнулися.

Групу перемикачів можна створити таким чином:

  • розміщуємо кожну з перемикальних кнопок, не турбуючись про їх об’єднання
  • у контейнер розміщують компонент Swing ButtonGroup. Цей компонент є невидимим. Тому він не відображається у конструкторі вікна. Однак він відображається у його структурі:

Image

Вище, у гілці Autre, можна побачити невидимі атрибути вікна. Після створення групи перемикачів можна прив’язати до неї кожен з перемикачів. Для цього потрібно вибрати властивості перемикача:

Image

і у властивості buttonGroup перемикача вказуємо назву групи, до якої хочемо додати перемикач, у даному випадку buttonGroup1. Цю операцію повторюємо для всіх 3 перемикачів.

Основним методом для перемикачів та прапорців є метод isSelected(), який вказує, чи встановлено прапорець або перемикач. Текст, пов’язаний із компонентом, можна дізнатися за допомогою getText() та встановити за допомогою setText(String unTexte). Поле або перемикач можна встановити за допомогою методу setSelected(boolean value).

При натисканні на перемикач або прапорець спрацьовує подія actionPerformed. У наведеному нижче коді ми використовуємо цю подію для відстеження змін значень перемикачів та прапорців:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JRadioButton jRadioButton1 = new JRadioButton();
  JRadioButton jRadioButton2 = new JRadioButton();
  JRadioButton jRadioButton3 = new JRadioButton();
  JCheckBox jCheckBox1 = new JCheckBox();
  JCheckBox jCheckBox2 = new JCheckBox();
  JCheckBox jCheckBox3 = new JCheckBox();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel valeurs=new DefaultListModel();
  JList jList1 = new JList(valeurs);

   /**Створити фрейм*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
    jRadioButton1.setSelected(true);
    jRadioButton1.setText("un");
    jRadioButton1.setBounds(new Rectangle(57, 31, 49, 23));
    jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });

    jRadioButton2.setBounds(new Rectangle(113, 30, 49, 23));
    jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });
    jRadioButton2.setText("deux");

    jRadioButton3.setBounds(new Rectangle(168, 30, 49, 23));
    jRadioButton3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });
    jRadioButton3.setText("trois");

// перемикачі згруповані
    buttonGroup1.add(jRadioButton1);
    buttonGroup1.add(jRadioButton2);
    buttonGroup1.add(jRadioButton3);

// прапорці
    jCheckBox1.setText("A");
    jCheckBox1.setBounds(new Rectangle(58, 69, 32, 17));
    jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });

    jCheckBox2.setBounds(new Rectangle(112, 69, 40, 17));
    jCheckBox2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });
    jCheckBox2.setText("B");

    jCheckBox3.setText("C");
    jCheckBox3.setBounds(new Rectangle(170, 69, 37, 17));
    jCheckBox3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });

    ....
  }
   /**Замінено, щоб ми могли вийти, коли вікно закрито*/
  protected void processWindowEvent(WindowEvent e) {
        ...
  }

  private void afficheRadioButtons(ActionEvent e){
     // відображає значення 3 перемикачів
    valeurs.addElement("boutons radio=("+jRadioButton1.isSelected()+","+
      jRadioButton2.isSelected()+","+jRadioButton3.isSelected()+")");
  }//afficheRadioButtons

  void afficheCases(ActionEvent e) {
     // відображає значення прапорців
    valeurs.addElement("cases à cocher=["+jCheckBox1.isSelected()+","+
      jCheckBox2.isSelected()+","+jCheckBox3.isSelected()+")");
  }//afficheCases

}//сортує

Ось приклад виконання:

Image

5.2.5.5. компонент JScrollBar

Створимо такий додаток:

Image

тип
назва
роль
1
JScrollBar
jScrollBar1
горизонтальний регулятор
2
JScrollBar
jScrollBar2
вертикальний регулятор
3
JTextField
txtvaleurHS
відображає значення горизонтального регулятора 1 — також дозволяє зафіксувати це значення
4
JTextField
txtvaleurVS
відображає значення вертикального регулятора 2 — також дозволяє зафіксувати це значення
  • Регулятор JScrollBar дозволяє користувачеві вибрати значення в діапазоні цілих чисел, що символізується «смугою» регулятора, по якій переміщується курсор.
  • Для горизонтального повзунка лівий край відповідає мінімальному значенню діапазону, правий край — максимальному, а курсор — поточно вибраному значенню. Для вертикального повзунка мінімум відповідає верхньому краю, максимум — нижніму. Пара (min,max) за замовчуванням дорівнює (0,100).
  • Клік на крайніх точках регулятора змінює значення на один крок (позитивний або негативний) відповідно до крайньої точки, на яку натиснуто, що називається unitIncrement і за замовчуванням дорівнює 1.
  • Клік по обидва боки від повзунка змінює значення на один крок (у позитивному або негативному напрямку) відповідно до крайньої точки, на яку натиснуто, що має назву blockIncrement і за замовчуванням дорівнює 10.
  • Ці п’ять значень (min, max, value, unitIncrement, blockIncrement) можна отримати за допомогою методів getMinimum(), getMaximum(), getValue(), getUnitIncrement(), getBlockIncrement(), які всі повертають ціле число і можуть бути встановлені за допомогою методів setMinimum(int min), setMaximum(int max), setValue(int val), setUnitIncrement(int uInc), setBlockIncrement(int bInc)

При використанні компонентів JScrollBar слід знати кілька моментів. По-перше, його можна знайти на панелі компонентів Swing:

Image

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

Image

На аркуші властивостей, наведеному вище, видно, що ми маємо доступ до властивостей minimum, maximum, value, unitIncrement, blockIncrement об’єкта JScrollbar. Отже, їх можна задати на етапі проектування. Коли на контейнер розміщують смугу прокрутки, її «діапазон зміни» не відображається:

Image

Цю проблему можна вирішити, додавши компоненту облямівку. Це робиться за допомогою властивості border, яка може мати різні значення:

Image

Ось як, наприклад, виглядає значення RaisedBevel:

Image

При натисканні на верхній край вертикального повзунка його значення зменшується. Це може здивувати пересічного користувача, який зазвичай очікує, що значення «зросте». Цю проблему можна вирішити, присвоївши від’ємні значення параметрам unitIncrement та blockIncrement.

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

Image

Корисний код нашого додатка виглядає так:

....

public class cadreAppli extends JFrame {
  JPanel contentPane;
  JScrollBar jScrollBar1 = new JScrollBar();
  Border border1;
  JTextField txtValeurHS = new JTextField();
  JScrollBar jScrollBar2 = new JScrollBar();
  JTextField txtValeurVS = new JTextField();
  TitledBorder titledBorder1;

   /**Створити рамку*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
...

// рамка для смуг прокрутки
    border1 = BorderFactory.createBevelBorder(BevelBorder.RAISED,Color.white,Color.white,new Color(134, 134, 134),new Color(93, 93, 93));
        // без заголовка на рамці
    titledBorder1 = new TitledBorder("");

    jScrollBar1.setOrientation(JScrollBar.HORIZONTAL);
    jScrollBar1.setBorder(BorderFactory.createRaisedBevelBorder());
    jScrollBar1.setAutoscrolls(true);
    jScrollBar1.setBounds(new Rectangle(37, 17, 218, 20));
    jScrollBar1.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar1_adjustmentValueChanged(e);
      }
    });

    txtValeurHS.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtValeurHS_actionPerformed(e);
      }
    });

    jScrollBar2.setBounds(new Rectangle(39, 51, 30, 27));
    jScrollBar2.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar2_adjustmentValueChanged(e);
      }
    });
    jScrollBar2.setAutoscrolls(true);
    jScrollBar2.setUnitIncrement(-1);
    jScrollBar2.setBorder(BorderFactory.createRaisedBevelBorder());

    txtValeurVS.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtValeurVS_actionPerformed(e);
      }
    });

    ......
  }

   /**Замінено, щоб можна було вийти, коли вікно закрито*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
    // значення смуги прокрутки 1 змінилося
    txtValeurHS.setText(""+jScrollBar1.getValue());
  }

  void jScrollBar2_adjustmentValueChanged(AdjustmentEvent e) {
    // значення смуги прокрутки 2 змінилося
    txtValeurVS.setText(""+jScrollBar2.getValue());
  }

  void txtValeurHS_actionPerformed(ActionEvent e) {
    // зафіксовано значення горизонтальної смуги прокрутки
    setValeur(jScrollBar1,txtValeurHS);
  }

  void txtValeurVS_actionPerformed(ActionEvent e) {
    // встановлюємо значення вертикальної смуги прокрутки
    setValeur(jScrollBar2,txtValeurVS);
  }

  private void setValeur(JScrollBar jS, JTextField jT){
     // встановлює значення смуги прокрутки jS з текстом поля jT
    int valeur=0;
    try{
      valeur=Integer.parseInt(jT.getText());
      jS.setValue(valeur);
    }
    catch (Exception e){
      // виводиться повідомлення про помилку
      afficher(""+e);
    }//try-catch
  }//setValeur

  void afficher(String message){
    // виводить повідомлення у вікні
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//відобразити

}

Ось приклад виконання:

Image

5.2.5.6. компонент JTextArea

Компонент JTextArea дозволяє вводити кілька рядків тексту, на відміну від компонента JTextField, де можна ввести лише один рядок. Якщо цей компонент розмістити в контейнері з прокруткою (JScrollPane), отримаємо поле введення тексту з прокруткою. Такий тип компонента може зустрічатися, наприклад, у програмі електронної пошти, де текст повідомлення, що надсилається, вводиться у компоненті JTextArea. Звичайними методами є String getText() для отримання вмісту текстового поля, setText(String unTexte) — для введення unTexte у текстове поле, а append(String unTexte) — для додавання unTexte до тексту, що вже міститься у текстовому полі. Розглянемо таку програму:

Image

тип
назва
роль
1
JTextArea
txtTexte
багаторядкове текстове поле
2
JButton
cmdAfficher
відображає вміст 1 у діалоговому вікні
3
JButton
cmdEffacer
очищає вміст 1
4
JTextField
txtAjout
текст, що додається до тексту з позиції 1 після підтвердження клавішею Enter.
5
JScrollPane
jScrollPane1
прокручуваний контейнер, в який розміщено текстове поле 1, щоб отримати прокручуване текстове поле.

Відповідний код такий:

.....

public class cadreAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JButton cmdAfficher = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea txtTexte = new JTextArea();
  JLabel jLabel2 = new JLabel();
  JTextField txtAjout = new JTextField();
  JButton cmdEffacer = new JButton();

  /**Створити фрейм*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {

    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    txtAjout.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtAjout_actionPerformed(e);
      }
    });
    cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdEffacer_actionPerformed(e);
      }
    });
    .......
    jScrollPane1.getViewport().add(txtTexte, null);
  }
   /**Замінено, щоб ми могли вийти, коли вікно закриється*/
  protected void processWindowEvent(WindowEvent e) {
        ........
  }

  void cmdAfficher_actionPerformed(ActionEvent e) {
    // відображає вміст TextArea
    afficher(txtTexte.getText());
  }

    void afficher(String message){
     // відображає повідомлення у вікні
    JOptionPane.showMessageDialog(this,message,"Suivi",JOptionPane.INFORMATION_MESSAGE);
  }// відобразити

  void cmdEffacer_actionPerformed(ActionEvent e) {
    txtTexte.setText("");
  }//cmdEffacer_actionPerformed

  void txtAjout_actionPerformed(ActionEvent e) {
    // додавання тексту
    txtTexte.append(txtAjout.getText());
     // очищення та додавання
    txtAjout.setText("");
  }//
}

5.2.6. Події миші

Під час малювання в контейнері важливо знати положення миші, щоб, наприклад, відобразити точку під час кліка. Переміщення миші викликають події в контейнері, в якому вона переміщується. Ось, наприклад, ті, що пропонує JBuilder для контейнера JPanel:

Image

mouseClicked
клацання мишею
mouseDragged
переміщення миші, натиснута ліва кнопка
mouseEntered
миша щойно увійшла в область контейнера
mouseExited
миша щойно вийшла з області контейнера
mouseMoved
миша рухається
mousePressed
Натискання лівої кнопки миші
mouseReleased
Відпускання лівої кнопки миші

Ось програма, яка допоможе краще зрозуміти, в які моменти відбуваються різні події з мишею:

Image

тип
назва
роль
1
JTextField
txtPosition
для відображення положення миші в контейнері (можливо MouseMoved)
2
JList
lstAffichage
для відображення подій миші, відмінних від MouseMoved
3
JButton
cmdEffacer
для очищення вмісту 2

При запуску цієї програми при натисканні миші отримуємо таке:

Image

Події в списку розташовуються зверху вниз. Отже, на знімку екрана вище показано, що один клік викликає три події в такому порядку:

  1. MousePressed при натисканні кнопки
  2. MouseReleased при відпусканні кнопки
  3. MouseClicked, що вказує на те, що послідовність двох попередніх подій розглядається як клік. Це могло б бути подвійним кліком. Але вище наведена інформація clickCount=1 вказує, що це простий клік.

Тепер, якщо натиснути кнопку, перемістити мишу та відпустити кнопку:

Image

Тут ми бачимо три події:

  1. MousePressed — при першому натисканні кнопки
  2. MouseDragged — під час переміщення миші з натиснутою кнопкою
  3. MouseReleased — при відпусканні кнопки

У двох наведених вище прикладах видно, що подія миші містить різну інформацію, зокрема координати (x, y) миші, наприклад (408,65) у першому рядку вище.

Якщо продовжувати в тому ж дусі, можна виявити, що подія MouseExited спрацьовує, щойно миша залишає контейнер або наводиться на один із його компонентів. В останньому випадку контейнер отримує подію MouseExited, а компонент — подію MouseEntered. Зворотне відбудеться, коли миша залишить компонент і повернеться до контейнера.

Що відбувається під час подвійного клацання?

Image

Події абсолютно такі самі, як і при одинарному кліці. Лише подія містить інформацію clickCount=2 (див. вище), що вказує на те, що насправді відбувся подвійний клік.

Корисний код цього додатка такий:

public class Cadre1 extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtPosition = new JTextField();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel valeurs=new DefaultListModel();
  JList lstAffichage = new JList(valeurs);
  JButton cmdEffacer = new JButton();

  /**Створити рамку*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {

    contentPane.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
      public void mouseMoved(MouseEvent e) {
        contentPane_mouseMoved(e);
      }
      public void mouseDragged(MouseEvent e) {
        contentPane_mouseDragged(e);
      }
    });

    contentPane.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseEntered(MouseEvent e) {
        contentPane_mouseEntered(e);
      }
      public void mouseExited(MouseEvent e) {
        contentPane_mouseExited(e);
      }
      public void mousePressed(MouseEvent e) {
        contentPane_mousePressed(e);
      }
      public void mouseClicked(MouseEvent e) {
        contentPane_mouseClicked(e);
      }
      public void mouseReleased(MouseEvent e) {
        contentPane_mouseReleased(e);
      }
    });

    cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdEffacer_actionPerformed(e);
      }
    });

    jScrollPane1.getViewport().add(lstAffichage, null);

...............
  }
   /**Замінено, щоб ми могли вийти, коли вікно закрито*/
  protected void processWindowEvent(WindowEvent e) {
    .........
  }

  void contentPane_mouseMoved(MouseEvent e) {
    txtPosition.setText("("+e.getX()+","+e.getY()+")");
  }

  void contentPane_mouseDragged(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseEntered(MouseEvent e) {
    afficher(e);
  }

  void afficher(MouseEvent e){
     // відображає подію e у списку lstAffichage
    valeurs.insertElementAt(e,0);
  }

  void contentPane_mouseExited(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mousePressed(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseClicked(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseReleased(MouseEvent e) {
    afficher(e);
  }

  void cmdEffacer_actionPerformed(ActionEvent e) {
     // очищає список
    valeurs.removeAllElements();
  }
}

5.2.7. Створення вікна з меню

Тепер давайте розглянемо, як створити вікно з меню за допомогою JBuilder. Ми створимо таке вікно:

Image

Image

Створіть новий проєкт, який спочатку міститиме порожнє вікно. У списку компонентів «Swing-контейнери» виберіть компонент JMenuBar (див. рис. 1 нижче) і перетягніть його на вікно, яке ви зараз проектуєте.

Image

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

Image

Двічі клацніть на елементі jMenuBar1 вище, щоб отримати доступ до меню в режимі проектування:

Image

1
вставити елемент меню
2
вставити роздільник
3
вставити вкладене меню
4
видалити елемент меню
5
вимкнути пункт меню
6
елемент меню, який потрібно позначити галочкою
7
перемикач

Щоб створити свій перший пункт меню, введіть «Options A» у поле A вище, а потім під ним у такому порядку: A1, A2, роздільник, A3, A4.

Image

Потім поруч:

Image

Використовуйте інструмент 3, щоб вказати, що B3 є вкладеним підменю.

У міру розробки меню логічна структура нашого вікна змінюється:

Image

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

Image

Після цього ви отримаєте доступ до властивостей this:

Image

Одним із них є JMenuBar, яке слугує для визначення меню, що буде пов’язане з вікном. Клацніть у комірці праворуч від JMenuBar. Після цього вам будуть запропоновані всі створені меню. У даному випадку у нас буде лише jMenuBar1. Виберіть його.

Запустіть програму (F9):

Image

Тепер у нас є меню, але опції, поки що, нічого не роблять. Опції меню обробляються як компоненти: вони мають властивості та події. У структурі меню виберіть опцію jMenuItem1:

Image

Після цього ви отримаєте доступ до її властивостей та подій:

Image

Виберіть сторінку подій і клацніть на комірці праворуч від події actionPerformed: це подія, яка відбувається при клацанні на елементі меню. За замовчуванням пропонується процедура обробки. Двічі клацніть на ній, щоб отримати доступ до її коду:

Image

Ми напишемо такий простий код:

  void jMenuItem1_actionPerformed(ActionEvent e) {
    afficher("L'option A1 a été sélectionnée");
  }

  void afficher(String message){
     // відображає повідомлення у вікні
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//відобразити

Запустіть програму та виберіть опцію A1, щоб отримати таке повідомлення:

Image

Корисний код цієї програми такий:

.....

public class Cadre1 extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem jMenuItem1 = new JMenuItem();
  JMenuItem jMenuItem2 = new JMenuItem();
  JMenuItem jMenuItem3 = new JMenuItem();
  JMenuItem jMenuItem4 = new JMenuItem();
  JMenu jMenu2 = new JMenu();
  JMenuItem jMenuItem5 = new JMenuItem();
  JMenuItem jMenuItem6 = new JMenuItem();
  JMenu jMenu3 = new JMenu();
  JMenuItem jMenuItem7 = new JMenuItem();
  JMenuItem jMenuItem8 = new JMenuItem();
  JMenuItem jMenuItem9 = new JMenuItem();

  /**Створити фрейм*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
        // вікно пов'язане з меню
    this.setJMenuBar(jMenuBar1);

    jMenu1.setText("Options A");
    jMenuItem1.setText("A1");
    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jMenuItem1_actionPerformed(e);
      }
    });
    jMenuItem2.setText("A2");
    jMenuItem3.setText("A3");
    jMenuItem4.setText("A4");
    jMenu2.setText("Options B");
    jMenuItem5.setText("B1");
    jMenuItem6.setText("B2");
    jMenu3.setText("B3");
    jMenuItem7.setText("B31");
    jMenuItem8.setText("B32");
    jMenuItem9.setText("B4");
    jMenuBar1.add(jMenu1);
    jMenuBar1.add(jMenu2);
    jMenu1.add(jMenuItem1);
    jMenu1.add(jMenuItem2);
    jMenu1.addSeparator();
    jMenu1.add(jMenuItem3);
    jMenu1.add(jMenuItem4);
    jMenu2.add(jMenuItem5);
    jMenu2.add(jMenuItem6);
    jMenu2.add(jMenu3);
    jMenu2.add(jMenuItem9);
    jMenu3.add(jMenuItem7);
    jMenu3.add(jMenuItem8);
  }
   /**Замінено, щоб ми могли вийти, коли вікно закрито*/
  protected void processWindowEvent(WindowEvent e) {
....
  }

  void jMenuItem1_actionPerformed(ActionEvent e) {
    afficher("L'option A1 a été sélectionnée");
  }

  void afficher(String message){
     // виводить повідомлення у вікні
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//відобразити

}

5.3. Діалогові вікна

5.3.1. Вікна повідомлень

Ми вже використовували клас JOptionPane для відображення повідомлень. Отже, такий код:

import javax.swing.*;

public class dialog1 {
  public static void main(String arg[]){
    JOptionPane.showMessageDialog(null,"Un message","Titre de la boîte",JOptionPane.INFORMATION_MESSAGE);
  }
}

виводить на екран таке вікно:

Image

Коли це вікно закрити, воно зникає, але потік виконання, в якому воно працювало, не зупиняється. Зазвичай такого явища не відбувається. Діалогові вікна використовуються в рамках програми, яка в той чи інший момент використовує команду System.exit(n) для зупинки всіх потоків. Про це слід пам’ятати в наступних прикладах, які побудовані за тим самим зразком. У DOS програму можна перервати за допомогою комбінації клавіш Ctrl-C. З JBuilder слід використовувати опцію «Виконати/Перезапустити програму» (Ctrl-F2). Крім того, першим аргументом команди showMessageDialog тут є null. Зазвичай це не так. Зазвичай це this або this, що позначає головне вікно програми.

5.3.2. Зовнішній вигляд

Зовнішній вигляд вікна, показаного вище, може відрізнятися. Цей вигляд можна налаштувати за допомогою класу javax.swing.UIManager. Коли ми коментували код, згенерований JBuilder для нашого першого вікна, ми натрапили на інструкцію, на якій не зупинялися:

      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

Метод setLookAndFeel класу UIManager (UI = «User Interface») дозволяє задавати зовнішній вигляд графічних інтерфейсів. Клас UIManager має метод, що дозволяє дізнатися про можливі «варіанти зовнішнього вигляду» інтерфейсів:

static UIManager.LookAndFeelInfo[]
getInstalledLookAndFeels()

Цей метод повертає масив елементів типу LookAndFeelInfo. Цей клас має метод:

String
getClassName()

який повертає ім’я класу, що «реалізує» певний стиль. Спробуємо виконати таку програму:

import javax.swing.*;

public class LookAndFeels {
  // відображає доступні стилі інтерфейсу
  public static void main(String[] args) {
    // перелік встановлених стилів інтерфейсу
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    // відображення
    for(int i=0;i<lf.length;i++){
      System.out.println(lf[i].getClassName());
    }//для
  }//головне
}//сортує

Він дає такі результати:

javax.swing.plaf.metal.MetalLookAndFeel
com.sun.java.swing.plaf.motif.MotifLookAndFeel
com.sun.java.swing.plaf.windows.WindowsLookAndFeel

Отже, здається, існує три «різні» «варіанти оформлення». Повернімося до нашої програми відображення повідомлень, випробувавши різні можливі варіанти оформлення:

import javax.swing.*;

public class LookAndFeel2 {
  // відображає доступні стилі інтерфейсу
  public static void main(String[] args) {
    // перелік встановлених стилів інтерфейсу
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    // відображення
    for(int i=0;i<lf.length;i++){
      // менеджер зовнішнього вигляду
      try{
        UIManager.setLookAndFeel(lf[i].getClassName());
      }catch(Exception ex){
        System.err.println(ex.getMessage());
      }//catch
      // повідомлення
      JOptionPane.showMessageDialog(null,"Un message",lf[i].getClassName(),JOptionPane.INFORMATION_MESSAGE);
    }//for
  }//main
}//клас

Результатом виконання є такі виводи:

що відповідають (зправа наліво) «стилям» Metal, Motif, Windows.

5.3.3. Вікна підтвердження

Клас JOptionPane має метод showConfirmDialog для відображення вікон підтвердження з кнопками Oui, Non, Annuler. Існує кілька перевантажених методів showConfirmDialog. Розглянемо один із них:

static int
showConfirmDialog(Component parentComponent, Object message, String title, int optionType)
parentComponent
батьківський компонент діалогового вікна. Зазвичай це вікно або значення null
message
повідомлення, яке потрібно відобразити
title
заголовок діалогового вікна
optionType
JOptionPane.YES_NO_OPTION: кнопки «так», «ні»
JOptionPane.YES_NO_CANCEL_OPTION: кнопки «так», «ні», «скасувати»

Результат, який повертає цей метод:

JOptionPane.YES_OPTION
користувач натиснув «так»
JOptionPane.NO_OPTION
користувач натиснув «Ні»
JOptionPane.CANCEL_OPTION
користувач натиснув «Скасувати»
JOptionPane.CLOSED_OPTION
користувач закрив вікно

Ось приклад:

import javax.swing.*;

public class confirm1 {
  public static void main(String[] args) {
    // відображає вікна підтвердження
    int réponse;
    affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_OPTION));
    affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_CANCEL_OPTION));
  }//головна

  private static void affiche(int réponse){
     // вказує, який тип відповіді було отримано
    switch(réponse){
      case JOptionPane.YES_OPTION :
        System.out.println("Oui");
        break;
      case JOptionPane.NO_OPTION :
        System.out.println("Non");
        break;
      case JOptionPane.CANCEL_OPTION :
        System.out.println("Annuler");
        break;
      case JOptionPane.CLOSED_OPTION :
        System.out.println("Fermeture");
        break;
    }//комутатор
  }//дисплей
}//класифікувати

На консолі відображаються повідомлення Non та Annuler.

5.3.4. Поле введення

Клас JOptionPane також надає можливість введення даних за допомогою методу showInputDialog. І тут, як і раніше, існує кілька перевантажених методів. Ми розглянемо один із них:

static String
showInputDialog(Component parentComponent, Object message, String title, int messageType)

Аргументи вже неодноразово зустрічалися раніше. Цей метод повертає рядок, введений користувачем. Ось приклад:

import javax.swing.*;

public class input1 {
  public static void main(String[] args) {
    // введення
    System.out.println("Chaîne saisie ["+
      JOptionPane.showInputDialog(null,"Quel est votre nom","Saisie du nom",JOptionPane.QUESTION_MESSAGE )
      + "]");
  }//рука
}//клас

Вигляд поля введення:

Image

Вигляд консолі:

Chaîne saisie [dupont]

5.4. Поля вибору

Тепер розглянемо кілька попередньо визначених полів вибору в Java 2:

JFileChooser
поле вибору, що дозволяє вказати файл у дереві файлів
JColorChooser
поле вибору, що дозволяє вибрати колір

5.4.1. Поле вибору JFileChooser

Ми створимо такий додаток:

Image

Елементи управління такі:

тип
назва
роль
0
JScrollPane
jScrollPane1
Прокручуваний контейнер для текстового поля 1
1
JTextArea сам у JScrollPane
txtTexte
текст, введений користувачем або завантажений із файлу
2
JButton
btnSauvegarder
дозволяє зберегти текст з пункту 1 у текстовому файлі
3
JButton
btnCharger
дозволяє завантажити вміст текстового файлу в 1
4
JButton
btnEffacer
очищає вміст 1

Використовується невидимий елемент управління: jFileChooser1. Він береться з палітри контейнерів Swing елемента JBuilder:

Image

Ми розміщуємо компонент у вікні проектування, але поза межами форми. Він з’являється у списку компонентів:

Image

Тепер наведемо відповідний код програми, щоб отримати загальне уявлення про неї:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;

public class dialogues extends JFrame {
   // компоненти фрейму
  JPanel contentPane;
  JButton btnSauvegarder = new JButton();
  JButton btnCharger = new JButton();
  JButton btnEffacer = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea txtTexte = new JTextArea();
  JFileChooser jFileChooser1 = new JFileChooser();

  // фільтри файлів
  javax.swing.filechooser.FileFilter filtreTxt = null;

   //Створити фрейм
  public dialogues() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
       // інші ініціалізації
      moreInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

   // moreInit
  private void moreInit(){
     // ініціалізації під час побудови вікна
     // фільтр *.txt
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // чи допускається f?
        return f.getName().toLowerCase().endsWith(".txt");
      }//прийнято
      public String getDescription(){
        // опис фільтра
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // додаємо фільтр
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // також потрібно додати фільтр для всіх файлів
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // встановлюємо початковий каталог коробки FileChooser як поточний каталог
    jFileChooser1.setCurrentDirectory(new File("."));
  }

   //Ініціалізуємо компонент
  private void jbInit() throws Exception  {
.......................
  }
   //Замінено, щоб можна було вийти після закриття вікна
  protected void processWindowEvent(WindowEvent e) {
......................
    }
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    // вибір файлу за допомогою обєкта JFileChooser

     // встановлюємо початковий фільтр
    jFileChooser1.setFileFilter(filtreTxt);
     // відображається вікно вибору
    int returnVal = jFileChooser1.showOpenDialog(this);
    // чи вибрав користувач щось?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // вставляємо файл у текстове поле
       lireFichier(jFileChooser1.getSelectedFile());
    }//if
  }//btnCharger_actionPerformed

  // lireFichier
  private void lireFichier(File fichier){
     // відображає вміст текстового файлу у текстовому полі

     // очищає текстове поле
    txtTexte.setText("");

     // деякі дані
    BufferedReader IN=null;
    String ligne=null;
    try{
      // відкриття файлу для читання
      IN=new BufferedReader(new FileReader(fichier));
      // файл читається по рядках
      while((ligne=IN.readLine())!=null){
        txtTexte.append(ligne+"\n");
      }//while
       // закриття файлу
      IN.close();
    }catch(Exception ex){
       // сталася помилка
      txtTexte.setText(""+ex);
    }//catch
  }

  // очищення
  void btnEffacer_actionPerformed(ActionEvent e) {
    // очищення текстового поля
    txtTexte.setText("");
  }

   // зберегти
  void btnSauvegarder_actionPerformed(ActionEvent e) {
     // зберегти вміст текстового поля у файл

     // встановлює початковий фільтр
    jFileChooser1.setFileFilter(filtreTxt);
     // відображається вікно вибору місця збереження
    int returnVal = jFileChooser1.showSaveDialog(this);
    // Чи вибрав користувач щось?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // записуємо вміст текстового поля у файл
       écrireFichier(jFileChooser1.getSelectedFile());
    }//if
  }

   // lireFichier
  private void écrireFichier(File fichier){
     // записує вміст текстового поля у файл

     // деякі дані
    PrintWriter PRN=null;
    try{
       // відкриття файлу для запису
      PRN=new PrintWriter(new FileWriter(fichier));
      // записує вміст текстового поля
      PRN.print(txtTexte.getText());
       // закриття файлу
      PRN.close();
    }catch(Exception ex){
       // сталася помилка
      txtTexte.setText(""+ex);
    }//обробка помилки
  }

Ми не будемо коментувати код методів btnEffacer_Click, lireFichier та écrireFichier, оскільки вони не містять нічого нового. Зупинимося на класі JFileChooser та його використанні. Цей клас є складним, на кшталт «заплутаної конструкції». Тут ми використовуємо лише такі методи:

addChoosableFilter(FileFilter)
визначає типи файлів, що пропонуються для вибору
setAcceptAllFileFilterUsed(boolean)
вказує, чи слід пропонувати тип «Усі файли» для вибору
File getSelectedFile()
файл (File), обраний користувачем
int showSaveDialog()
метод, що відображає діалогове вікно вибору місця збереження. Повертає результат типу int. Значення jFileChooser.APPROVE_OPTION вказує, що користувач зробив правильний вибір. В іншому випадку він або скасував вибір, або сталася помилка.
setCurrentDirectory
для встановлення початкового каталогу, з якого користувач почне перегляд файлової системи
setFileFilter(FileFilter)
для встановлення активного фільтра

Метод showSaveDialog відображає вікно вибору, подібне до наведеного нижче:

Image

1
випадаючий список, створений за допомогою методу addChoosableFilter. Він містить так звані фільтри вибору, представлені класом FileFilter. Розробник повинен самостійно визначити ці фільтри та додати їх до списку 1.
2
поточний каталог, встановлений методом setCurrentDirectory, якщо цей метод було використано; в іншому випадку поточним каталогом буде папка «Мої документи» у Windows або домашній каталог у Unix.
3
ім’я файлу, обране або введене безпосередньо користувачем. Буде доступне за допомогою методу getSelectedFile()
4
кнопки «Зберегти»/«Скасувати». Якщо використовується кнопка Enregistrer, метод showSaveDialog повертає результат jFileChooser.APPROVE_OPTION

Як створюються фільтри файлів у випадаючому списку 1? Фільтри додаються до списку 1 за допомогою методу:

addChoosableFilter(FileFilter)
визначає типи файлів, що пропонуються для вибору

класу JFileChooser. Нам залишається ознайомитися з класом FileFilter. Насправді це клас javax.swing.filechooser.FileFilter, який є абстрактним класом c.a.d — класом, який не можна інстанціювати, а лише успадковувати. Він визначається наступним чином:

FileFilter()
конструктор
boolean accept(File)
вказує, чи належить файл f до фільтра чи ні
String getDescription()
рядок з описом фільтра

Розглянемо приклад. Ми хочемо, щоб у випадаючому списку 1 був доступний фільтр для вибору файлів *.txt з описом «Текстові файли (*.txt)».

  • нам потрібно створити клас, похідний від класу FileFilter
  • використати метод boolean accept(File f), щоб повернути значення true, якщо ім’я файлу f закінчується на .txt
  • використати метод String getDescription(), щоб повернути опис «Текстові файли (*.txt)»

Цей фільтр можна визначити в нашому додатку наступним чином:

  javax.swing.filechooser.FileFilter filtreTxt = new javax.swing.filechooser.FileFilter(){
    public boolean accept(File f){
      // чи приймається f?
      return f.getName().toLowerCase().endsWith(".txt");
    }//прийнято
    public String getDescription(){
      // опис фільтра
      return "Fichiers Texte (*.txt)";
    }//getDescription
  };

Цей фільтр буде додано до списку фільтрів об’єкта jFileChooser1 за допомогою інструкції:

     // додаємо фільтр *.txt
    jFileChooser1.addChoosableFileFilter(filtretxt);

Усе це та деякі інші ініціалізації виконуються в методі moreInit, що запускається під час створення вікна (див. повну програму вище). Код кнопки Sauvegarder такий:

  void btnSauvegarder_actionPerformed(ActionEvent e) {
    // зберігає вміст текстового поля у файлі

     // встановлює початковий фільтр
    jFileChooser1.setFileFilter(filtreTxt);
     // відображається вікно вибору місця збереження
    int returnVal = jFileChooser1.showSaveDialog(this);
    // Чи вибрав користувач щось?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // записує вміст текстового поля у файл
       écrireFichier(jFileChooser1.getSelectedFile());
    }//if
  }

Послідовність операцій така:

  • активний фільтр встановлюється на *.txt, щоб користувач міг переважно шукати файли цього типу. Також доступний фільтр «Усі файли». Він був доданий у процедурі moreInit. Отже, маємо два фільтри.
  • відображається діалогове вікно вибору файлу для збереження. Тут ми втрачаємо контроль, оскільки користувач використовує це діалогове вікно для вибору файлу з файлової системи.
  • коли він залишає вікно вибору, перевіряється значення, що повертається, щоб визначити, чи потрібно зберігати текстове поле. Якщо так, його слід зберегти у файлі, отриманому за допомогою методу getSelectedFile.

Код, пов’язаний із кнопкою «Завантажити», дуже схожий на код кнопки «Зберегти».

  void btnCharger_actionPerformed(ActionEvent e) {
    // вибір файлу за допомогою об’єкта JFileChooser

     // встановлюємо початковий фільтр
    jFileChooser1.setFileFilter(filtreTxt);
     // відображення діалогового вікна вибору
    int returnVal = jFileChooser1.showOpenDialog(this);
    // Чи вибрав користувач щось?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // вставляємо файл у текстове поле
       lireFichier(jFileChooser1.getSelectedFile());
    }//if
  }//btnCharger_actionPerformed

Є дві відмінності:

  • для відображення вікна вибору файлів використовується метод showOpenDialog замість методу showSaveDialog. Вікно вибору, що відображається, аналогічне тому, яке відображається методом showSaveDialog.
  • якщо користувач успішно вибрав файл, викликається метод lireFichier замість методу écrireFichier.

5.4.1.1. Вікна вибору JColorChooser та JFontChooser

Продовжуємо попередній приклад, додавши дві нові кнопки:

Image

тип
назва
роль
6
JButton
btnCouleur
для визначення кольору символів у TextBox
7
JButton
btnPolice
для встановлення шрифту TextBox

Компонент JColorChooser, що дозволяє відобразити вікно вибору кольору, можна знайти у списку Swing-компонентів JBuilder:

Image

Ми розміщуємо цей компонент у вікні дизайну, але поза межами форми. Він не відображається у формі, але все ж присутній у списку компонентів вікна:

Image

Клас JColorChooser дуже простий. Вікно вибору кольорів відображається за допомогою методу int showDialog:

static Color
showDialog(Component component, String title, Color initialColor)
Component component
батьківський компонент діалогового вікна вибору, зазвичай вікно JFrame
String title
заголовок у рядку заголовка діалогового вікна вибору
Колір intialColor
колір, спочатку вибраний у полі вибору

Якщо користувач вибирає колір, метод повертає колір, інакше — значення null. Код, пов'язаний із кнопкою Couleur, такий:

  void btnCouleur_actionPerformed(ActionEvent e) {
     // вибір кольору тексту за допомогою компонента JColorChooser
    Color couleur;
    if((couleur=jColorChooser1.showDialog(this,"Choix d'une couleur",Color.BLACK))!=null){
       // встановлення кольору символів у текстовому полі
      txtTexte.setForeground(couleur);
    }//if
  }

Клас Color визначено в java.awt.Color. У ньому визначено різні константи, зокрема Color.BLACK для чорного кольору. Відображається таке вікно вибору

Image

Досить дивно, але бібліотека Swing не пропонує класу для вибору шрифту. На щастя, є Java-ресурси в Інтернеті. Здійснивши пошук за ключовим словом «JFontChooser», яке здається можливою назвою для такого класу, можна знайти кілька варіантів. Наступний приклад дасть нам можливість налаштувати JBuilder так, щоб він використовував пакети, не передбачені в його початковій конфігурації.

Отриманий пакет називається swingextras.jar і розміщений у папці <jdk>\jre\lib\perso, де <jdk> позначає каталог інсталяції JDK, який використовує JBuilder. Він міг бути розміщений будь-де в іншому місці.

Давайте розглянемо вміст пакета SwingExtras.jar:

Image

Тут міститься вихідний код Java для компонентів, що входять до складу пакета. Також тут містяться самі класи:

Image

З цього архіву слід зауважити, що клас JFontChooser насправді називається com.lamatek.swingextras.JFontChooser. Якщо ми не хочемо писати повну назву, нам доведеться на початку програми написати:

import com.lamatek.swingextras.*;

Як компілятор і віртуальна машина Java знайдуть цей новий пакет? У випадку прямого використання JDK це вже було пояснено, і читач може ознайомитися з поясненнями в розділі про пакети Java. Тут ми детально опишемо метод, який слід використовувати з JBuilder. Пакет налаштовується в меню «Параметри»/«Налаштувати JDK»:

Image

1
Кнопка Modifier (1) дозволяє вказати JBuilder, який JDK використовувати. У цьому прикладі JBuilder приніс із собою JDK 1.3.1. Коли вийшов JDK 1.4, його було встановлено окремо від JBuilder, і за допомогою кнопки Modifier було вказано JBuilderвідтепер використовувати JDK 1.4, вказавши каталог його встановлення
2
базовий каталог JDK, який наразі використовується JBuilder
3
список архівів Java (.jar), які використовує JBuilder. Інші архіви можна додати за допомогою кнопки Ajouter (4)
4
Кнопка Ajouter (4) дозволяє додавати нові пакети, які JBuilder використовуватиме як для компіляції, так і для виконання програм. Тут її використано для додавання пакета SwingExtras.jar (5)

Тепер JBuilder налаштований належним чином для використання класу JFontChooser. Однак для його правильного використання нам потрібен доступ до визначення цього класу. Архів swingextras.jar містить HTML-файли, які можна витягти для подальшого використання. У цьому немає потреби. До документації Java, що міститься у файлах .jar, можна отримати прямий доступ із JBuilder. Для цього потрібно налаштувати вкладку Documentation (6), показану вище. З’явиться таке нове вікно:

Image

Кнопка Ajouter дозволяє вказати, що файл SwingExtras.jar має бути просканований на наявність документації. Після підтвердження цієї дії можна переконатися, що ми дійсно маємо доступ до документації SwingExtras.jar. Це надає низку зручностей:

  • якщо почати вводити команду імпорту
import com.lamatek.swingextras.*;

, можна помітити, що JBuilder надає нам підказку:

Image

Пакет com.lamatek знайдено.

  • А тепер перейдемо до наступної програми:
import com.lamatek.swingextras.*;

public class test{
  JFontChooser jFontChooser1=null;
}  

виконуємо F1 для ключового слова JFontChooser, отримуємо довідку щодо цього класу:

Image

У рядку стану 1 видно, що дійсно використовується HTML-файл із пакета swingextras.jar. Наведений вище приклад є достатньо зрозумілим, щоб ми могли написати код кнопки Police для нашого додатка:

  void btnPolice_actionPerformed(ActionEvent e) {
    // вибір шрифту тексту за допомогою компонента JFontChooser
    jFontChooser1 = new JFontChooser(new Font("Arial", Font.BOLD, 12));
    if (jFontChooser1.showDialog(this, "Choix d'une police") == JFontChooser.ACCEPT_OPTION) {
      // зміна шрифту символів у текстовому полі
      txtTexte.setFont(jFontChooser1.getSelectedFont());
    }//if
  }

Вікно вибору, яке відображається методом showDialog, наведеним вище, виглядає наступним чином:

Image

5.5. Графічний додаток IMPOTS

Повернемося до програми IMPOTS, яку ми вже двічі розглядали. Тепер додамо до неї графічний інтерфейс:

Image

Елементи управління такі

тип
назва
роль
1
JRadioButton
rdOui
позначте, якщо одружений
2
JRadioButton
rdNon
позначте, якщо не одружений
3
JSpinner
spinEnfants
кількість дітей платника податків
Мінімальне значення = 0, Максимальне значення = 20, Крок = 1
4
JTextField
txtSalaire
річний дохід платника податків у F
5
JLabel
lblImpots
сума податку до сплати
6
JTextField
txtStatus
поле повідомлень про стан — не підлягає редагуванню

Меню виглядає наступним чином:

головна опція
додаткова опція
ім'я
роль
Податки
   
 
Ініціалізувати
mnuInitialiser
завантажує дані, необхідні для розрахунку, з текстового файлу
 
Обчислити
mnuCalculer
розраховує суму податку до сплати, якщо всі необхідні дані наявні та правильні
 
Скинути
mnuEffacer
повертає форму до початкового стану
 
Вийти
mnuQuitter
завершує роботу програми

Правила роботи

  • меню Calculer залишається вимкненим, доки в полі «зарплата» немає даних
  • якщо під час запуску розрахунку виявляється, що зарплата вказана неправильно, з’являється повідомлення про помилку:

Image

Програма наведена нижче. Вона використовує клас impots, створений у розділі про класи. Частина коду, що автоматично генерується JBuilder, тут не наведена.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
import java.util.*;
import javax.swing.event.*;

public class frmImpots extends JFrame {
  // компоненти вікна
  JPanel contentPane;
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem mnuInitialiser = new JMenuItem();
  JMenuItem mnuCalculer = new JMenuItem();
  JMenuItem mnuEffacer = new JMenuItem();
  JMenuItem mnuQuitter = new JMenuItem();
  JLabel jLabel1 = new JLabel();
  JFileChooser jFileChooser1 = new JFileChooser();
  JTextField txtStatus = new JTextField();
  JRadioButton rdOui = new JRadioButton();
  JRadioButton rdNon = new JRadioButton();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSalaire = new JTextField();
  JLabel jLabel4 = new JLabel();
  JLabel jLabel5 = new JLabel();
  JLabel lblImpots = new JLabel();
  JLabel jLabel7 = new JLabel();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JSpinner spinEnfants=null;
  FileFilter filtreTxt=null;

   // атрибути класу
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;

   //Створити фрейм
  public frmImpots() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // інші ініціалізації
    moreInit();
  }

   // ініціалізація форми
  private void moreInit(){
     // меню «Обчислити» заблоковано
    mnuCalculer.setEnabled(false);
    // поля введення заблоковано
    txtSalaire.setEditable(false);
    txtSalaire.setBackground(Color.WHITE);
    // поле стану
    txtStatus.setBackground(Color.WHITE);
    // список «Діти»  від 0 до 20 дітей
    spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);
     // фільтр *.txt для списку вибору
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // чи допускається «f»?
        return f.getName().toLowerCase().endsWith(".txt");
      }//accept
      public String getDescription(){
        // опис фільтра
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // додаємо фільтр *.txt
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // також потрібно додати фільтр для всіх файлів
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // встановлюємо вихідний каталог скриньки FileChooser
    jFileChooser1.setCurrentDirectory(new File("."));
  }//moreInit

   //Ініціалізуємо компонент
  private void jbInit() throws Exception  {

................

  }

   //Замінено, щоб можна було вийти після закриття вікна
  protected void processWindowEvent(WindowEvent e) {
.....................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // завершуємо роботу програми
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // завантажуємо файл даних
     // який вибирається за допомогою вікна вибору JFileChooser1
    jFileChooser1.setFileFilter(filtreTxt);
    if (jFileChooser1.showOpenDialog(this)!=JFileChooser.APPROVE_OPTION)
      return;
     // обробляється вибраний файл
    try{
       // читання даних
      lireFichier(jFileChooser1.getSelectedFile());
       // створення об’єкта «податки»
      objImpots=new impots(limites,coeffr,coeffn);
       // підтвердження
      txtStatus.setText("Données chargées");
       // зарплату можна змінити
      txtSalaire.setEditable(true);
       // більше змін неможливо
      mnuInitialiser.setEnabled(false);
    }catch(Exception ex){
       // проблема
      txtStatus.setText("Erreur : " + ex.getMessage());
      // кінець
      return;
    }//вилов
  }

  private void lireFichier(File fichier) throws Exception {
     // таблиці даних
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // відкриття файлу для читання
    BufferedReader IN=new BufferedReader(new FileReader(fichier));
    // файл читається по рядках
     // вони мають вигляд: межа coeffr coeffn
    String ligne=null;
    int numLigne=0;           // номер поточного рядка
    while((ligne=IN.readLine())!=null){
      // ще один рядок
      numLigne++;
       // розбиваємо рядок на поля
      champs=ligne.split("\\s+");
       // 3 поля?
      if(champs.length!=3)
        throw new Exception("ligne " + numLigne + "erronée dans fichier des données");
       // отримуємо три поля
       aLimites.add(champs[0]);
       aCoeffR.add(champs[1]);
       aCoeffN.add(champs[2]);
    }//while
     // закриття файлу
    IN.close();
     // перенесення даних у обмежені масиви
    int n=aLimites.size();
    limites=new double[n];
    coeffr=new double[n];
    coeffn=new double[n];
    for(int i=0;i<n;i++){
      limites[i]=Double.parseDouble((String)aLimites.get(i));
      coeffr[i]=Double.parseDouble((String)aCoeffR.get(i));
      coeffn[i]=Double.parseDouble((String)aCoeffN.get(i));
    }//for
  }

  void mnuCalculer_actionPerformed(ActionEvent e) {
    // розрахунок податку
     // перевірка заробітної плати
    int salaire=0;
    try{
      salaire=Integer.parseInt(txtSalaire.getText().trim());
      if(salaire<0) throw new Exception();
    }catch (Exception ex){
       // повідомлення про помилку
      txtStatus.setText("Salaire incorrect. Recommencez");
       // фокус на полі з помилкою
      txtSalaire.requestFocus();
       // повернення до інтерфейсу
      return;
    }
     // кількість дітей
    Integer InbEnfants=(Integer)spinEnfants.getValue();
     // розрахунок податку
    lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),InbEnfants.intValue(),salaire));
     // видалення повідомлення про стан
    txtStatus.setText("");
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
     // зарплата змінилася  оновлюємо меню «Розрахувати»
    mnuCalculer.setEnabled(! txtSalaire.getText().trim().equals(""));
  }

  void mnuEffacer_actionPerformed(ActionEvent e) {
    // очищення форми
    rdNon.setSelected(true);
    spinEnfants.getModel().setValue(new Integer(0));
    txtSalaire.setText("");
    mnuCalculer.setEnabled(false);
    lblImpots.setText("");
  }
}

Тут ми використали компонент, доступний лише починаючи з версії JDK 1.4, — JSpinner. Це інкрементатор, який у даному випадку дозволяє користувачеві встановити кількість дочірніх елементів. Цей компонент Swing не був доступний у панелі компонентів Swing версії JBuilder 6, яка використовувалася для тестування. Це не заважає його використанню, хоча процес дещо складніший, ніж у випадку з компонентами, доступними в панелі компонентів. Дійсно, компонент JSpinner неможливо розмістити на формі під час проектування. Це потрібно зробити під час виконання. Давайте розглянемо код, який це реалізує:

     // спиннер «Діти» — від 0 до 20 дітей
    spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);

Перший рядок створює компонент JSpinner. Цей компонент може використовуватися для різних цілей, а не лише як інкрементатор цілих чисел, як у цьому випадку. Аргументом конструктора JSpinner тут є шаблон інкрементатора чисел, що приймає чотири параметри (значення, мінімум, максимум, крок). Компонент має такий вигляд:

Image

valeur
початкове значення, що відображається в компоненті
min
мінімальне значення, яке можна відобразити в компоненті
max
максимальне значення, яке може відображатися в компоненті
incrément
значення кроку зміни відображуваного значення при використанні стрілок «вгору»/«вниз» компонента

Значення компонента отримується за допомогою його методу getValue, який повертає тип Object. Тому потрібно виконати кілька перетворень типів, щоб отримати потрібне ціле число:

     // кількість дітей
    Integer InbEnfants=(Integer)spinEnfants.getValue();
     // розрахунок податку
    lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),
      InbEnfants.intValue(),salaire));

Після визначення компонента JSpinner він розміщується у вікні:

    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);

Перш за все, користувач повинен скористатися пунктом меню Initialiser, який створює об’єкт impots за допомогою конструктора

    public impots(double[] LIMITES, double[] COEFFR, double[] COEFFN) throws Exception

класу impots. Нагадаємо, що цей клас було визначено у прикладі в розділі про класи. У разі потреби зверніться до нього. Три масиви, необхідні для конструктора, заповнюються на основі вмісту текстового файлу такого формату:

12620.0
0
0
13190
0,05
631
15640
0,1
1290,5
24740
0,15
2072,5
31810
0,2
3309,5
39970
0,25
4900
48360
0,3
6898,5
55790
0,35
9316,5
92970
0,4
12106
127860
0,45
16754,5
151250
0,50
23147,5
172040
0,55
30710
195 000
0,60
39312
0
0,65
49062

Кожен рядок містить три числа, розділені щонайменше одним пробілом. Цей текстовий файл вибирається користувачем за допомогою компонента JFileChooser. Після створення об’єкта типу impots залишається лише дати користувачеві можливість ввести три необхідні дані: одружений чи ні, кількість дітей, річний оклад, а потім викликати метод calculer класу impots. Цю операцію можна повторювати кілька разів. Об’єкт типу impots створюється лише один раз під час використання опції Initialiser.

5.6. Написання аплетів

5.6.1. Вступ

Якщо ви написали програму з графічним інтерфейсом, її досить легко перетворити на applet. Збережена на комп'ютері А, її можна завантажити за допомогою веб-браузера з комп'ютера Б через Інтернет. Таким чином, початкова програма стає доступною для багатьох користувачів, і саме в цьому полягає головна перевага перетворення програми на аплет. Проте не кожну програму можна перетворити таким чином: щоб не створювати незручностей для користувача, який використовує аплет у своєму браузері, середовище аплету регламентоване:

  • аплет не може читати або записувати дані на диск користувача
  • вона може взаємодіяти лише з тим комп’ютером, з якого її завантажив браузер.

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

Загальна структура простого веб-додатка така:

Image

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

5.6.2. Клас JApplet

5.6.2.1. Définition

Додаток може бути завантажений веб-браузером, якщо він є екземпляром класу java.applet.Applet або класу javax.swing.JApplet. Останній походить від першого, який, у свою чергу, походить від класу Panel, що походить від класу Container. Оскільки екземпляр класу Applet або JApplet належить до типу container, він може містити компоненти (Component), такі як кнопки, прапорці, списки тощо. Наведемо кілька вказівок щодо ролі різних методів:

Метод
Роль
public void destroy();
знищує екземпляр аплету
public AppletContext getAppletContext();
отримує контекст виконання аплету (документ HTML, у якому він знаходиться, інші аплети того самого документа тощо)
public String getAppletInfo();
повертає рядок, що містить інформацію про аплет
public AudioClip getAudioClip(URL url);
завантажує аудіофайл, вказаний URL
public AudioClip getAudioClip(URL url, String name);
завантажує аудіофайл, вказаний параметром URL/name
public URL getCodeBase();
повертає URL аплету
public URL getDocumentBase();
повертає URL з документа HTML, що містить аплет
public Image getImage(URL url);
отримує зображення, вказане параметром URL
public Image getImage(URL url, String name);
отримує зображення, вказане параметром URL/name
public String getParameter(String name);
отримує значення параметра name, що міститься в тезі <applet> документа HTML, який містить аплет.
public void init();
цей метод викликається браузером під час першого запуску аплету
public boolean isActive();
стан аплету
public void play(URL url);
відтворює звуковий файл, вказаний параметром URL
public void play(URL url, String name);
відтворює звуковий файл, вказаний за UR/name
public void resize(Dimension d);
встановлює розмір рамки аплету
public void resize(int width, int height);
те саме
public final void setStub(AppletStub stub);
 
public void showStatus(String msg);
виводить повідомлення у станній панелі аплету
public void start();
цей метод запускається браузером при кожному відображенні документа, що містить аплет
public void stop();
цей метод викликається браузером щоразу, коли документ, що містить аплет, замінюється іншим (користувач змінює URL)

Клас JApplet вніс деякі вдосконалення до класу Applet, зокрема можливість містити компоненти JMenuBar та c.a.d. меню, що було неможливо у класі Applet.

5.6.2.2. Виконання аплету: методи init, start та stop

Коли браузер завантажує аплет, він викликає три його методи:

init
Цей метод викликається під час початкового завантаження аплету. Тому в ньому слід розмістити необхідні для програми ініціалізації.
start
Цей метод викликається щоразу, коли документ, що містить аплет, стає поточним документом браузера. Отже, коли користувач завантажує аплет, методи init та start виконуються саме в такому порядку. Коли він покине цей документ, щоб переглянути інший, буде виконано метод stop. Коли він повернеться до нього пізніше, буде виконано метод start.
stop
Цей метод викликається щоразу, коли користувач залишає документ, що містить аплет.

Для багатьох аплетів потрібен лише метод init. Методи start і stop потрібні лише в тому випадку, якщо програма запускає завдання (потоки), які виконуються паралельно й безперервно, часто без відома користувача. Коли користувач залишає документ, видима частина програми зникає, але ці фонові завдання продовжують працювати. Це часто є зайвим. Тоді для їх зупинки використовується виклик браузером методу stop. Якщо користувач повертається до документа, для їх повторного запуску використовується виклик браузером методу **start**.

Візьмемо, наприклад, аплет, який має годинник у своєму графічному інтерфейсі. Його роботу підтримує фонове завдання (потік). Коли користувач у браузері залишає сторінку аплету, немає сенсу підтримувати годинник, який став невидимим: у методі stop** аплету ми зупинимо потік, що керує годинником. У методі start** його запускають знову, щоб, коли користувач повернеться на сторінку аплету, він побачив годинник, що показує правильний час.

5.6.3. Перетворення графічного додатка на аплет

Тут припускаємо, що таке перетворення можливе, тобто воно відповідає обмеженням щодо виконання аплетів. Додаток запускається методом main одного з його класів:


public class application{
    
    public static main void(String arg[]){
        
    }
    
}// кінець класу

Такий код перетворюється на аплет наступним чином:

import java.applet.JApplet;

public class application extends JApplet{
    
    public void init(){
        
    }
    
}// кінець класу

Слід звернути увагу на наступні моменти:

  1. клас application тепер походить від класу JApplet
  2. метод main замінено на метод init.

Як приклад, повернемося до розглянутого раніше додатка: управління списками.

Image

Компоненти цього вікна такі:

тип
назва
роль
1
JTextField
txtSaisie
поле введення
2
JList
jList1
список, що міститься в контейнері jScrollPane1
3
JList
jList2
список, що міститься в контейнері jScrollPane2
4
JButton
cmd1To2
переносить вибрані елементи зі списку 1 до списку 2
5
JButton
cmd2To1
виконує зворотну операцію
6
JButton
cmdRaz1
очистити список 1
7
JButton
cmdRaz2
очистити список 2

Структура програми була такою:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**Створити таблицю*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Ініціалізація компонента*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         // Jlist1 розміщено в контейнері jScrollPane1
    jScrollPane1.getViewport().add(jList1, null);
        // Jlist2 розміщено в контейнері jScrollPane2
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**Замінено, щоб ми могли вийти, коли вікно закрито*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
.............
}//клас
  void cmd1To2_actionPerformed(ActionEvent e) {
..........
  }//перенесення
  void cmdRaz1_actionPerformed(ActionEvent e) {
    // очистити список 1
    v1.removeAllElements();
  }//команда Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // очистити список 2
    v2.removeAllElements();
  }///команда Raz2

Щоб перетворити клас appli на applet, необхідно виконати такі дії:

  • змінити попередній клас interfaceAppli так, щоб він походив не від JFrame, а від JApplet:
public class interfaceAppli extends JApplet {
  • видалити інструкцію, що визначає заголовок вікна JFrame. Аплет JApplet не має панелі заголовка
    // this.setTitle("JList");
  • змінити конструктор на метод init і в цьому методі видалити обробку подій вікна (WindowListener, ...). Аплет — це контейнер, розмір якого не можна змінювати, і який не можна закрити.
   /**Створити фрейм*/
  public init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli
  • Метод processWindowEvent слід видалити або закомментувати
   /**Замінено, щоб ми могли вийти, коли вікно закрито*/
  //protected void processWindowEvent(WindowEvent e) {
  //  super.processWindowEvent(e);
  //  if (e.getID() == WindowEvent.WINDOW_CLOSING) {
  //    System.exit(0);
  //  }
  // }

Як приклад наводимо повний код аплету, за винятком частини, що генерується автоматично за допомогою JBuilder

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceAppli extends JApplet {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**Створити фрейм*/
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Ініціалізувати компонент*/
  private void jbInit() throws Exception  {
    //setIconImage(Toolkit.getDefaultToolkit().createImage(interfaceAppli.class.getResource("[Votre icône]")));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(400, 308));
    // this.setTitle("JList");
    jScrollPane1.setBounds(new Rectangle(37, 133, 124, 101));
    jScrollPane2.setBounds(new Rectangle(232, 132, 124, 101));
.............
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
     // текст, введений користувачем, було перевірено
     // його отримуємо, видаливши пробіли на початку та в кінці
    String texte=txtSaisie.getText().trim();
     // якщо він порожній, його не враховують
    if(texte.equals("")){
      // повідомлення про помилку
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      // кінець
      return;
    }//if
    // якщо він не порожній, додаємо його до значень списку 1
    v1.addElement(texte);
     // і очищаємо поле введення
    txtSaisie.setText("");
  }

  void cmd1To2_actionPerformed(ActionEvent e) {
    // перенесення вибраних елементів зі списку 1 до списку 2
    transfert(jList1,jList2);
  }//cmd1To2

  private void transfert(JList L1, JList L2){
      // перенесення вибраних елементів зі списку 1 до списку 2
       // отримуємо масив індексів вибраних елементів у L1
      int[] indices=L1.getSelectedIndices();
      // що робити?
      if (indices.length==0) return;
      // отримуємо значення з L1
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      // та з L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // додаємо до L2 значення, вибрані з L1
        v2.addElement(v1.elementAt(indices[i]));
        // елементи з L1, скопійовані в L2, потрібно видалити з L1
        v1.removeElementAt(indices[i]);
      }//для
  }//перенесення

  private void affiche(String message){
    // відображає повідомлення
      JOptionPane.showMessageDialog(this,message,
        "Suivi",JOptionPane.INFORMATION_MESSAGE);
  }// відображає

  void cmd2To1_actionPerformed(ActionEvent e) {
    // передача вибраних елементів з jList2 до jList1
      transfert(jList2,jList1);
  }//cmd2TO1

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // очистити список 1
    v1.removeAllElements();
  }//команда Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // порожній список 2
    v2.removeAllElements();
  }//команда «Очистити 2»

}//клас

Можна скомпілювати вихідний код цього аплету. Ми робимо це тут за допомогою JDK, без JBuilder.

E:\data\serge\Jbuilder\interfaces\JApplets\1>javac.bat interfaceAppli.java

E:\data\serge\Jbuilder\interfaces\JApplets\1>dir
12/06/2002  16:40                6 148 interfaceAppli.java
12/06/2002  16:41                  527 interfaceAppli$1.class
12/06/2002  16:41                  525 interfaceAppli$2.class
12/06/2002  16:41                  525 interfaceAppli$3.class
12/06/2002  16:41                  525 interfaceAppli$4.class
12/06/2002  16:41                  525 interfaceAppli$5.class
12/06/2002  16:41                4 759 interfaceAppli.class

Додаток можна протестувати за допомогою програми AppletViewer з JDK, яка дозволяє запускати аплети або браузер. Для цього потрібно створити документ HTML appli.htm, який міститиме аплет:

<html>
    <head>
        <title>listes swing</title>
    </head>
    <body>
        <applet 
        code="interfaceAppli.class"
      width="400"
      height="300">
        </applet>
    </body>
</html>

Це класичний документ HTML, за винятком наявності тегу applet. Він використовувався з трьома параметрами:

code="interfaceAppli.class"
ім’я скомпільованого класу JAVA, який потрібно завантажити для виконання аплету
width="400"
ширина фрейму аплету в документі
height="300"
висота фрейму аплету в документі

Після створення файлу appli.htm його можна завантажити за допомогою програми appletviewer з JDK або за допомогою веб-браузера. У вікні командного рядка введіть наступну команду в папці, де знаходиться файл appli.htm:

appletviewer appli.htm

Тут припускається, що каталог, у якому знаходиться виконуваний файл appletviewer.exe, вказано у PATH у вікні DOS; інакше потрібно вказати повний шлях до виконуваного файлу appletviewer.exe. З’явиться таке вікно:

Image

Зупиняємо виконання аплету за допомогою опції Applet/Quitter. Тепер протестуємо аплет у браузері. Він повинен використовувати віртуальну машину Java 2, щоб мати змогу відображати компоненти Swing. Донедавна (2001 рік) ця вимога створювала проблеми, оскільки компанія Sun випускала версії JDK, які розробники браузерів підтримували лише з великим запізненням. Зрештою компанія Sun усунула цю перешкоду, надавши користувачам програму під назвою «Java plugin», яка дозволяє браузерам Internet Explorer та Netscape Navigator використовувати найновіші версії JRE, випущені компанією Sun (JRE = Java Runtime Environment). Наведені нижче тести проводилися з використанням IE 5.5 із плагіном Java 1.4.

Перший спосіб перевірити аплет interfaceAppli.class — завантажити файл HTML appli.htm безпосередньо у браузері, двічі клацнувши по ньому. Браузер відобразить сторінку HTML та її аплет без допомоги веб-сервера:

Image

З URL (1) видно, що файл було завантажено безпосередньо у браузер. У наступному прикладі файл appli.htm було запрошено з веб-сервера Apache, що працює на порту 81 локального комп’ютера:

Image

5.6.4. Параметр форматування <applet> у документі HTML

Ми побачили, що в документі HTML на аплет посилається тег <applet>. Цей тег може мати різні параметри:

<applet
    code=
    width=
    height=
    codebase=
    align=
    hspace=
    vspace=
alt=
>
    <param name1=nom1 value=val1>
    <param name2=nom2 value=val2>
    texte
>
</applet>

Значення параметрів такі:

Параметр
Значення
code
обов’язковий — ім’я файлу .class, що має бути виконано
width
обов'язковий — ширина аплету в документі
height
обов’язкове — висота …
codebase
необов'язкове — URL каталогу, що містить аплет, який потрібно виконати. Якщо codebase не вказано, аплет шукатиметься в каталозі HTML-документа, який на нього посилається
align
необов’язкове — позиціонування (LEFT, RiGHT, CENTER) аплету в документі
hspace
опціонально — горизонтальне поле навколо аплету, виражене в пікселях
vspace
необов’язкове — вертикальне поле навколо аплету, виражене в пікселях
alt
опціонально — текст, що відображається замість аплету, якщо браузер не може його завантажити
param
опціонально — параметр, що передається аплету, який визначає його ім’я (name) та значення (value). Аплет зможе отримати значення параметра nom1 за допомогою val1=getParameter("nom1")
Можна використовувати скільки завгодно параметрів
texte
необов'язковий — відображатиметься у будь-якому браузері, який не може виконати аплет, наприклад, через відсутність віртуальної машини Java.

Розглянемо приклад, щоб проілюструвати передачу параметрів аплету:

<html>
    <head>
        <title>paramètres applet</title>
    </head>
    <body>
        <applet code="interfaceParams.class" width="400" height="300">
      <param name="param1" value="val1">
      <param name="param2" value="val2">      
        </applet>
    </body>
</html>

Java-код аплету interfaceParams було згенеровано, як зазначено вище. Було створено додаток JBuilder, після чого було виконано кілька перетворень, згаданих вище:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceParams extends JApplet {
  JPanel contentPane;
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel1 = new JLabel();
  DefaultListModel params=new DefaultListModel();
  JList lstParams = new JList(params);

  //Створити рамку
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // інші ініціалізації
    moreInit();
  }

   // ініціалізації
  public void moreInit(){
     // відображає значення параметрів аплету
    params.addElement("nom=param1 valeur="+getParameter("param1"));
    params.addElement("nom=param2 valeur="+getParameter("param2"));
  }//додаткові ініціалізації

   //Ініціалізувати компонент
  private void jbInit() throws Exception  {
............
    this.setSize(new Dimension(205, 156));
    //this.setTitle("Параметри аплету");
    jScrollPane1.setBounds(new Rectangle(19, 53, 160, 73));
............
 }
}

Виконання за допомогою AppletViewer:

Image

5.6.5. Доступ до віддалених ресурсів з аплету

Багато програм мають використовувати інформацію, що міститься у файлах або базах даних. Ми вже зазначали, що аплет не має доступу до ресурсів комп’ютера, на якому він виконується. Це розумний захід безпеки. Інакше достатньо було б написати аплет, щоб «підглядати» за диском тих, хто його завантажує. Проте аплет має доступ до ресурсів сервера, з якого він був завантажений, наприклад, до файлів. Саме це ми й розглянемо зараз.

5.6.5.1. Клас URL

Будь-яка Java-програма може зчитати файл, що знаходиться на комп’ютері в мережі, завдяки класу java.net.URL (URL = Uniform Resource Locator). URL ідентифікує мережевий ресурс, комп’ютер, на якому він знаходиться, а також протокол і порт зв’язку, які слід використовувати для його отримання, у такому форматі:

протокол:порт//комп’ютер/файл

Таким чином, URL http://www.ibm.com/index.html позначає файл index.html на комп’ютері www.ibm.com. Доступ до нього здійснюється за протоколом http. Порт не вказано: браузер використовуватиме порт 80, який є портом за замовчуванням для служби http.

Розглянемо детальніше деякі елементи класу URL:

public URL(String spec)
створює екземпляр класу URL на основі рядка у форматі «протокол:порт//комп’ютер/файл» — генерує виняток, якщо синтаксис рядка не відповідає URL
  
public String getFile()
дозволяє отримати поле «файл» із рядка «протокол:порт//машина/файл» для URL
  
public String getHost()
дозволяє отримати поле «машина» з рядка «протокол:порт//машина/файл» з URL
  
public String getPort()
дозволяє отримати поле «порт» з рядка «протокол:порт//машина/файл» з URL
  
public String getProtocol()
дозволяє отримати поле «протокол» з рядка «протокол:порт//машина/файл» з URL
  
public URLConnection openConnection()
відкриває з'єднання з віддаленим комп'ютером getHost() на його порту getPort() за протоколом getProtocol() з метою читання файлу getFile(). Генерує виняток, якщо з'єднання не вдалося встановити
  
public final InputStream openStream()
скорочена форма для openConnection().getInputStream(). Дозволяє отримати вхідний потік, з якого можна буде прочитати вміст файлу getFile(). Генерує виняток, якщо не вдалося отримати потік
  
public String toString()
виводить ідентифікатор екземпляра URL

Тут є два методи, які нас цікавлять:

  • public URL(String spec) — для вказання файлу, який потрібно обробити
  • public final InputStream openStream() для його обробки

5.6.5.2. Приклад для консолі

Ми напишемо програму на Java без графічного інтерфейсу, яка виведе на екран вміст файлу URL, переданого їй як параметр. Приклад виклику може виглядати так:

    DOS> java urlcontenu http://istia.univ-angers.fr/index.html

Програма є відносно простою:


import java.net.*;             // для класу URL
import java.io.*;                // для потоків (stream)

public class urlcontenu{

// відображає вміст URL, переданий як аргумент
// цей вміст має бути текстом, щоб його можна було прочитати

  public static void main (String arg[]){
    // перевірка аргументів
    if(arg.length==0){
      System.err.println("Syntaxe pg url");
      System.exit(0);
    }
    
    try{
      // створення URL      
      URL url=new URL(arg[0]);
      // читання вмісту
      try{
        // створення вхідного потоку
        BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
        try{
          // читання рядків тексту у вхідному потоці
          String ligne;
          while((ligne=is.readLine())!=null)
            System.out.println(ligne);
        } catch (Exception e){
            System.err.println("Erreur lecture : " +e);
        }
        finally{
          try { is.close(); } catch (Exception e) {}
        }
      } catch (Exception e){
          System.err.println("Erreur openStream : " +e);
      }
    } catch (Exception e){
      System.err.println("Erreur création URL : " +e);
    }
  }// кінець main
}// кінець класу

Перевіривши, що аргумент дійсно є, намагаємося створити URL з його використанням:


// створення URL      
      URL url=new URL(arg[0]);

Це створення може завершитися невдачею, якщо аргумент не відповідає синтаксису URL protocole:port//machine/fichier. Якщо маємо синтаксично правильний URL, намагаємося створити вхідний потік, з якого можна буде зчитувати рядки тексту. Потік вхідних даних, що надається функцією URL URL.openStream(), є потоком типу InputStream, тобто символьно-орієнтованим потоком: читання відбувається символ за символом, і рядки потрібно формувати самостійно. Щоб мати змогу читати рядки тексту, потрібно використовувати метод readLine класів BufferedReader або DataInputStream.On; тут обрано BufferedReader. Залишається лише перетворити потік InputStream з URL на потік BufferedReader. Це робиться шляхом створення проміжного потоку InputStreamReader:


BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));

Створення цього потоку може завершитися невдачею. Ми обробляємо відповідне виключення. Отримавши потік, нам залишається лише прочитати з нього рядки тексту та вивести їх на екран.


            String ligne;
         while((ligne=is.readLine())!=null)
                System.out.println(ligne);

І тут читання може спричинити виняток, який потрібно обробити. Ось приклад виконання програми, яка вимагає локального файлу URL:

E:\data\serge\Jbuilder\interfaces\JApplets\3>java urlcontenu http://localhost
<html>

<head>


<title>Bienvenue dans le Serveur Web personnel</title>
</head>

<body bgcolor="#FFFFFF" link="#0080FF" vlink="#0080FF"
topmargin="0" leftmargin="0">

<table border="0" cellpadding="0" cellspacing="0" width="100%"
bgcolor="#000000">
............
                </table>
                </center></div></td>
            </tr>
        </table>
        </td>
    </tr>
</table>
</body>
</html>

5.6.5.3. Графічний приклад

Графічний інтерфейс матиме такий вигляд:

Image

Номер
Назва
Тип
Роль
1
txtURL
JTextField
URL для ознайомлення
2
btnCharger
JButton
кнопка для запуску відтворення URL
3
JScrollPane1
JScrollPane
прокручувана панель
4
lstURL
JList
список, що відображає вміст запитуваного URL

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

Image

Відповідний код програми такий:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.net.*;
import java.io.*;

public class interfaceURL extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtURL = new JTextField();
  JButton btnCharger = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel lignes=new DefaultListModel();
  JList lstURL = new JList(lignes);

  //Створити фрейм
  public interfaceURL() {
..............
  }

   //Ініціалізація компонента
  private void jbInit() throws Exception  {
..............
  }

   //Замінено, щоб ми могли вийти, коли вікно закриється
  protected void processWindowEvent(WindowEvent e) {
...................
  }

  void txtURL_caretUpdate(CaretEvent e) {
    // встановлює стан кнопки «Завантажити»
    btnCharger.setEnabled(! txtURL.getText().trim().equals(""));
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    // відображає вміст URL у списку
    try{
      afficherURL(txtURL.getText().trim());
    }catch(Exception ex){
       // відображення помилки
      JOptionPane.showMessageDialog(this,"Erreur : " + ex.getMessage(),"Erreur",JOptionPane.ERROR_MESSAGE);
    }//try-catch
  }

  private void afficherURL(String strURL) throws Exception {
    // відображає вміст URL strURL у списку
     // жодне виключення не обробляється окремо. Їх просто передають далі

     // створення URL
    URL url=new URL(strURL);
     // створення вхідного потоку
    BufferedReader IN=new BufferedReader(new InputStreamReader(url.openStream()));
    // читання рядків тексту у вхідному потоці
    String ligne;
    while((ligne=IN.readLine())!=null)
      lignes.addElement(ligne);
     // закриття потоку читання
    IN.close();
  }
}

5.6.5.4. Аплет

Попередня графічна програма перетворена на аплет, як це вже неодноразово демонструвалося. Аплет вставлено в документ HTML appliURL.htm:

<html>
  <head>
    <title>Applet lisant une URL</title>
  </head>
  <body>
    <h1>Applet lisant une URL</h1>
    <applet
      code="appletURL.class"
      width="400"
      height="300"
    >
    </applet>
  </body>
</html>

Image

У наведеному вище прикладі браузер надіслав запит на файл URL http://localhost:81/Japplets/2/appliURL.htm до веб-сервера apache, що працює на порту 81. Після цього аплет було відображено в браузері. У ньому було знову зроблено запит на файл URL http://localhost:81/Japplets/2/appliURL.htm, щоб перевірити, чи дійсно отримується саме той файл appliURL.htm, який ми створили. Тепер спробуємо завантажити файл URL, який не належить машині, що видала аплет (у даному випадку localhost):

Image

Завантаження файлу URL було відхилено. Тут ми знову стикаємося з обмеженням, пов’язаним з аплетами: вони можуть отримувати доступ лише до мережевих ресурсів того комп’ютера, з якого їх було завантажено. Існує спосіб, за допомогою якого аплет може обійти це обмеження, — делегувати мережеві запити серверній програмі, розташованій на комп’ютері, з якого його було завантажено. Ця програма здійснюватиме мережеві запити замість аплету та надсилатиме йому результати. Таку програму називають проміжною.

5.7. Аплет IMPOTS

Тепер ми перетворимо графічну програму IMPOTS на аплет. Це має певний інтерес: програма стане доступною для будь-якого користувача Інтернету, який має браузер та плагін Java 1.4 (завдяки компоненту JSpinner). Таким чином, наша програма стане доступною в усьому світі... Ця модифікація вимагатиме дещо більше, ніж просто перетворення графічної програми на аплет, яке вже стало класичним. Програма використовує пункт меню Initialiser, призначений для зчитування вмісту локального файлу. Однак якщо уявити собі веб-програму, стає зрозуміло, що така схема більше не працює:

Image

Очевидно, що дані, які визначають шкали оподаткування, будуть розміщені на веб-сервері, а не на кожному з клієнтських комп’ютерів. Файл, який потрібно прочитати на веб-сервері, буде розміщений у тій самій папці, що й аплет, і опція Initialiser повинна буде знайти його саме там. Попередні приклади показали, як це зробити. Крім того, для вибору файлу з даними локально ми використовували компонент JFileChooser, який тут більше не потрібен.

Документ HTML, що містить аплет, матиме такий вигляд:

<html>
  <head>
    <title>Applet de calcul d'impôts</title>
  </head>
  <body>
    <h2>Calcul d'impôts</h2>
    <applet
      code="appletImpots.class"
      width="320"
      height="270"
    >

<param name="data" value="impots.txt">


    </applet>
  </body>
</html>

Зверніть увагу на параметр data, значенням якого є ім'я файлу, що містить дані про шкалу оподаткування. Документ HTML, клас appletImpots, клас impots та файл impots.txt знаходяться в одній папці на веб-сервері:

E:\data\serge\web\JApplets\impots>dir
12/06/2002  13:24                  247 impots.txt
13/06/2002  10:17                  654 appletImpots$2.class
13/06/2002  10:17                  653 appletImpots$3.class
13/06/2002  10:17                  653 appletImpots$4.class
13/06/2002  10:17                  651 appletImpots$5.class
13/06/2002  10:06                  651 appletImpots$6.class
13/06/2002  10:17                8 655 appletImpots.class
13/06/2002  10:17                  657 appletImpots$1.class
13/06/2002  10:24                  286 appletImpots.htm
13/06/2002  10:17                1 305 impots.class

Код аплету виглядає так (ми виділили лише зміни порівняно з графічним додатком):

...........
import java.net.*;
import java.applet.Applet;

public class appletImpots extends JApplet {
  // компоненти вікна
  JPanel contentPane;
............................

   // атрибути класу
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;
  String urlDATA=null;

  //Створення фрейму
  public void init() {
    //enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // інші ініціалізації
    moreInit();
  }

   // ініціалізація форми
  private void moreInit(){
     // меню «Розрахувати» вимкнено
    mnuCalculer.setEnabled(false);
................
     // отримано ім’я файлу податкової шкали
    String nomFichier=getParameter("data");
    // помилка?
    if(nomFichier==null){
       // повідомлення про помилку
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       // блокується опція «Ініціалізувати»
      mnuInitialiser.setEnabled(false);
      // кінець
      return;
    }//if
     // встановлюємо URL даних
    urlDATA=getCodeBase()+"/"+nomFichier;
  }//moreInit

   //Ініціалізувати компонент
  private void jbInit() throws Exception  {
...................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // вихід із програми
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // завантажується файл даних
    try{
       // читання даних
      lireDATA();
       // створення об’єкта «податки»
      objImpots=new impots(limites,coeffr,coeffn);
................
  }

  private void lireDATA() throws Exception {
     // таблиці даних
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // відкриття файлу для читання
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
    // файл читається по рядках
....................
  }

  void mnuCalculer_actionPerformed(ActionEvent e) {
    // розрахунок податку
......................
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
..........
  }

  void mnuEffacer_actionPerformed(ActionEvent e) {
...............
  }
}

Тут ми коментуємо лише зміни, пов'язані з тим, що файл даних, який потрібно прочитати, тепер знаходиться на віддаленому комп'ютері, а не на локальному:

Ім’я файлу даних, що підлягають зчитуванню, URL, отримується за допомогою такого коду:

     // отримання імені файлу шкали податків
    String nomFichier=getParameter("data");
    // помилка?
    if(nomFichier==null){
       // повідомлення про помилку
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       // блокування опції «Ініціалізувати»
      mnuInitialiser.setEnabled(false);
      // кінець
      return;
    }//if
     // встановлюємо URL даних
    urlDATA=getCodeBase()+"/"+nomFichier;

Нагадаємо, що ім'я файлу «impots.txt» передається в параметр data аплету:

    <param name="data" value="impots.txt">

Отже, наведений вище код спочатку отримує значення параметра data, обробляючи можливі помилки. Якщо значення параметра URL у документі HTML, що містить аплет, дорівнює http://localhost:81/JApplets/impots/appletImpots.htm, то URL файлу impots.txt буде http://localhost:81/JApplets/impots/impots.txt. Нам потрібно побудувати ім’я цього URL. Метод getCodeBase() аплету повертає URL папки, з якої було отримано документ HTML, що містить аплет, тобто у нашому прикладі — http://localhost:81/JApplets/impots. Отже, наступна інструкція дозволяє побудувати URL файлу даних:

    urlDATA=getCodeBase()+"/"+nomFichier;

У методі lireFichier(), який зчитує вміст URL та urlData, міститься код для створення вхідного потоку, що дозволить зчитати дані:

     // відкриття файлу для читання
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));

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

Image

5.8. Висновок

У цьому розділі було представлено

  • вступ до створення графічних інтерфейсів за допомогою JBuilder
  • найпоширеніші компоненти Swing
  • створення аплетів

Запам’ятаємо, що

  • код, згенерований JBuilder, можна написати вручну. Отримавши цей код тим чи іншим способом, для його виконання достатньо простого JDK, і JBuilder більше не є необхідним.
  • використання такого інструменту, як JBuilder, може забезпечити значне підвищення продуктивності:
    • хоча згенерований JBuilder код можна написати вручну, це може зайняти багато часу і не має великого сенсу, оскільки логіка програми, як правило, полягає в іншому.
    • Згенерований код може бути повчальним. Його читання та вивчення — це хороший спосіб ознайомитися з певними методами та властивостями компонентів, які використовуються вперше.
    • JBuilder є багатоплатформовим. Отже, при переході з однієї платформи на іншу ви зберігаєте набуті знання. Можливість писати програми, що працюють як під Windows, так і під Linux, є, звичайно, дуже важливим фактором продуктивності. Але це зумовлено самою мовою Java, а не JBuilder.

5.9. JBuilder під Linux

Усі наведені вище приклади було протестовано під Windows 98. Можна задатися питанням, чи є написані програми переносимими в незмінному вигляді під Linux. За умови, що на відповідній машині з Linux є класи, які використовуються різними програмами, вони є переносимими. Наприклад, якщо ви встановили JBuilder під Linux, необхідні класи вже є на вашій машині. Ось, наприклад, який результат дає виконання однієї з наших програм на компоненті JList разом із JBuilder 4 під Linux:

Нижче ми описуємо встановлення JBuilder 4 Foundation на комп’ютері з ОС Linux. Його встановлення на комп’ютері з Win9x не викликає жодних проблем і аналогічне процесу, який буде описано нижче. Встановлення пізніших версій, безсумнівно, відрізняється, але цей документ все ж може містити корисну інформацію.

JBuilder доступний на сайті компанії «Inprise» за адресою http://www.inprise.com/jbuilder

Image

На цій сторінці розміщені посилання, зокрема, для Windows та Linux. Нижче ми опишемо встановлення JBuilder на комп’ютері з ОС Linux, що має графічний інтерфейс KDE.

Перейшовши за посиланням «Jbuilder 4 for Linux», з’явиться форма. Заповніть її, і в результаті ви отримаєте два файли:

jb4docs_fr.tar.gz: документація та приклади до Jbuilder4

jb4fndlinux_fr.tar.gz: Jbuilder4 Foundation. Це обмежена версія комерційного Jbuilder4, але її цілком достатньо для навчальних цілей.

Ключ активації програмного забезпечення надсилається вам електронною поштою. Він дозволить вам користуватися Jbuilder 4 і буде запитуватися під час першого запуску програми. Якщо ви загубите цей ключ, ви можете повернутися на вказану вище сторінку та перейти за посиланням «get your activation key». Далі ми припускаємо, що ви маєте root і перебуваєте в каталозі з двома вищезазначеними файлами tar.gz. Розпакуйте обидва файли:

[tar xvzf jb4fndlinux_fr.tar.gz]
[tar xvzf jb4docs_fr.tar.gz]
[ls -l]
drwxr-xr-x    3 nobody   nobody       4096 oct 10  2000 docs
drwxr-xr-x    3 nobody   nobody       4096 déc  5 13:00 foundation
[ls -l foundation]
-rw-r--r--    1 nobody   nobody       1128 déc  5 13:00 deploy.txt
-rwxr-xr-x    1 nobody   nobody   69035365 déc  5 13:00 fnd_linux_install.bin
drwxr-xr-x    2 nobody   nobody       4096 déc  5 13:00 images
-rw-r--r--    1 nobody   nobody      15114 déc  5 13:00 index.html
-rw-r--r--    1 nobody   nobody      23779 déc  5 13:00 license.txt
-rw-r--r--    1 nobody   nobody      75739 déc  5 13:00 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 déc  5 13:00 whatsnew.html
[ls -l docs]
-rw-r--r--    1 nobody   nobody       1128 oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 oct 10  2000 whatsnew.html

У обох створених каталогах файл .bin є інсталяційним файлом. Крім того, за допомогою веб-браузера відкрийте файл index.html у кожному з каталогів. У них наведено покрокові інструкції щодо інсталяції обох продуктів. Почнемо з інсталяції Jbuilder Foundation:

[cd foundation]
[./fnd_linux_install.bin]

З’являється перший екран інсталяції. Далі з’являться ще багато інших:

Image

Підтвердіть. Далі з’явиться екран із поясненнями:

Image

Виконайте [suivant].

Image

Погодьтеся з умовами ліцензійної угоди та виконайте команду [suivant].

Image

Погодьтеся з запропонованим місцем для Jbuilder (запишіть його, воно знадобиться пізніше) і виконайте [suivant]. Встановлення відбувається швидко.

Image

Ми готові до першого тесту. У KDE запустіть файловий менеджер, щоб перейти до каталогу з виконуваними файлами Jbuilder: /opt/jbuilder4/bin (якщо ви встановили Jbuilder у /opt/jbuilder4):

Image

Клацніть на піктограму jbuilder вище. Оскільки ви використовуєте Jbuilder вперше, вам потрібно буде ввести свій ключ активації:

Image

Заповніть поля Nom та Société. Натисніть [Ajouter], щоб ввести свій ключ активації. Нагадуємо, що цей ключ мав бути надісланий вам електронною поштою, і якщо ви його загубили, ви можете отримати його за адресою, з якої ви завантажили Jbuilder 4 (див. початок інсталяції). Після прийняття вашого ключа активації вам нагадають про умови ліцензії:

Image

Натиснувши OK, ви повернетеся до вже знайомого вікна введення даних:

Image

Натисніть OK, щоб завершити цей етап, який виконується лише під час першого запуску. Після цього з’явиться середовище розробки JBuilder:

Image

Закрийте JBuilder, щоб тепер встановити документацію. Вона встановить певну кількість файлів, які будуть використовуватися в довідці JBuilder, яка наразі є неповною. Поверніться до каталогу, де ви розпакували файли JBuilder з кодом tar.gz. Програма встановлення знаходиться в каталозі docs. Перейдіть до нього:

[cd docs]
[ls -l]
-rw-r--r--    1 nobody   nobody       1128 oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 oct 10  2000 whatsnew.html

Інсталяційний файл має назву doc_install.bin, але його не можна запускати одразу. Якщо це зробити, інсталяція завершиться невдало, і ви не зрозумієте, чому. Прочитайте файл index.html у веб-браузері, щоб ознайомитися з докладним описом процесу встановлення. Програмі встановлення потрібна віртуальна машина Java, а саме програма під назвою java, яка має знаходитися у каталозі PATH на вашому комп’ютері. Нагадаємо, що PATH — це змінна Unix, значення якої у форматі rep1:rep2:...:repn вказує на каталоги repi, які слід обшукати під час пошуку виконуваного файлу. У даному випадку інсталятор вимагає запуску програми java. У вас може бути кілька версій цієї програми залежно від кількості віртуальних машин Java, які ви встановили тут чи там. Цілком логічно, що ми використаємо ту, яку надає Jbuilder4 і яка знаходиться в /opt/jbuilder4/jdk1.3/bin. Щоб вказати цей каталог у змінній PATH:

[echo $PATH]
/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
[export PATH=/opt/jbuilder4/jdk1.3/bin/:$PATH]
[echo $PATH]
/opt/jbuilder4/jdk1.3/bin/:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin

Тепер ми можемо розпочати встановлення документації:

[./doc_install.bin]
Preparing to install...

Це буде графічна інсталяція:

Image

Вона дуже схожа на інсталяцію JBuilder Foundation. Тому ми не будемо її детально описувати. Є одне вікно, яке не можна пропустити:

Image

Зазвичай інсталятор самостійно визначає, куди ви встановили Jbuilder Foundation. Тому не змінюйте запропоновані налаштування, за винятком випадків, коли вони є неправильними.

Після встановлення документації ми готові до нового тестування Jbuilder. Запустіть програму, як показано вище. Коли Jbuilder запуститься, виберіть пункт «Довідка/Тема довідки». У лівій панелі натисніть на посилання Tutoriels:

Image

JBuilder постачається з набором навчальних посібників, які допоможуть вам розпочати програмування на Java. Нижче наведено покроковий опис виконання навчального посібника «Створення програми», про який йшлося вище.

Image

У JBuilder виберіть «Файл» > «Новий проект». Майстер покаже вам 3 екрани:

Image

Ми створимо просте вікно з заголовком «Привіт усім». Назвемо цей проєкт coucou. Приклад було виконано за допомогою root. Після цього JBuilder пропонує об’єднати всі проекти в каталог jbproject, що знаходиться в каталозі підключення root. Проєкт coucou буде розміщено в каталозі coucou (поле «Ім’я каталогу проєкту») проєкту jbproject. Створіть [suivant].

Image

Цей другий екран містить підсумок різних шляхів вашого проєкту. Нічого змінювати не потрібно. Виконайте [suivant].

Image

На третьому екрані вам пропонується налаштувати ваш проект. Заповніть поля та натисніть [Terminer].

Тепер виконайте Fichier/Nouveau:

Image

Виберіть Application і виконайте OK. Новий майстер покаже вам 2 екрани:

Image

У полі paquet вказується назва проєкту. У полі «Клас» потрібно ввести nom — це ім’я головного класу проєкту. Візьміть наведену вище назву та введіть [suivant]:

Image

Наш додаток містить другий клас Java для вікна додатка. Присвойте цьому класу ім’я. Поле Titre — це заголовок, який ви хочете надати цьому вікну. У полі options пропонуються параметри для вашого вікна. Виберіть усі параметри та вкажіть [Terminer]. Після цього ви повернетеся до середовища JBuilder, яке поповнилося інформацією, яку ви вказали для свого проєкту:

Image

У лівому верхньому вікні (1) ви бачите список файлів, що складають ваш проєкт. Серед них, зокрема, є два класи .java, яким ми щойно дали імена. У правому вікні (2) ви бачите Java-код класу coucouCadre. У лівому нижньому вікні відображається структура (класи, методи, атрибути) вашого проєкту. Він готовий до виконання. Натисніть кнопку 4 вище, виберіть «Виконати» > «Виконати проєкт» або введіть F9. Ви повинні побачити таке вікно:

Image

Натиснувши на опцію Aide, ви повинні побачити інформацію, яку ви вказали у майстрах створення. Ми не будемо заглиблюватися далі. Настав час перейти до навчальних посібників.

Перед тим, як завершити, просто покажемо, що ви можете використовувати не JBuilder та його графічний інтерфейс, а JDK, який він приніс із собою та розмістив у /opt/jbuilder4/jdk1.3. Скомпілюйте такий файл essai1.java:

import java.io.*;

public class essai1{
    public static void main(String args[]){
        System.out.println("coucou");
        System.exit(0);
    }
}

Скомпілюємо його та запустимо за допомогою JDK з JBuilder:

[ls -l *.java]
-rw-r--r--    1 root     root          135 mai  9 21:57 essai1.java
[/opt/jbuilder4/jdk1.3/bin/javac essai1.java]
[/opt/jbuilder4/jdk1.3/bin/java essai1]
coucou