JavaFX con stile – Rubrica telefonica

di - 9 ottobre 2012 in Programmazione

Come annunciato nel corso del precedente articolo, questo nostro ultimo appuntamento con le JavaFX sarà focalizzato sullo sviluppo di un’applicazione completa che oltre a fare uso di alcuni elementi di base disponibili all’interno della libreria degli oggetti, mostre in che modo è possibile modificarne l’aspetto mediante l’uso dei fogli stili.

L’applicazione che ci accingiamo a sviluppare è una rubrica telefonica, al suo interno è stato previsto il seguente insieme di operazioni:

  • Inserimento di un nuovo contatto;
  • Modifica di un’entry in precedenza definita;
  • Cancellazione di un record;
  • Ricerca all’interno della rubrica.

L’attuale implementazione della nostra soluzione non prevede alcun processo di salvataggio, non è questo un grosso limite poiché non è questo l’obiettivo che ci poniamo di raggiungere con questo codice, infatti, il nostro obiettivo, lo rimarchiamo ancora una volta, è quello di mostrare come l’utilizzo delle JavaFX in combinazione con i fogli stile consentano di dare una nuova linfa allo sviluppo delle applicazioni Windows based.

Detto, questo mostriamo nel seguito i sorgenti che si riferiscono al foglio stile utilizzato all’interno della nostra applicazione e il corrispondente file fxml all’interno del quale è descritta la struttura della nostra interfaccia

Foglio Stile (rubricaFx.css)

/*

Document   : rubricaFx

Created on : 22-set-2012, 8.58.41

Author     : Alessandro Grande

Description:

Purpose of the stylesheet follows.

*/

 

#AnchorPane {

-fx-background-color:  linear-gradient(from 0px 0px to 0px 100px, #6495ed, white 80%,#5f9ea0,  lightgray);

}

