Introduzione

Swing è un framework Java, composto da classi e componenti e appartenente alle JFC (Java Foundation Classes), che viene utilizzato per lo sviluppo di interfacce grafiche. Swing consente di creare finestre in cui vengono posti diversi componenti come caselle di testo, etichette, "combobox", caselle di controllo di vario tipo, tabelle, pulsanti e così via. A differenza di AWT, inizialmente utilizzata come libreria Java per le GUI, Swing rende il look and feel dell’applicazione indipendente dal sistema operativo sui cui essa sta girando [1]. Per quegli sviluppatori principianti che non conoscessero tutti i componenti Swing, ricordiamo che, nella pagina ad essi dedicata [3], che invitiamo comunque a visitare, è pubblicato un riassunto visuale che riportiamo in figura 1.

Figura 1 - Un compendio dei principali componenti Swing.
Figura 1 - Un compendio dei principali componenti Swing.

I componenti di Swing consentono di creare delle finestre e dei controlli (e molto altro) per realizzare l'interfaccia grafica della nostra applicazione. Chiaramente, ad ognuno dei componenti, può essere associata opportunamente una azione (o anche più di una). Una "lista della spesa" dei componenti Swing vede la presenza di JCheckBox, JComboBox, JList, JMenu, JRadioButton, JSlider, JSpinner, JTextField, JPasswordField. Ribadiamo ai programmatori principianti di fare riferimento ai titoli indicati nella bibliografia in coda all'articolo.

SwiXml

Costruire un'interfaccia grafca utente basata su documenti XML non è un'idea completamente nuova. Progetti comeThinlet [4], XUL, XULUX, Jelly e SwingML, per citarne alcuni, hanno avuto un discreto successo.[2] http://www.thinlet.com/

SwiXml è un motore che genera interfacce grafiche, sia per applicazioni che per applet. Il meccanismo di funzionamento è piuttosto lineare:

l'interfaccia viene strutturata in un file XML;

il file viene sottoposto a parsing a tempo di esecuzione;

viene eseguito il rendering in oggetti di tipo javax.swing.

Nulla impedisce di caricare in modo dinamico un documento XML che descrive la GUI dell'applicazione.

Chiaramente, SwiXml non fa tutto da solo: lo sviluppatore deve comunque conoscere il package javax.swing, la sua strutturazione, i suoi componenti e il modo corretto di usarli nella creazione di un'interfaccia, specie in relazione alle azioni cui i componenti vengono associati. Ciò che SwiXml compie al meglio, invece, è ridurre la quantità di lavoro ripetitivo (in quanto tale soggetto a errori) per la realizzazione di interfacce grafiche complesse.

Prerariamo l’ambiente di lavoro

Per prima cosa apriamo il nostro browser e andiamo nella home page [2] del progetto SwiXML (figura 2).

Figura 2 - La home page del progetto SwiXml.
Figura 2 - La home page del progetto SwiXml.

Clicchiamo sulla voce Inside e, in fondo alla pagina, dovremmo trovare la sezione download per scaricare il file che ci interessa.

Figura 3 - Ecco da dove effettuare il downolad.
Figura 3 - Ecco da dove effettuare il downolad.

Apriamo il file ZIP appena scaricato e copiamo la cartella swixml149\lib nella directory del nostro progetto Java. Inoltre all’interno della cartella dobbiamo anche copiare il file JAR swixml contenuto in swixml149\build. Il pathclass del nostro progetto apparirà simile a quello mostrato in figura 4.

Figura 4 - Il pathclass del nostro progetto.
Figura 4 - Il pathclass del nostro progetto.

Un ulteriore passo importante nella creazione del nostro ambiente di lavoro è il seguente: nella cartella src, dovremo creare anche una cartella xml, dove verrano salvati i file XML che andremo a scrivere per le nostre applicazioni.

Figura 5 - Occorre creare una cartella xml dentro src. In essa salveremo i file XML.
Figura 5 - Occorre creare una cartella xml dentro src. In essa salveremo i file XML.

HelloWorld

Bene, adesso che abbiamo sistemato il nostro ambiente di lavoro, siamo pronti per scrivere la nostra prima interfaccia con SwiXml; come ogni prima prova che si rispetti, scriviamo dentro una finestra il nostro immancabile “Hello World”!

Es1.java

Secondo i principi di SwiXml, il file .java in questo caso ci serve solo da contenitore per far partire l’interfaccia grafica: in realtà il codice che definisce la GUI è descritto nell’XML.

