Graphical User Interface (GUI) - Java Swing: Diferență între versiuni

De la WikiLabs
Jump to navigationJump to search
Linia 63: Linia 63:
=== Event Handlers ===
=== Event Handlers ===


Fiecare '''JComponent''' suportă o listă de evenimente la care e sensibil. Fiecărui eveniment i se poate asociaza o acțiune care se execută când acel eveniment se declanșează. De exemplu, când un buton este apăsat, sau când cursorul de la mouse a intrat în zona ocupată de componentă, sau când s-a tastat ceva într-o zonă de text, etc. Aceste ''handler''-e sunt, de fapt, niște metode, definite în anumite interfețe. Aceste metode se excută în paralel cu programul principal (ca și thread-uri) în momentul în care evenimentul se declanșează. Metodele care adaugă un ''handler'' unui obiect sunt de forma:
Every '''JComponent''' supports a list of events which it is sensitive to. To each event, an action can be associated which is executed when that event is triggered. For example, then a button is pressed, or when the mouse moves over the component, or when something is typed in a text component, etc. These handlers are, in fact, methods, defined in certain interfaces. These methods are executed in parallel with the main program, as threads, in the moment when the event is triggered. Methods that add a handled to a component look like this:
* ''public void addActionListener(ActionListener _listener)'' - pentru evenimente de tip ''action'', adică activarea unui component (click pe un buton, enter într-un text field, etc.);
* ''public void addActionListener(ActionListener _listener)'' - for ''action'' type events, meaning activating a component (like click on a button, writing a text in a text field, etc.);
* ''public void addMouseListener(MouseListener _listener)'' - pentru evenimente legate de mouse;
* ''public void addMouseListener(MouseListener _listener)'' - for events related to the mouse;
* etc.
* etc.