.esci {

-fx-background-color:

linear-gradient(#ffd65b, #e68400),

linear-gradient(#ffef84, #f2ba44),

linear-gradient(#ffea6a, #efaa22),

linear-gradient(#ffe657 0%, #f8c202 50%, #eea10b 100%),

linear-gradient(from 0% 0% to 15% 50%, rgba(255,255,255,0.9), rgba(255,255,255,0));

-fx-background-radius: 30;

-fx-background-insets: 0,1,2,3,0;

-fx-text-fill: #000000;

-fx-font-weight: bold;

-fx-font-size: 14px;

-fx-padding: 10 20 10 20;

}

#dentro {

-fx-background-color:

linear-gradient(#ff0000, #ff4500),

linear-gradient(#ff0000, #ff4500),

linear-gradient(#ff0000 0%, #ff4500 50%, #ff4522 100%),

linear-gradient(from 0% 0% to 15% 50%, rgba(255,255,255,0.9), rgba(255,255,255,0));

-fx-background-radius: 30;

-fx-background-insets: 0,1,2,3,0;

-fx-text-fill: whitesmoke;

-fx-font-weight: bold;

-fx-font-size: 14px;

-fx-padding: 10 20 10 20;

}

#normale {

-fx-background-color:

linear-gradient(#ffd65b, #e68400),

linear-gradient(#ffef84, #f2ba44),

linear-gradient(#ffea6a, #efaa22),

linear-gradient(#ffe657 0%, #f8c202 50%, #eea10b 100%),

linear-gradient(from 0% 0% to 15% 50%, rgba(255,255,255,0.9), rgba(255,255,255,0));

-fx-background-radius: 30;

-fx-background-insets: 0,1,2,3,0;

-fx-text-fill: #654b00;

-fx-font-weight: bold;

-fx-font-size: 14px;

-fx-padding: 10 20 10 20;

}

#evidenzia {

-fx-background-color:

linear-gradient(#1e90ff, #00bfff),

linear-gradient(#1e90ff, #00bfff),

linear-gradient(#1e90ff, #00bfff),

linear-gradient(#1e90ff 0%, #00bfff 50%, #00aa8b 100%),

linear-gradient(from 0% 0% to 15% 50%, rgba(255,255,255,0.9), rgba(255,255,255,0));

-fx-background-radius: 30;

-fx-background-insets: 0,1,2,3,0;

-fx-text-fill: #fff;

-fx-font-weight: bold;

-fx-font-size: 14px;

-fx-padding: 10 10 10 20;

}

.my_label {

-fx-font-size: 20px;

-fx-font-family: serif;

-fx-font-weight: bold;

-fx-text-fill: linear-gradient( #b22222,#ff8c00);

}

.titolo {

-fx-effect: dropshadow(gaussian,orange,25,0.25,4,4);

-fx-text-fill: linear-gradient(black,#ff2233);

-fx-font-size: 72px;

-fx-font-family: serif;

-fx-font-weight: bold;

-fx-padding: 5 10 5 10;

}

#text_field {

-fx-background-color: linear-gradient(gray,white);

-fx-background-radius: 30;

-fx-text-fill:black;

-fx-font-family: serif;

}

 

Di seguito riportiamo invece il sorgente per il file FXML all’interno del quale si definisce la struttura dell’interfaccia grafica della nostra applicazione.

<?xml version=”1.0″ encoding=”UTF-8″?>

 

<?import java.lang.*?>

<?import java.net.*?>

<?import java.util.*?>

<?import javafx.scene.*?>

<?import javafx.scene.control.*?>

<?import javafx.scene.layout.*?>

 

<AnchorPane id=”AnchorPane” fx:id=”main_panel” prefHeight=”508.0″ prefWidth=”754.0″ xmlns:fx=”//javafx.com/fxml” fx:controller=”rubricafx2.SampleController”>

<children>

<Button id=”normale” fx:id=”esci” layoutX=”655.0″ layoutY=”447.0″ onAction=”#handleButtonAction” onMouseEntered=”#handleButtonOnMouseEntered” onMouseExited=”#handleButtonOnMouseExited” prefWidth=”83.0″ text=”Esci” textFill=”WHITE” />

<Button id=”normale” fx:id=”inserisci_utente” layoutX=”13.0″ layoutY=”449.0″ onAction=”#handleButtonAction” onMouseEntered=”#handleButtonOnMouseEntered” onMouseExited=”#handleButtonOnMouseExited” text=”Inserisci Utente” />

<Button id=”normale” fx:id=”modifica_utente” layoutX=”166.0″ layoutY=”449.0″ mnemonicParsing=”false” onMouseClicked=”#modify” onMouseEntered=”#handleButtonOnMouseEntered” onMouseExited=”#handleButtonOnMouseExited” text=”Modifica Utente” />

<Button id=”normale” fx:id=”ricerca_utente” layoutX=”326.0″ layoutY=”447.0″ mnemonicParsing=”false” onAction=”#handleButtonAction” onMouseClicked=”#search” onMouseEntered=”#handleButtonOnMouseEntered” onMouseExited=”#handleButtonOnMouseExited” text=”Ricerca Utente” />

<Label styleClass=”titolo” text=”Rubrica” />

<Button id=”normale” fx:id=”cancella_utente” layoutX=”480.0″ layoutY=”449.0″ mnemonicParsing=”false” onMouseClicked=”#delete” onMouseEntered=”#handleButtonOnMouseEntered” onMouseExited=”#handleButtonOnMouseExited” text=”Cancella Utente” />

<Label layoutX=”13.0″ layoutY=”134.0″ styleClass=”my_label” text=”Nome:” />

<Label id=”” layoutX=”13.0″ layoutY=”177.0″ styleClass=”my_label” text=”Cognome” />

<Label layoutX=”14.0″ layoutY=”205.0″ prefHeight=”67.0″ prefWidth=”218.0″ styleClass=”my_label” text=”Indirizzo (Via,Civico,Città)” wrapText=”true” />

<Label layoutX=”16.0″ layoutY=”275.0″ styleClass=”my_label” text=”Email” />

<Label layoutX=”15.0″ layoutY=”308.0″ styleClass=”my_label” text=”Telefono:” />

<Label layoutX=”16.0″ layoutY=”342.0″ styleClass=”my_label” text=”Cellulare:” />

<Label layoutX=”15.0″ layoutY=”379.0″ styleClass=”my_label” text=”Note:” />

<Button id=”normale” fx:id=”prossimo_contatto” layoutX=”383.0″ layoutY=”32.0″ mnemonicParsing=”false” onMouseClicked=”#nextEntry” onMouseEntered=”#handleButtonOnMouseEntered” onMouseExited=”#handleButtonOnMouseExited” text=”Prossimo Contatto” />

<Button id=”normale” fx:id=”precedente_contatto” layoutX=”561.0″ layoutY=”32.0″ mnemonicParsing=”false” onMouseClicked=”#prevEntry” onMouseEntered=”#handleButtonOnMouseEntered” onMouseExited=”#handleButtonOnMouseExited” text=”Contatto Precedente” />

<TextField id=”text_field” fx:id=”nome” layoutX=”141.0″ layoutY=”145.0″ prefWidth=”584.0″ promptText=”nome” />

<TextField id=”text_field” fx:id=”cognome” layoutX=”141.0″ layoutY=”188.0″ prefWidth=”584.0″ promptText=”cognome” />

<TextField id=”text_field” fx:id=”indirizzo” layoutX=”195.0″ layoutY=”228.0″ prefWidth=”530.0″ promptText=”indirizzo” />

<TextField id=”text_field” fx:id=”mail” layoutX=”144.0″ layoutY=”279.0″ prefWidth=”582.0″ promptText=”mail” />

<TextField id=”text_field” fx:id=”telefono” layoutX=”144.0″ layoutY=”312.0″ prefWidth=”582.0″ promptText=”telefono” />

<TextField id=”text_field” fx:id=”cellulare” layoutX=”146.0″ layoutY=”346.0″ prefWidth=”582.0″ promptText=”cellulare” />

<TextField id=”text_field” fx:id=”note” layoutX=”146.0″ layoutY=”381.0″ prefWidth=”582.0″ promptText=”note” />

</children>

<stylesheets>

<URL value=”@rubricaFx.css” />

</stylesheets>

</AnchorPane>

 

Visivamente il risultato determinato dal foglio stile e dal file xml appena presentato è il seguente risultato:

 

Se non si fosse fatto uso del foglio stile precedente, il risultato della sola definizione del file FXML sarebbe stato il seguente:

Indubbiamente si tratta di un risultato non particolarmente esaltante.

Osservando il codice xml si nota come la gestione degli eventi sia stata definita tramite una classe java completamente separata, decisione questa che consente di mantenere separata la logica di business da quella di presentazione, rispettando in questo modo i dettami classi del pattern MVS, non a caso il nome della classe all’interno della quale sono stati definiti i diversi gestori degli eventi utilizza come suffisso la parola Controller, proprio a voler porre l’accento ulteriormente il legame con la teoria dei design pattern.

A questo punto l’ultimo elemento necessario al completamento del nostro progetto e su cui appuntiamo adesso la nostra attenzione è la classe controller di cui riportiamo di seguito il sorgente.

/*

* To change this template, choose Tools | Templates

* and open the template in the editor.

*/

package rubricafx2;

 

import java.net.URL;

import java.util.HashMap;

import java.util.LinkedList;

import java.util.ListIterator;

import java.util.ResourceBundle;

import javafx.event.ActionEvent;

import javafx.fxml.FXML;

import javafx.fxml.Initializable;

import javafx.scene.Node;

import javafx.scene.control.Button;

import javafx.scene.control.TextField;

import javafx.scene.input.MouseEvent;

import javafx.scene.layout.AnchorPane;

import javax.swing.JOptionPane;

 

/**

*

* @author Alessandro Grande

*/

public class SampleController implements Initializable {

@FXML

public Button esci;

public Button inserisci_utente;

public Button prossimo_contatto;

public Button precedente_contatto;

public Button modifica_utente;

public Button ricerca_utente;

public Button cancella_utente;

public TextField nome,cognome,email,telefono,cellulare,indirizzo,note;

public AnchorPane main_panel;

private String lastAction=””;

private LinkedList<HashMap<String,String>> rubricaTelefonica = new LinkedList();

private LinkedList<HashMap<String,String>> risultatiRicerca;

private int rubricaIndex=0;

private int risultatiIndex=0;

private HashMap<String,String> contatto;

@FXML

private void handleButtonAction(ActionEvent event) {

Object source = event.getSource();

if(source==esci) {

System.exit(0);

} else if(source==inserisci_utente) {

insert_new_user();

} else if(source==ricerca_utente) {

}

}

@FXML

private void handleButtonOnMouseEntered(MouseEvent event) {

if((event.getSource())instanceof  Button) {

if(event.getSource()==esci) {

esci.setId(“dentro”);

}

else {

((Button)event.getSource()).setId(“evidenzia”);

}

}

}

@FXML

private void handleButtonOnMouseExited(MouseEvent event) {

if((event.getSource())instanceof  Button) {

((Button)event.getSource()).setId(“normale”);

}

}

@Override

public void initialize(URL url, ResourceBundle rb) {

// TODO

}

private void insert_new_user() {

lastAction=”insert”;

ListIterator<Node> iterator = main_panel.getChildren().listIterator();

contatto=new HashMap<>();

while(iterator.hasNext()) {

Node currentElement = iterator.next();

if(currentElement  instanceof TextField)

{

//inserimento delle nuove informazioni all’interno dello hashmap

contatto.put(((TextField)currentElement).getPromptText(),((TextField)currentElement).textProperty().getValue()==null?””:((TextField)currentElement).textProperty().getValue());

}

}

rubricaTelefonica.add(contatto);

clearAllField();

}

private void clearAllField() {

ListIterator<Node> iterator = main_panel.getChildren().listIterator();

while(iterator.hasNext()) {

Node currentElement = iterator.next();

if(currentElement  instanceof TextField)

{

((TextField)currentElement).clear();

}

}

}

@FXML

private void nextEntry(MouseEvent evt) {

HashMap<String,String> info= lastAction.equals(“insert”)?rubricaTelefonica.get(Math.abs(rubricaIndex%(rubricaTelefonica.size())))

:risultatiRicerca.get(Math.abs(risultatiIndex%(risultatiRicerca.size())));

printInfo(info);

if(lastAction.equals(“insert”)) {

rubricaIndex++;

}

else {

risultatiIndex++;

}

}

@FXML

private void prevEntry(MouseEvent evt) {

HashMap<String,String> info = lastAction.equals(“insert”)?rubricaTelefonica.get(Math.abs(rubricaIndex%(rubricaTelefonica.size())))

:risultatiRicerca.get(Math.abs(risultatiIndex%(risultatiRicerca.size())));

printInfo(info);

if(lastAction.equals(“insert”)) {

rubricaIndex–;

}

else {

risultatiIndex–;

}

}

@FXML

private void search() {

// al momento la ricerca viene eseguita solamente rispetto ai

// campi nome e cognome

String criterio1=nome.getText().toLowerCase();

String criterio2=cognome.getText().toLowerCase();

risultatiRicerca = new LinkedList();

risultatiIndex=1;

for(HashMap<String,String> contattoRubrica:rubricaTelefonica) {

if((contattoRubrica.get(“nome”).toLowerCase().indexOf(criterio1)>=0)&&

(contattoRubrica.get(“cognome”).toLowerCase().indexOf(criterio2)>=0)) {

risultatiRicerca.add(contattoRubrica);

}

}

clearAllField();

if(risultatiRicerca.size()>0) {

printInfo(risultatiRicerca.get(0));

}

else {

nome.setText(“Nessun Risultato Prodotto”);

}

lastAction=”search”;

}

@FXML

private void delete() {

String criterio1=nome.getText().toLowerCase();

String criterio2=cognome.getText().toLowerCase();

HashMap<String,String> contattoRubrica;

if((criterio1.length()>0)&&(criterio2.length()>0)) {

for(int index =0; index<rubricaTelefonica.size();index++) {

contattoRubrica = rubricaTelefonica.get(index);

if((contattoRubrica.get(“nome”).toLowerCase().equals(criterio1))&&

(contattoRubrica.get(“cognome”).toLowerCase().equals(criterio2))) {

rubricaTelefonica.remove(contattoRubrica);

break;

}

}

clearAllField();

} else {

JOptionPane.showMessageDialog(null, “E’ necessario compilare sia il campo nome sia quello cognome”, “Impossibile effettuare l’operazione”, JOptionPane.INFORMATION_MESSAGE);

}

}

@FXML

private void modify() {

ListIterator<Node> iterator = main_panel.getChildren().listIterator();

contatto=new HashMap<>();

while(iterator.hasNext()) {

Node currentElement = iterator.next();

if(currentElement  instanceof TextField)

{

//inserimento delle nuove informazioni all’interno dello hashmap

contatto.put(((TextField)currentElement).getPromptText(),((TextField)currentElement).textProperty().getValue()==null?””:((TextField)currentElement).textProperty().getValue());

}

}

delete();

rubricaTelefonica.add(contatto);

}

private void printInfo(HashMap<String,String> contatto) {

int index=0;

ListIterator<Node> iterator = main_panel.getChildren().listIterator();

while(iterator.hasNext()) {

Node currentElement = iterator.next();

if(currentElement  instanceof TextField)

{

((TextField)currentElement).textProperty().setValue(contatto.get(((TextField)currentElement).getPromptText()));

index++;

}

}

}

}

 

Da un punto di vista del codice l’elemento su cui vogliamo appuntare la nostra attenzione è l’uso delle annotazioni, in particolare la combinazione “@FXML” è fondamentale sia per l’associazione tra attributi della classe e corrispondenti elementi dell’interfaccia, sia per consentire l’associazione dei differenti gestori di eventi definiti per gestire le diverse operazioni implementate all’interno del nostro programma.  Chiaramente gli elementi sin qui presentati sono ancora insufficienti per permettere l’esecuzione del nostro programma, per farlo è, infatti, necessaria la definizione della classe main di cui riportiamo il codice:

/*

* To change this template, choose Tools | Templates

* and open the template in the editor.

*/

package rubricafx2;

 

import javafx.application.Application;

import javafx.fxml.FXMLLoader;

import javafx.scene.Parent;

import javafx.scene.Scene;

import javafx.stage.Stage;

 

/**

*

* @author Alessandro Grande

*/

public class RubricaFX2 extends Application {

@Override

public void start(Stage stage) throws Exception {

Parent root = FXMLLoader.load(getClass().getResource(“Sample.fxml”));

Scene scene = new Scene(root);

stage.setScene(scene);

stage.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().

*

* @param args the command line arguments

*/

public static void main(String[] args) {

launch(args);

}

}

 

Con quest’ultimo codice si termina, il nostro ciclo introduttivo relativo alle JavaFX® e al modo in cui esse possano essere utilizzate per dare una nuova vita alle applicazioni Windows Based.

Share

Promozioni

Potrebbe interessarti



Commenti