import org.swixml.SwingEngine;
import javax.swing.*;
import java.awt.event.ActionEvent;
public class Es1 {
  private Es1() throws Exception {
    new SwingEngine( this ).render( "xml/Es1.xml" ).setVisible( true );
  }
  public static void main( String[] args ) throws Exception {
    new Es1();
  }
}

Es1.xml

Nel file .xml scriviamo il codice per generare la GUI. Come potete notare, abbiamo definito la grandezza della finestra, il titolo e l’operazione di chiusura. In questa Gui al centro potete trovare la scritta “Hello World! MokaByte”

<frame size="640,280" title="Hello SWIXML World" defaultCloseOperation="JFrame.EXIT_ON_CLOSE">
  <panel constraints="BorderLayout.CENTER">
    <label labelfor="tf" font="Georgia-BOLD-18" foreground="blue" text="Hello World!"/>
    <label labelfor="tf1" font="Georgia-BOLD-18" foreground="green" text="MokaByte"></label>
  </panel>
</frame>
Figura 6 - Ecco la nostra finestra JFrame, con l'immancabile "Hello World!".
Figura 6 - Ecco la nostra finestra JFrame, con l'immancabile "Hello World!".

JLabel, JTextField e JButton

Dopo aver stampato una stringa a vdeo, proviamo a creare qualcosa di più complicato. In questo esempio si vuole scrivere il proprio nome in una JTextField e premendo un pulsante più in basso comparirà un saluto con la stringa “Ciao” (descritta nell’xml) accanto al nome che abbiamo inserito precedentemente.

Es2.java

import org.swixml.SwingEngine;
import javax.swing.*;
import java.awt.event.ActionEvent;
public class Es2 {
  public JTextField tf;
  public JLabel stampa;

  // Definisco l’azione invia che ci consente di stampare nella JLabel creata il saluto
  public Action invia= new AbstractAction() {
    public void actionPerformed( ActionEvent e ) {
      stampa.setText( tf.getText() );
    }
  };

  // Costruttore per far elaborare il file xml
  private Es2() throws Exception {
    new SwingEngine( this ).render( "xml/Es2.xml" ).setVisible( true );
  }

  // Main
  public static void main( String[] args ) throws Exception {
    new Es2();
  }

}

Es2.xml

Nella parte superiore di questa GUI abbiamo inserito una etichetta, un campo di testo e un pulsante al quale è collegata l’azione invia. Nella parte inferiore invece possiamo notare due label: la prima stampa “Ciao!”, la seconda invece visualizza il contenuto del textfield.

<?xml version="1.0" encoding="UTF-8"?>
<frame size="640,280" title="Ciao!" defaultCloseOperation="JFrame.EXIT_ON_CLOSE">
  <panel constraints="BorderLayout.CENTER">
    <label labelfor="tf" font="Georgia-BOLD-12" foreground="blue" text="Come ti Chiami??"/>
    <textfield id="tf" columns="20" Text="Swixml"/>
    <button text="ok" action="invia"/>
  </panel>
  <panel constraints="BorderLayout.SOUTH">
    <label font="Georgia-BOLD-36" text="Ciao! "/>
    <label font="Georgia-BOLD-36" id="stampa"/>
  </panel>
</frame>
Figura 7 - Ecco la visualizzazione dell'esempio appena riportato.
Figura 7 - Ecco la visualizzazione dell'esempio appena riportato.

JComboBox

Con SwiXml è possibile creare anche delle ComboBox: vediamo insieme come farlo. Prima di tutto bisogna creare una classe ComboModel per inserire i valori nella nostra ComboBox.

// ComboModel.java
import javax.swing.*;
/**
 * Combobox Model used in the InitClass sample.
 */
public class ComboModel extends DefaultComboBoxModel {
  /**
   * Constructs a DefaultComboBoxModel object.
   */
  public ComboModel() {
    super( new Object[]{"Item1", "Item2", "Item3", "Item4", "Item5"} );
  }
}

Es3.java

A questo punto possiamo passare alla creazione della classe Java.