Același handler poate fi asociat mai multor elemente, iar în acest caz, pentru a știi care obiect a generat evenimentul, se folosește metoda ''getSource()'' definită în clasa '''java.util.EventObject''' care este superclasă pentru toate obiectele primite ca argumente de metode de tip handler ([http://docs.oracle.com/javase/7/docs/api/java/awt/event/ActionEvent.html java.awt.event.ActionEvent], [http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseEvent.html java.awt.event.MouseEvent], etc.). Metoda ''getSource()'' întoarce o referință de tip Object la componenta de interfață care a generat evenimentul.
The same handler can be associated to multiple elements, in which case, in order to know which element triggered the event, the method ''getSource()'' is used, defined in class '''java.util.EventObject''' which is the superclass for all objects received as arguments by handler methods ([http://docs.oracle.com/javase/7/docs/api/java/awt/event/ActionEvent.html java.awt.event.ActionEvent], [http://docs.oracle.com/javase/7/docs/api/java/awt/event/MouseEvent.html java.awt.event.MouseEvent], etc.). Method ''getSource()'' returns a reference of type Object to the component that generated the event.


Mai multe despre handler-e, în [http://docs.oracle.com/javase/tutorial/uiswing/events/index.html tutorial-ul Oracle].
More about handlers in the [http://docs.oracle.com/javase/tutorial/uiswing/events/index.html Oracle tutorial].


=== Exemplu ===
=== Exemplu ===

Versiunea de la data 23 decembrie 2013 14:23

In many of the applications that you will develop in Java, you will also need an adequate graphical interface: windows, buttons, edit fields, checkboxes, etc. There are several libraries used for developing graphical interfaces, the most popular being Java Swing and the most recent being JavaFX.

Java Swing

The package that contains the majority of classes for Swing applications is java.swing, some other other classes are used from the older package java.awt. The main container class for GUI elements is javax.swing.JFrame.

The Frame is the main window of the GUI. It's the element associated with the horizontal bar containing the icon, application name and the three buttons minimize, maximize and close:

Exemplu de frame fără elemente

This is a JFrame containing the most used elements in Swing:

Exemplu de frame cu elemente

Components

All Swing objects, with the exception of class JFrame, inherit class javax.swing.JComponent which in turn inherits (indirectly) class java.awt.Container. So, there is a hierarchy of components, each element called parent containing other sub-components called children. Next, we'll present the elements required for task 6. For a more detailed description, read the Oracle tutorial.

javax.swing.JPanel

JPanel is a generic container that can hold other elements. It can be visible, changing the background color, the image model or having a border, or be invisible, only used for the hierarchy of the content. It is recommended not to place elements directly in a JFrame, but in a JPanel that is placed in a JFrame. This is particularly useful when reusing a panel.

javax.swing.JLabel

JLabel is a component used to display text or image in a container.

javax.swing.JButton

JButton is, as the name says, a button. This can have either a text or an image displayed on top. It's used by specifying an event handler of type ActionListener (see #Event Handlers) which is triggered when the button is clicked.

javax.swing.JTextField

JTextField is an area where a short text can be entered, on a single line. This too can have an associated event handler of type ActionListener which is triggered when Enter is pressed when the text field is focused.

javax.swing.JTextArea

JTextArea is a component where you can add a large text on more than one line.

Layouts

O altă serie de clase necesară pentru implementarea unei interfețe grafice este setul de clase care extind interfața java.awt.LayoutManager. Aceste clase descriu modul în care elementele se așează într-un Container. Cele mai importante sunt:

Another series of classes required for implementing a GUI is the set of classes implementing interface java.awt.LayoutManager. These classes describe how elements are placed in a container. Some of them are:

java.awt.FlowLayout

FlowLayout is used to place elements horizontally, until they don't fit anymore, in which case, subsequent components are placed on the next line. This is the simplest type of layout.

java.awt.GridLayout

GridLayout is used to place components in a matrix with configurable size.

java.awt.BorderLayout

BorderLayout is used to place elements along the four borders and in center: NORTH, SOUTH, EAST, WEST and CENTER. Only one element can be placed in either of the five positions.

java.awt.CardLayout

CardLayout is used to add more components to a container, from which only one is visible at any given time. This type of layout is useful to generate wizard type applications in which the user skips from one screen to the next and back by using Next and Previous buttons.

More about layouts in the Oracle tutorial.

Event Handlers

Every JComponent supports a list of events which it is sensitive to. To each event, an action can be associated which is executed when that event is triggered. For example, then a button is pressed, or when the mouse moves over the component, or when something is typed in a text component, etc. These handlers are, in fact, methods, defined in certain interfaces. These methods are executed in parallel with the main program, as threads, in the moment when the event is triggered. Methods that add a handled to a component look like this:

  • public void addActionListener(ActionListener _listener) - for action type events, meaning activating a component (like click on a button, writing a text in a text field, etc.);
  • public void addMouseListener(MouseListener _listener) - for events related to the mouse;
  • etc.

The same handler can be associated to multiple elements, in which case, in order to know which element triggered the event, the method getSource() is used, defined in class java.util.EventObject which is the superclass for all objects received as arguments by handler methods (java.awt.event.ActionEvent, java.awt.event.MouseEvent, etc.). Method getSource() returns a reference of type Object to the component that generated the event.

More about handlers in the Oracle tutorial.

Exemplu

Vom descrie un JFrame care conține două JLabel, două JTextField, un JTextArea și un JButton. Când se apasă butonul, cele două JTextField se vor încărca cu valorile dimensiunii JFrame-ului și se va scrie un caracter x în JTextArea:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class FrameTest extends JFrame implements ActionListener {

    // we define the elements used in
    // the frame
    private JPanel mainPanel;
    private JLabel xLabel;
    private JLabel yLabel;
    private JTextField xField;
    private JTextField yField;
    private JTextArea textArea;
    private JButton button;
    
public FrameTest(String _title){
    // calling the constructor for JFrame to set the title
    super(_title);
    
    // initializing the components (method is implemented below)
    initComponents();
    
    // calling pack() defined in superclass to resize the frame according to
    // contents
    pack();
    
    // displaying the frame
    setVisible(true);
    
    // select the default behaviour when closing the frame by clicking
    // the X button on the bar: the application will exit
    setDefaultCloseOperation(EXIT_ON_CLOSE);
}

public static void main(String[] _args){
    FrameTest _frame = new FrameTest("Frame Test");
}

private void initComponents() {
    // setting the layout as FlowLayout
    setLayout(new FlowLayout());
    
    // creating the components
    
    // the panel adds the components in
    // a FlowLayout
    mainPanel = new JPanel(new FlowLayout()); 
    xLabel = new JLabel("X size (width):");
    yLabel = new JLabel("Y size (height):");
    xField = new JTextField(6); //6 columns (characters)
    yField = new JTextField(6); //6 columns (characters)
    textArea = new JTextArea(10, 10); //10 columns, 10 rows
    button = new JButton("Click me!");
    
   
    //adding components to panel
    mainPanel.add(xLabel);
    mainPanel.add(xField);
    mainPanel.add(yLabel);
    mainPanel.add(yField);
    mainPanel.add(textArea);
    mainPanel.add(button);
    
    //adding scrollPane to frame
    add(mainPanel);
    
    // adding the listener to the button Component
    button.addActionListener(this);
}

// this is the handler defined in the ActionListener interface
public void actionPerformed(ActionEvent _actionEvent) {
    xField.setText(String.valueOf(this.getWidth()));
    yField.setText(String.valueOf(this.getHeight()));
    textArea.append("x");
}
    
}

Rezultatul arată așa:

Codul de mai sus, rulat

Pentru a crea frame-uri mai complexe, trebuie să folosiți alte tipuri de LayoutManager, elemente de tip javax.swing.JScrollPane, sau, puteți utiliza un mediu de dezvoltare, gen Netbeans pentru a crea în mod vizual interfața.

JavaFX

JavaFX este cea mai nouă implementare a platformei de dezvoltare pentru interfețe GUI de client. Cu toate că este încă într-un stadiu incipient, are avantaje față de vechiul Swing. Versiunea 2.2, care a fost publicată pe 14 august 2012 este un pas înainte către o nouă generație de aplicații multimedia pe Internet. Conform site-ului Oracle, principalele avantaje ale JavaFX sunt:

  • integrare completă cu Java SE și JDK, incepând cu versiunea 7, update 6 (7u6), ceea ce implică faptul că aplicațiile JavaFX vor putea fi dezvoltate și rulate de către orice client cu această verisune de Java;
  • inițial JavaFX a fost un limbaj de scripting, dar acum Oracle pune la dispoziție un API pentru dezvoltarea aplicațiilor direct în Java, pentru un mai bun management și reutilizare a codului;
  • un nou motor (engine) grafic, numit Prism, care face uz de accelerarea hardware oferită de GPU-urile moderne, precum și un nou manager de ferestre (Window Toolkit) numit Glass;
  • un nou limbaj bazat pe XML, numit FXML, folosit pentru descrierea interfețelor grafice, astfel încât să nu fie nevoie de recompilarea codului la fiecare modificare;
  • un nou engine multimedia, bazat pe GStreamer, care permite redarea de conținut multimedia;
  • o componentă care poate afișa conținut web și care poate fi integrată în orice interfață grafică JavaFX;
  • o serie de componente noi de interfață, precum grafice, tabele, meniuri și panouri;
  • un sistem de a împacheta aplicațiile astfel încât acestea să fie livrate cu toate bibliotecile necesare execuției;
  • portabilitate pe Linux, Windows și Mac OS X;

Un alt avantaj alt JavaFX spre deosebire de Swing, este faptul că aceeași aplicație poate fi rulată de sine stătător, ca applet, sau ca aplicație de tip Web Start.

În plus, orice component din JavaFX poate fi modificat ca aspect folosind directive CSS, conform [1].

Atenție: În laboratorul din sala 2 de calculatoare este instalată o versiune veche de Java care nu permite dezvoltarea aplicațiilor in JavaFX.

Componente

Ca și Java Swing, JavaFX se bazează pe o ierarhie de clase care implementează diferite componente și containere ce reprezintă elementele grafice. Analog clasei JFrame, în JavaFX, clasa care descrie fereastra principală a unei aplicații este javafx.stage.Stage. O aplicație JavaFX (spre deosebire de o aplicație Java obișnuită, care pornește cu metoda main()) trebuie să extindă clasa javafx.application.Application. Aceasta este o clasă abstractă, deci utilizatorul este obligat să definească metoda public void start(Stage _primaryStage), care este metoda de start a aplicației, analog metodei main().

Un obiect de tip Stage conține, la un moment dat, o singură scenă (javafx.scene.Scene). Această scenă este inițializată dându-i-se dimensiunile scenei și container-ul care conține toate celălalte elemente din fereastră. Acest container este, de cele mai multe ori, un panou. Panoul, pe lângă rolul de container, specifică și modul în care sunt afișate componentele, analog LayoutManager-ului din Swing. Vom folosi, pentru exemplu, un javafx.scene.layout.FlowPane, care este analog clasei FlowLayout:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

public class JavaFXApplicationTest extends Application {

public void start(Stage _primaryStage){
    // creating the pane for the elements:
    FlowPane _pane = new FlowPane();

    // creating the scene with the FlowPane as the
    // container for all elements and dimensions
    // width = 300 and height = 250 pixels
    Scene scene = new Scene(_pane, 300, 250);

    // setting the scene in the primary stage
    primaryStage.setScene(scene);

    // setting the title of the stage
    primaryStage.setTitle("Empty pane");

    //displaying the stage
    primaryStage.show();
}

/**
 * The main() method is ignored in correctly deployed JavaFX application.
 * main() serves only as fallback in case the application can not be
 * launched through deployment artifacts, e.g., in IDEs with limited FX
 * support. NetBeans ignores main().
 */
public static void main(String[] args) {
    launch(args);
}

}

Rezultatul:

O scenă fără elemente în JavaFX

Alte componente care pot fi folosite într-un scene:

Un exemplu analog cu cel de la Swing:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

public class JavaFXApplicationTest extends Application {
    
    private Label labelx;
    private Label labely;
    private TextField fieldx;
    private TextField fieldy;
    private TextArea area;
    private Button button;
    
public void start(Stage primaryStage) {

    FlowPane _pane = new FlowPane();

    //creating the components:
    labelx = new Label("Width:");
    labely = new Label("Height:");
    fieldx = new TextField();
    fieldy = new TextField();
    area = new TextArea();
    button = new Button("Click me!");

    //adding the elements to pane:
    _pane.getChildren().add(labelx);
    _pane.getChildren().add(fieldx);
    _pane.getChildren().add(labely);
    _pane.getChildren().add(fieldy);
    _pane.getChildren().add(area);
    _pane.getChildren().add(button);
    
    Scene scene = new Scene(_pane, 300, 250);

    primaryStage.setTitle("Test pane");
    primaryStage.setScene(scene);
    primaryStage.show();
}

/**
 * The main() method is ignored in correctly deployed JavaFX application.
 * main() serves only as fallback in case the application can not be
 * launched through deployment artifacts, e.g., in IDEs with limited FX
 * support. NetBeans ignores main().
 */
public static void main(String[] args) {
    launch(args);
}

}

Cu rezultatul:

O scenă cu diverse elemente în JavaFX

Panouri

Analog diferitelor tipuri de LayoutManager din Swing și JavaFX dispune de o serie de panouri:

Tot panouri sunt și alte tipuri de elemente care în Java Swing aveau propriul tip de clasă, doar că aceste nu fac parte din pachetul javafx.scene.layout ci javafx.scene.control:

Event Handlers

Ca și în Swing, JavaFX permite asocierea unor metode de tip handler cu declanșarea unor evenimente. Modul de conectare este foarte similar:

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

public class JavaFXApplicationTest extends Application implements EventHandler<ActionEvent>{
    
    private Label labelx;
    private Label labely;
    private TextField fieldx;
    private TextField fieldy;
    private TextArea area;
    private Button button;
    private Scene scene;
    
public void start(Stage primaryStage) {

    FlowPane _pane = new FlowPane();

    //creating the components:
    labelx = new Label("Width:");
    labely = new Label("Height:");
    fieldx = new TextField();
    fieldy = new TextField();
    area = new TextArea();
    button = new Button("Click me!");

    //adding the handler to the button
    button.setOnAction(this);
    
    //adding the elements to pane:
    _pane.getChildren().add(labelx);
    _pane.getChildren().add(fieldx);
    _pane.getChildren().add(labely);
    _pane.getChildren().add(fieldy);
    _pane.getChildren().add(area);
    _pane.getChildren().add(button);
    
    scene = new Scene(_pane, 300, 250);

    primaryStage.setTitle("Test pane");
    primaryStage.setScene(scene);
    primaryStage.show();
}

// this is the handler method defined in interface
// EventHandler
public void handle(ActionEvent _event) {
    fieldx.setText(String.valueOf(scene.getWidth()));
    fieldy.setText(String.valueOf(scene.getHeight()));
    area.appendText("x");
}

/**
 * The main() method is ignored in correctly deployed JavaFX application.
 * main() serves only as fallback in case the application can not be
 * launched through deployment artifacts, e.g., in IDEs with limited FX
 * support. NetBeans ignores main().
 */
public static void main(String[] args) {
    launch(args);
}

}

Spre deosebire de Swing, unde existau mai multe tipuri de interfețe, una pentru fiecare tip de eveniment (ex: ActionListener, MouseListener, PropertyChangeListener, etc.), în JavaFX se folosește o singură interfață, javafx.event.EventHandler cu o singură metodă definită (handle(T)), unde T este un șablon folosit pentru a face diferența între diferitele tipuri de evenimente: javafx.event.ActionEvent, javafx.stage.WindowEvent, javafx.scene.web.WebEvent, etc.

Pentru JavaFX există o aplicație care permite dezvoltarea vizuală de interfețe grafice, numită JavaFX Scene Builder.