import org.swixml.SwingEngine;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Es3 extends WindowAdapter implements ActionListener {
  private SwingEngine swix;
  public Action azione = new AbstractAction() {
    public void actionPerformed(ActionEvent e) {
      System.out.println(       ((JComboBox) e.getSource()).getSelectedItem().toString() );
    }
  };

  private Es3() {
    try {
      swix = new SwingEngine( this );
      swix.render( "xml/Es3.xml" );
      swix.getRootComponent().setVisible(true);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    new Es3();
  }
  @Override
  public void actionPerformed(ActionEvent arg0) {
    // TODO Auto-generated method stub
  }
}

Es3.xml

<?xml version="1.0" encoding="UTF-8" ?>
<frame id="frame" title="ComboBox" size="360,200" >
  <panel Border="EtchedBorder">
    <label labelfor="cbx" Font="Comic Sans MS-BOLD-12" Foreground="blue">ComboBox</label>
    <combobox id="cbx" initclass="ComboModel" Action="azione" PrototypeDisplayValue="1234567890|1234567890"/>
  </panel>
  <panel constraints="BorderLayout.SOUTH">
  <label>Stato:</label>
  </panel>
</frame>
Figura 8 - Ed ecco la nostra ComboBox dell'Es3.
Figura 8 - Ed ecco la nostra ComboBox dell'Es3.

Alcuni Layout Manager

Di seguito mostriamo alcune implementazioni usate da SwiXml per gestire i layout delle applicazioni. Ancora una volta gli esempi saranno autoesplicativi: per questo set di esempi però useremo una sola classe Java. I diversi file XML, invece, sono sempre denominati Es4.xml, ma cambiano nella loro formulazione: accanto al nome viene riportato ciò che fanno, ossia il layout cui danno origine quando accoppiati alla classe Es4.java.

Es4.java

import org.swixml.SwingEngine;

public class Es4 extends SwingEngine {

  private Es4() {
    try {
      render( "xml/Es4.xml" ).setVisible( true );
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) {
    new Es4();
  }
}

Es4.xml = FlowLayout

<?xml version="1.0" encoding="UTF-8"?>
<frame name="frame" size="500,300" title="FlowLayout" background="FFFFFF" layout="FlowLayout">
  <panel Title="Flow Layout (right aligned)" Bounds="10,10,150,150" Layout="FlowLayout(FlowLayout.CENTER)" Visible="true" Resizable="true">
    <button>1</button>
    <button>2</button>
    <button>3</button>
    <button>4</button>
  </panel>
</frame>
Figura 9 - L'implementazione del FlowLayout.
Figura 9 - L'implementazione del FlowLayout.

Es4.xml = GridLayout

<?xml version="1.0" encoding="UTF-8"?>
<frame name="frame" size="500,300" title="GridLayout" background="FFFFFF" layout="GridLayout">
  <panel Title="Grid Layout" Bounds="200,10,150,150" Layout="GridLayout(2,2)" Visible="true" Resizable="true">
    <button text="1"/>
    <button text="2"/>
    <button text="3"/>
    <button text="4"/>
  </panel>
</frame>
Figura 10 - L'implementazione del GridLayout.
Figura 10 - L'implementazione del GridLayout.

Es4.xml = GridBagLayout

<?xml version="1.0" encoding="UTF-8"?>
<frame name="frame" size="500,300" title="GridBagLayout" background="FFFFFF" layout="GridBagLayout">
  <panel Title="Gridbag Layout" Bounds="400,170,220,210" Layout="GridBagLayout" Visible="true" Resizable="true">
    <button text="b1">
      <gridbagconstraints id="gbc_1" insets="2,2,2,2" gridx="0" gridy="0" ipadx="15" ipady="15" weightx="1" weighty="1"/>
    </button>
    <button text="b2">
      <gridbagconstraints refid="gbc_1" gridx="1"/>
    </button>
    <button text="b3">
      <gridbagconstraints refid="gbc_1" gridy="1"/>
    </button>
    <button text="b4">
      <gridbagconstraints refid="gbc_1" gridx="1" gridy="1"/>
    </button>
  </panel>
</frame>
Figura 11 - L'implementazione del GridBagLayout.
Figura 11 - L'implementazione del GridBagLayout.

Es4.xml = BorderLayout

<?xml version="1.0" encoding="UTF-8"?>
<frame name="frame" size="500,300" title="Borderlayout" background="FFFFFF" layout="Borderlayout">
  <panel Title="Border Layout" Bounds="390,10,150,150" Layout="borderlayout" Visible="true" Resizable="true">
    <button constraints="BorderLayout.NORTH">1</button>
    <button constraints="BorderLayout.EAST">2</button>
    <button constraints="BorderLayout.SOUTH">3</button>
    <button constraints="BorderLayout.WEST">4</button>
  </panel>
</frame>
Figura 12 - L'impementazione del BorderLayout.
Figura 12 - L'impementazione del BorderLayout.

Applet

SwiXml, ci permette di creare anche delle semplici applet, semplicemente aggiungendo un descrittore (descriptor) all’interno del file .java. Rispetto alle classi precedenti, non è che cambi molto.

Es8.java

public class Es8 extends JApplet {

  public JTextField tf;
  public AbstractAction azione = new AbstractAction() {
    public void actionPerformed( ActionEvent e ) {
      tf.setText( tf.getText() + '@' );
    }
  };

  public void init() {
    super.init();
    try {
      String descriptorfile = this.getParameter( "xml" );
      if (descriptorfile == null) {
        descriptorfile = "xml/Es8.xml";
      }
      new SwingEngine( this ).insert( new URL( getCodeBase(), descriptorfile ), this );
      this.setVisible( true );
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Es8.xml

<applet size="640,480">
  <panel constraints="BorderLayout.CENTER">
    <label DisplayedMnemonic="VK_E" LabelFor="tf" Font="Comic Sans MS-BOLD-12" Foreground="blue">
      Aggiungi un '@'
    </label>
    <textfield id="tf" Columns="20" Text="@"/>
    <button id="btn" Text="ok" Action="azione"/>
  </panel>
</applet>
Figura 13 - L'applet dell'esempio Es8.
Figura 13 - L'applet dell'esempio Es8.

CustomTag

Grazie a questa funzionalità, contenuta in SwiXml, possiamo utilizzare degli oggetti già inclusi: ad esempio, di seguito viene mostrato il modo in cui creare un calendario.

Es9.java

import com.toedter.calendar.*;
import org.swixml.SwingEngine;
import org.swixml.ConverterLibrary;
import org.jvnet.substance.SubstanceLookAndFeel;
import org.jvnet.substance.theme.SubstanceEbonyTheme;

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

public class Es9 extends WindowAdapter {

  public Es9() throws Exception {
    SwingEngine swix = new SwingEngine(this);
    swix.getTaglib().registerTag("Calendar", JCalendar.class);
    swix.render("xml/Es9.xml").setVisible(true);
  }

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

  public static void main(String[] args) throws Exception {
    new Es9();
  }
}

Es9.xml

<?xml version="1.0" encoding="UTF-8" ?>
<frame title="Calendario" size="400,260" defaultCloseOperation="JFrame.EXIT_ON_CLOSE"> <!--plaf="org.jvnet.substance.skin.SubstanceRavenLookAndFeel">                              -->
  <panel layout="BorderLayout">
  <panel  border="TitledBorder(JCalendar,0,1,VERDANA-BOLD-18)"   background="white" constraints="BorderLayout.NORTH">
    <label font="Comic Sans MS-BOLD-18" foreground="black">Calendario</label>
  </panel>
    <calendar initclass="java.util.Date"/>
  </panel>
</frame>
Figura 14 - L'esempio Es9 con il calendario.
Figura 14 - L'esempio Es9 con il calendario.

Conclusioni

SwiXml è indubbiamente un buono strumento per chi ha poca familiarità con le API swing di Java. Con la modifica del solo file XML si possono realizzare ottime interfacce grafiche in Java, soprattutto quando si ha poco tempo a disposizione: magari non è la soluzione per realizzare l'applicazione "definitiva" (ma per quello ci sono altri strumenti), ma di certo, per creare le nostre utility potrebbe essere proprio quello che ci serviva. Abbiamo fornito alcuni esempi proprio per mettere in luce come sia possibile creare delle semplici GUI standard da poter riutilizzare più volte per le proprie applicazioni, anche in un'ottica di uniformità dell'esperienza utente. Insomma, uno strumento semplice che fa cose semplici, ma in modo rapido e affidabile.

Riferimenti

  • [1] Andrea Gini, capp. 12-17 in AAVV, "Manuale pratico di Java. Dalla teoria alla programmazione", Hops - Tecniche Nuove, 2003
  • [2] Il sito ufficiale di SwiXml

http://www.swixml.org/

  • [3] La pagina dedicata ai componenti Swing

http://download.oracle.com/javase/tutorial/ui/features/components.html

  • [4] Thinlet, un analogo progetto per la realizzazione di interfacce grafiche a partire da XML

http://thinletweb.appspot.com/