JavaFX 2 Tutorial
JavaFX 2 Tutorial
ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Objetivo
El objetivo de este tutorial es aprender cmo crear interfaces grficas de usuario con JavaFX 2 yConstructor de escena . Vamos a cubrir muchas caractersticas de JavaFX 2 mediante la creacin de una aplicacin de direcciones y mejorndola de forma paso a paso.
Temas en la Parte I
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Mediante el Generador de escenas a disear la interfaz de usuario Estructura de la aplicacin bsica utilizando el patrn Modelo Vista Controlador (MVC)
Parte I - Generador de Escena Parte II - Modelo y TableView Parte III - Interactuar con el usuario Parte IV - CSS Styling Parte V - Almacenamiento de datos como XML Parte VI - Estadsticas Grfico Parte VII - Despliegue con e (fx) clipse
Requisitos previos
ltimas Java JDK 7 que incluye JavaFX 2.2 o superior. Eclipse 4.2 o ms con e (fx) clipse plugin. La forma ms fcil es descargar la distro preconfigurada de la pgina web clipse e (fx) . Escena Generador de 1,1 o mayor
JavaFX Ensemble es una galera de ms de 100 aplicaciones de ejemplo que utilizan una amplia gama de funciones de JavaFX. Contiene cdigo fuente para cada muestra. Contiene enlaces a documentacin de la API (JavaDoc). Otros enlaces tiles:
JavaFX Tutoriales - Tutoriales oficiales de Oracle JavaFX 2 API - JavaDoc para las clases de JavaFX API Java 7 - JavaDoc para las clases Java estndar Ahora, vamos a empezar!
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Para las clases de controlador: ch.makery.address Para las clases de vista: ch.makery.address.view Para las clases del modelo: ch.makery.address.model
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Haga clic en PersonOverview.fxml y seleccione Abrir con el Generador de Escena . Ahora debera ver el Constructor Escena con slo un AncherPane (visible bajo la Jerarqua de la izquierda). 1. Seleccione el panel de anclaje en la Jerarqua y ajustar el tamao en Diseo (lado derecho):
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
2. Agregar un panel de Split (flujo horizontal) arrastrndolo desde la biblioteca a la zona principal. Haga clic derecho y seleccione Ajustar a los padres .
3. Aadir un TableView en el lado izquierdo. Seleccione la TableView (no una columna) y establezca las siguientes restricciones de diseo. Dentro de un AnchorPane siempre se puede establecer puntos de anclaje para los cuatro bordes ( ms informacin sobre los diseos ).
4. Ir al men Ver | Vista previa en la ventana para ver, si se comporta bien. Trate de cambiar el tamao de la ventana. El TableView siempre debe mantener la distancia 10px a la frontera circundante.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
6. Agregar una etiqueta a la derecha con el texto "Detalles Persona". Ajuste su diseo mediante anclajes.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
8. Agregue un poco de filas (bajo Layout | GridPane Filas ). Aadir etiquetas a las clulas.
9. Aadir los tres botones en la parte inferior. Tipp: Seleccione todos ellos, haga clic derecho y llameWrap sesin | HBox . Esto, junto los agrupa. Es posible que tenga que especificar un espaciado dentro de la caja horizontal. 10. Ahora usted debera ver algo como lo siguiente. Por favor, prubelo usando el men Vista previa.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
2. Abrirlo en el Generador de escena. 3. Cambiar el tamao del BorderPane con Pref Ancho establece en 600 y Pref Altura establece en 400.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
4. Aadir un MenuBar en el TOP Slot. No vamos a implementar la funcionalidad del men en el momento.
5. Ahora, tenemos que crear el Java principal que inicia nuestra aplicacin con el RootLayout.fxml y agrega el PersonOverview.fxml en el centro. 6. Haga clic en el paquete del controlador, New | Other ... y seleccione JavaFX clase principal . Lo llamaremos MainApp .
aplicacin.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Como puede ver, el comienzo (...) mtodo recibe un escenario como parmetro. Es bueno entender el concepto bsico de una aplicacin grfica con JavaFX: Fuente de la imagen: http://www.oracle.com/
Es como una obra de teatro: El Stage es el contenedor principal, que suele ser una ventana con un borde y el tpico minimizar, maximizar y cerrar botones. Dentro de la etapa de agregar una escena que puede, por supuesto, se cambi por otra escena. Dentro de la escena se aaden los nodos reales JavaFX como AnchorPane, TextBox, etc. Abrir MainApp.java y reemplace el cdigo con lo siguiente:
package ch.makery.address; import java.io.IOException; import import import import import import javafx.application.Application; javafx.fxml.FXMLLoader; javafx.scene.Scene; javafx.scene.layout.AnchorPane; javafx.scene.layout.BorderPane; javafx.stage.Stage;
public class MainApp extends Application { private Stage primaryStage; private BorderPane rootLayout;
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
@Override public void start(Stage primaryStage) { this.primaryStage = primaryStage; this.primaryStage.setTitle("AddressApp"); try { // Load the root layout from the fxml file FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/RootLayout.fxml")); rootLayout = (BorderPane) loader.load(); Scene scene = new Scene(rootLayout); primaryStage.setScene(scene); primaryStage.show(); } catch (IOException e) { // Exception gets thrown if the fxml file could not be loaded e.printStackTrace(); } showPersonOverview(); } /** * Returns the main stage. * @return */ public Stage getPrimaryStage() { return primaryStage; } /** * Shows the person overview scene. */ public void showPersonOverview() { try { // Load the fxml file and set into the center of the main layout FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/PersonOverview.fxml")); AnchorPane overviewPage = (AnchorPane) loader.load(); rootLayout.setCenter(overviewPage); } catch (IOException e) { // Exception gets thrown if the fxml file could not be loaded e.printStackTrace(); } } public static void main(String[] args) { launch(args); } }
Trate de entender el cdigo. Los diversos comentarios deben darle algunas pistas sobre lo que est pasando.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Si ejecuta la aplicacin ahora, debera ver algo como la captura de pantalla al inicio de este post.
La creacin de un modelo de clase Utilizacin de la clase modelo en un ObservableList Mostrar datos de la TableView utilizando Controladores
Parte I - Generador de Escena Parte II - Modelo y TableView Parte III - Interactuar con el usuario
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Parte IV - CSS Styling Parte V - Almacenamiento de datos como XML Parte VI - Estadsticas Grfico Parte VII - Despliegue con e (fx) clipse
/** * Default constructor. */ public Person() { } /** * Constructor with some initial data. * * @param firstName * @param lastName */ public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; // some initial dummy data this.street = "some street";
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
this.postalCode = 1234; this.city = "some city"; this.birthday = Calendar.getInstance(); } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public int getPostalCode() { return postalCode; } public void setPostalCode(int postalCode) { this.postalCode = postalCode; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Calendar getBirthday() { return birthday; } public void setBirthday(Calendar birthday) { this.birthday = birthday; } }
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Los principales datos que nuestra aplicacin gestiona es un grupo de personas. Vamos a crear una lista de persona objetos dentro del MainApp clase. Todas las dems clases de controlador despus tener acceso a la lista dentro de la MainApp .
ObservableList
Estamos trabajando con clases de vista JavaFX que siempre necesitan ser informados de los cambios realizados en la lista de personas. Esto es importante, ya que de lo contrario la vista no estara en sintona con los datos. Para este propsito, JavaFX introduce algunas nuevas clases de coleccin . A partir de esas colecciones, necesitamos la ObservableList . Para crear un nuevo ObservableList , agregue el cdigo siguiente al principio del MainApp clase. Tambin vamos a aadir un constructor que crea algunos datos de ejemplo y un mtodo getter pblico:
import javafx.collections.FXCollections; import javafx.collections.ObservableList; // ... /** * The data as an observable list of Persons. */ private ObservableList<Person> personData = FXCollections.observableArrayList(); /** * Constructor */ public MainApp() { // Add some sample personData.add(new personData.add(new personData.add(new personData.add(new personData.add(new personData.add(new personData.add(new personData.add(new personData.add(new }
data Person("Hans", "Muster")); Person("Ruth", "Mueller")); Person("Heinz", "Kurz")); Person("Cornelia", "Meier")); Person("Werner", "Meyer")); Person("Lydia", "Kunz")); Person("Anna", "Best")); Person("Stefan", "Meier")); Person("Martin", "Mueller"));
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
*/ public ObservableList<Person> getPersonData() { return personData; }
El PersonOverviewController
Ahora vamos a ver finalmente algunos datos en nuestra mesa. 1. Crear una clase normal, dentro del paquete controlador llamado PersonOverviewController.java. 2. Vamos a aadir algunas variables de instancia que nos dan acceso a la tabla y las etiquetas dentro de la vista. Los campos y algunos mtodos tienen una especial FXML @ anotacin. Esto es necesario para el archivo de fxml tener acceso a esas variables. Despus de que tengamos todo listo en el archivo fxml, la aplicacin rellenar automticamente las variables cuando se carga el archivo fxml.As que vamos a agregar el siguiente cdigo: Nota: Recuerde que debe utilizar siempre las importaciones javafx (no AWT o swing)!
PersonOverviewController.java
1 public class PersonOverviewController { 2 @FXML 3 private TableView<Person> personTable; 4 @FXML 5 private TableColumn<Person, String> firstNameColumn; 6 @FXML 7 private TableColumn<Person, String> lastNameColumn; 8 9 @FXML 10 private Label firstNameLabel; 11 @FXML 12 private Label lastNameLabel; 13 @FXML 14 private Label streetLabel; 15 @FXML 16 private Label postalCodeLabel; 17 @FXML 18 private Label cityLabel; 19 @FXML 20 private Label birthdayLabel; 21 22 // Reference to the main application 23 private MainApp mainApp; 24 25 /**
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 * The constructor. * The constructor is called before the initialize() method. */ public PersonOverviewController() { } /** * Initializes the controller class. This method is automatically called * after the fxml file has been loaded. */ @FXML private void initialize() { // Initialize the person table firstNameColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName")); lastNameColumn.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName")); } /** * Is called by the main application to give a reference back to itself. * * @param mainApp */ public void setMainApp(MainApp mainApp) { this.mainApp = mainApp; // Add observable list data to the table personTable.setItems(mainApp.getPersonData()); } }
Todos los campos y mtodos donde el archivo fxml necesidades de acceso deben ser anotados con @ FXML . En realidad, slo si son privados, pero es mejor tenerlos privado y marcarlos con la anotacin!.
El initialize () mtodo se llama de forma automtica despus de que se haya cargado el archivo fxml. En este momento, todos los campos FXML deberan haberse inicializado ya.
El PropertyValueFactory que establecimos en las columnas de mesa se utilizan para determinar qu campo dentro de la persona objeto se debe utilizar para la columna en particular.
El setMainApp (...) mtodo debe ser llamado por el MainApp clase. Esto nos da una manera de acceder a la MainApp objeto y obtener la lista de datos y otras
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
cosas. De hecho, vamos a hacer esa llamada ahora. Vuelva a colocar la showPersonOverview () mtodo con la siguiente. Contiene dos lneas adicionales:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 MainApp.java /** * Shows the person overview scene. */ public void showPersonOverview() { try { // Load the fxml file and set into the center of the main layout FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/PersonOverview.fxml")); AnchorPane overviewPage = (AnchorPane) loader.load(); rootLayout.setCenter(overviewPage); // Give the controller access to the main app PersonOverviewController controller = loader.getController(); controller.setMainApp(this); } catch (IOException e) { // Exception gets thrown if the fxml file could not be loaded e.printStackTrace(); } }
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
5. Haga lo mismo para las columnas y seleccione firstNameColumn y lastNameColumnrespectivamente. 6. Para cada etiqueta en la segunda columna, elija el correspondiente fx: id . 7. Importante: Volver a Eclipse y refrescar todo el proyecto AddressApp (F5). Esto es necesario porque Eclipse veces no sabe acerca de los cambios que se hicieron en el interior del generador de escena.
Inicio de la aplicacin
Al iniciar la aplicacin ahora, usted debera ver algo como la captura de pantalla al comienzo de esta entrada del blog. Enhorabuena!
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Reaccionar a los cambios de seleccin en la tabla. Agregar funcionalidad al aadir , editar y eliminar botones. Crea una alfombrilla de dilogo emergente para editar una persona. Validar la entrada del usuario .
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Parte I - Generador de Escena Parte II - Modelo y TableView Parte III - Interactuar con el usuario Parte IV - CSS Styling Parte V - Almacenamiento de datos como XML Parte VI - Estadsticas Grfico Parte VII - Despliegue con e (fx) clipse
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Vamos a utilizar la conversin de calendario y secuencia (y viceversa) en varios lugares. Es una buena prctica para crear una clase de ayuda con estticas mtodos para ello. Lo llamaremos CalendarUtil y colquela en un paquete separado llamado ch.makery.address.util :
(CalendarUtil.java) download
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package ch.makery.address.util; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; /** * Helper functions for handling dates. */ public class CalendarUtil { /** * Default date format in the form 2013-03-18. */ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); /** * Returns the given date as a well formatted string. The above defined date * format is used. * * @param calendar date to be returned as a string * @return formatted string */ public static String format(Calendar calendar) { if (calendar == null) { return null; } return DATE_FORMAT.format(calendar.getTime()); } /** * Converts a String in the format "yyyy-MM-dd" to a Calendar object. * * Returns null if the String could not be converted. * * @param dateString the date as String * @return the calendar object or null if it could not be converted */ public static Calendar parse(String dateString) { Calendar result = Calendar.getInstance(); try { result.setTime(DATE_FORMAT.parse(dateString)); return result; } catch (ParseException e) { return null; }
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 } } /** * Checks the String whether it is a valid date. * * @param dateString * @return true if the String is a valid date */ public static boolean validString(String dateString) { try { DATE_FORMAT.parse(dateString); return true; } catch (ParseException e) { return false; } }
Tenga en cuenta que puede cambiar el formato de la fecha cambiando la constante DATE_FORMAT .Para todos los formatos posibles ver SimpleDateFormat en la API de Java.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
12 // clear person 13 showPersonDetails(null); 14 15 // Listen for selection changes 16 17 personTable.getSelectionModel().selectedItemProperty().addListener(new 18 ChangeListener<Person>() { 19 20 @Override 21 public void changed(ObservableValue<? extends Person> observable, Person oldValue, Person newValue) { showPersonDetails(newValue); } }); }
En la lnea 10 es restablecer los datos persona. Si ha implementado showPersonDetails (...) correctamente esta debe establecer una cadena vaca a todos los campos de texto. En la lnea 13 se obtiene la selectedItemProperty de la tabla persona y aadimos un oyente al mismo. El nuevo ChangeListener es del tipo de persona , ya que tenemos Persona objetos en la tabla. Ahora, cada vez que el usuario selecciona una persona en la tabla, el mtodo cambia
(...) se
pasarlo al showPersonDetails (...) mtodo. Trate de ejecutar la aplicacin en este punto. Verificar que cuando se selecciona una persona en la mesa, los detalles sobre esa persona se muestran a la derecha. Si algo no funciona, usted puede comparar su PersonOverviewController clase con PersonOverviewController.java .
El botn Eliminar
Nuestra interfaz de usuario que ya contiene un botn de eliminar, pero sin ninguna funcionalidad.Podemos seleccionar la accin de un botn en el interior del generador de Escena . Cualquier mtodo dentro de nuestro controlador que est anotado con @ FXML (o es pblico) es accesible por el Generador de Escena . Por lo tanto, creemos primero el mtodo de eliminacin al final de nuestra PersonOverviewController clase:
PersonOverviewController.java
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
/** * Called when the user clicks on the delete button. */ @FXML private void handleDeletePerson() { int selectedIndex = personTable.getSelectionModel().getSelectedIndex(); personTable.getItems().remove(selectedIndex); }
1 2 3 4 5 6 7 8
Ahora, abra el PersonOverview.fxml archivo en SceneBuilder . Seleccione el Borrar botn, abrir elcdigo de vista y elija # handleDeletePerson en el men desplegable de Accin . Escena Problema Constructor ( fijado en escena Constructor 1.1 beta 17 y por encima! no aparecen los mtodos En mi versin del Generador de escena (1.1 beta_11):). Tuve que ir a la raz AnchorPane (en la vista Jerarqua), eliminar la clase del controlador, pulse intro y agregar la clase de controlador de nuevo. Ahora, los mtodos aparecen en la lista desplegable. Espero que este errorser corregido pronto.
Control de errores
Si ejecuta la aplicacin en este punto, usted debe ser capaz de eliminar personas seleccionadas de la tabla. Pero lo happenes, si hace clic en el botn Eliminar si ninguna persona se ha seleccionado en la tabla? Habr un ArrayIndexOutOfBoundsException porque no poda quitar un elemento de persona en el ndice -1 . El ndice de -1 fue devuelto por getSelectedIndex () lo que significa que no haba seleccin.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Hacer caso omiso de este tipo de error no es muy agradable, por supuesto. Debemos dejar que el usuario sepa que l / ella debe seleccionar a una persona antes de eliminarlos. An mejor sera si deshabilitado el botn para que el usuario ni siquiera tiene la oportunidad de hacer algo mal. Te voy a mostrar cmo hacer el primer acercamiento aqu. Vamos a aadir un cuadro de dilogo emergente para informar al usuario. Usted tendr queagregar una biblioteca de los cuadros de dilogo: 1. Descarga los nuevos javafx-dilogos-xxxjar archivo de mi pgina GitHub . 2. Crear un lib subcarpeta en el proyecto y agregar el archivo jar en esta carpeta. 3. Agregue el archivo jar a classpath del proyecto: En Eclipse haga clic derecho en el archivo jar | Construye Ruta | Agregar a la Va de construccin . Con algunos cambios realizados en el handleDeletePerson () mtodo, podemos mostrar un cuadro de dilogo emergente cada vez que el usuario pulsa el botn de borrar, mientras que ninguna persona se ha seleccionado en la tabla:
PersonOverviewController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /** * Called when the user clicks on the delete button. */ @FXML private void handleDeletePerson() { int selectedIndex = personTable.getSelectionModel().getSelectedIndex(); if (selectedIndex >= 0) { personTable.getItems().remove(selectedIndex); } else { // Nothing selected Dialogs.showWarningDialog(mainApp.getPrimaryStage(), "Please select a person in the table.", "No Person Selected", "No Selection"); } }
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
1. Cree un nuevo archivo llamado fxml PersonEditDialog.fxml el interior del envase vista. 2. Utilice un GridPane , Label s, TextBoxe s y Button s para crear un cuadro de dilogo como el siguiente: Si no lo hace para hacer el trabajo, usted puede descargar PersonEditDialog.fxml .
/** * Dialog to edit details of a person. * * @author Marco Jakob */ public class PersonEditDialogController { @FXML private @FXML private @FXML private @FXML private @FXML private @FXML private TextField firstNameField; TextField lastNameField; TextField streetField; TextField postalCodeField; TextField cityField; TextField birthdayField;
private Stage dialogStage; private Person person; private boolean okClicked = false; /** * Initializes the controller class. This method is automatically called * after the fxml file has been loaded. */ @FXML
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 private void initialize() { } /** * Sets the stage of this dialog. * @param dialogStage */ public void setDialogStage(Stage dialogStage) { this.dialogStage = dialogStage; } /** * Sets the person to be edited in the dialog. * * @param person */ public void setPerson(Person person) { this.person = person; firstNameField.setText(person.getFirstName()); lastNameField.setText(person.getLastName()); streetField.setText(person.getStreet()); postalCodeField.setText(Integer.toString(person.getPostalCode())); cityField.setText(person.getCity()); birthdayField.setText(CalendarUtil.format(person.getBirthday())); birthdayField.setPromptText("yyyy-mm-dd"); } /** * Returns true if the user clicked OK, false otherwise. * @return */ public boolean isOkClicked() { return okClicked; } /** * Called when the user clicks ok. */ @FXML private void handleOk() { if (isInputValid()) { person.setFirstName(firstNameField.getText()); person.setLastName(lastNameField.getText()); person.setStreet(streetField.getText()); person.setPostalCode(Integer.parseInt(postalCodeField.getText())); person.setCity(cityField.getText()); person.setBirthday(CalendarUtil.parse(birthdayField.getText())); okClicked = true; dialogStage.close(); }
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 } /** * Called when the user clicks cancel. */ @FXML private void handleCancel() { dialogStage.close(); } /** * Validates the user input in the text fields. * * @return true if the input is valid */ private boolean isInputValid() { String errorMessage = ""; if (firstNameField.getText() == null || firstNameField.getText().length() == 0) { errorMessage += "No valid first name!\n"; } if (lastNameField.getText() == null || lastNameField.getText().length() == 0) { errorMessage += "No valid last name!\n"; } if (streetField.getText() == null || streetField.getText().length() == 0) { errorMessage += "No valid street!\n"; } if (postalCodeField.getText() == null || postalCodeField.getText().length() == 0) { errorMessage += "No valid postal code!\n"; } else { // try to parse the postal code into an int try { Integer.parseInt(postalCodeField.getText()); } catch (NumberFormatException e) { errorMessage += "No valid postal code (must be an integer)!\n"; } } if (cityField.getText() == null || cityField.getText().length() == 0) { errorMessage += "No valid city!\n"; } if (birthdayField.getText() == null || birthdayField.getText().length() == 0) { errorMessage += "No valid birthday!\n"; } else { if (!CalendarUtil.validString(birthdayField.getText())) { errorMessage += "No valid birthday. Use the format yyyymm-dd!\n"; }
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
} if (errorMessage.length() == 0) { return true; } else { // Show the error message Dialogs.showErrorDialog(dialogStage, errorMessage, "Please correct invalid fields", "Invalid Fields"); return false; } } }
El setPerson (...) se puede llamar de otra clase para establecer que la persona que se va a editar. Cuando el usuario hace clic en el butten OK, el handleOk () mtodo se llama. En primer lugar, algunos de validacin se hace llamando a la isInputValid () mtodo. Slo si la validacin se ha realizado correctamente, el objeto persona se llena con los datos que el usuario introduce.Esos cambios se pueden aplicar directamente a la persona objeto que se pas a setPerson (...) !
El booleano okClicked se utiliza para que la persona que llama puede determinar si el usuario hace clic en el botn Aceptar o Cancelar.
Abrir el dilogo
Agregue un mtodo para cargar y mostrar el cuadro de dilogo de edicin persona dentro de nuestro MainApp :
MainApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /** * Opens a dialog to edit details for the specified person. If the user * clicks OK, the changes are saved into the provided person object and * true is returned. * * @param person the person object to be edited * @return true if the user clicked OK, false otherwise. */ public boolean showPersonEditDialog(Person person) { try { // Load the fxml file and create a new stage for the popup FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/PersonEditDialog.fxml")); AnchorPane page = (AnchorPane) loader.load(); Stage dialogStage = new Stage(); dialogStage.setTitle("Edit Person");
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 } dialogStage.initModality(Modality.WINDOW_MODAL); dialogStage.initOwner(primaryStage); Scene scene = new Scene(page); dialogStage.setScene(scene); // Set the person into the controller PersonEditDialogController controller = loader.getController(); controller.setDialogStage(dialogStage); controller.setPerson(person); // Show the dialog and wait until the user closes it dialogStage.showAndWait(); return controller.isOkClicked(); } catch (IOException e) { // Exception gets thrown if the fxml file could not be loaded e.printStackTrace(); return false; }
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 "Please select a person in the table.", "No Person Selected", "No Selection"); } } /** * Refreshes the table. This is only necessary if an item that is already in * the table is changed. New and deleted items are refreshed automatically. * * This is a workaround because otherwise we would need to use property * bindings in the model class and add a *property() method for each * property. Maybe this will not be necessary in future versions of JavaFX * (see http://javafx-jira.kenai.com/browse/RT-22599) */ private void refreshPersonTable() { int selectedIndex = personTable.getSelectionModel().getSelectedIndex(); personTable.setItems(null); personTable.layout(); personTable.setItems(mainApp.getPersonData()); // Must set the selected index again (see http://javafxjira.kenai.com/browse/RT-26291) personTable.getSelectionModel().select(selectedIndex); }
Abra la PersonOverview.fxml archivo en el Generador de escena. Elegir los mtodos correspondientes de Accin para los botones nuevos y edicin.
Ya est!
Usted debe tener un trabajo de aplicacin de direcciones ahora. La aplicacin es capaz de aadir, editar y eliminar personas. Incluso hay validacin para los campos de texto para evitar las entradas de usuario malas. Espero que los conceptos y la estructura de esta aplicacin le ayudar a empezar a escribir su propia aplicacin JavaFX! Divirtete y permanezca atento a posibles futuros tutoriales.
Parte I - Generador de Escena Parte II - Modelo y TableView Parte III - Interactuar con el usuario Parte IV - CSS Styling Parte V - Almacenamiento de datos como XML Parte VI - Estadsticas Grfico Parte VII - Despliegue con e (fx) clipse
CSS Styling
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
En JavaFX puede estilo de la interfaz de usuario usando las Hojas de Estilo en Cascada (CSS). Esto es genial! Nunca ha sido tan fcil de personalizar la apariencia de una aplicacin Java. En este tutorial vamos a crear un DarkTheme inspirado en el diseo de Metro de Windows 8. El CSS para los botones se basa en la entrada de blog JMetro - 8 controles de Windows Metro en Java por Pedro Duque Vieira.
Skinning aplicaciones JavaFX con CSS - Tutorial de Oracle JavaFX CSS Referencia - Referencia Oficial
Esta hoja de estilo por defecto se aplica siempre a una aplicacin JavaFX. Mediante la adicin de una hoja de estilo personalizada podemos reemplazar los estilos predeterminados del caspian.css . Sugerencia: Es bueno ver el archivo CSS por defecto para ver los estilos que puede que tenga que reemplazar.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
.label { -fx-font-size: 11pt; -fx-font-family: "Segoe UI Semibold"; -fx-text-fill: white; -fx-opacity: 0.6; } .label-bright { -fx-font-size: 11pt; -fx-font-family: "Segoe UI Semibold"; -fx-text-fill: white; -fx-opacity: 1; } .label-header { -fx-font-size: 32pt; -fx-font-family: "Segoe UI Light"; -fx-text-fill: white; -fx-opacity: 1; } .table-view { -fx-base: #1d1d1d; -fx-control-inner-background: #1d1d1d; -fx-background-color: #1d1d1d; -fx-table-cell-border-color: transparent; -fx-table-header-border-color: transparent; -fx-padding: 5; } .table-view .column-header-background { -fx-background-color: transparent; } .table-view .column-header, .table-view .filler { -fx-size: 35; -fx-border-width: 0 0 1 0; -fx-border-color: transparent transparent derive(-fx-base, 80%) transparent; -fx-border-insets: 0 10 1 0; } .table-view .column-header .label { -fx-font-size: 20pt; -fx-font-family: "Segoe UI Light"; -fx-text-fill: white; -fx-alignment: center-left; -fx-opacity: 1; } .table-view:focused .table-row-cell:filled:focused:selected { -fx-background-color: -fx-focus-color; }
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
.split-pane:horizontal > * > .split-pane-divider { -fx-border-color: transparent #1d1d1d transparent #1d1d1d; -fx-background-color: transparent, derive(#1d1d1d,20%); } .split-pane { -fx-padding: 1 0 0 0; } .menu-bar { -fx-background-color: derive(#1d1d1d,20%); -fx-selection-bar: derive(-fx-background,-7%); } .menu-bar .label { -fx-font-size: 14pt; -fx-font-family: "Segoe UI Light"; -fx-text-fill: white; -fx-opacity: 0.9; } .text-field { -fx-font-size: 12pt; -fx-font-family: "Segoe UI Semibold"; }
/* * Metro style Push Button * Author: Pedro Duque Vieira * http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8controls-on-java/ */ .button { -fx-padding: 5 22 5 22; -fx-border-color: #e2e2e2; -fx-border-width: 2; -fx-background-radius: 0; -fx-background-color: #1d1d1d; -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif; -fx-font-size: 11pt; -fx-text-fill: #d8d8d8; -fx-background-insets: 0 0 0 0, 0, 1, 2; } .button:hover { -fx-background-color: #3a3a3a; } .button:pressed, .button:default:hover:pressed { -fx-background-color: white; -fx-text-fill: #1d1d1d; } .button:focused {
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 -fx-border-color: white, white; -fx-border-width: 1, 1; -fx-border-style: solid, segments(1, 1); -fx-border-radius: 0, 0; -fx-border-insets: 1 1 1 1, 0; } .button:disabled, .button:default:disabled { -fx-opacity: 0.4; -fx-background-color: #1d1d1d; -fx-text-fill: white; } .button:default { -fx-background-color: -fx-focus-color; -fx-text-fill: #ffffff; } .button:default:hover { -fx-background-color: derive(-fx-focus-color,30%); }
Ahora tenemos que conectar el CSS a nuestra escena. Podemos hacer esto mediante programacin en el cdigo Java, pero vamos a utilizar el Generador de Escena para aadirlo a nuestros ficheros fxml: Conecte CSS para RootLayout.fxml Abra el archivo RootLayout.fxml en el Generador de escena. Seleccione la raz BorderPane en la vista de Jerarqua. En Propiedades aadir el DarkTheme.css archivo como hoja de estilos. Conecte CSS para PersonEditDialog.fxml Abra el archivo PersonEditDialog.fxml en el Generador de escena. Seleccione la raz AnchorPane y elija DarkTheme.css en la ventana de propiedades como de estilo. El fondo sigue siendo blanco, por lo que aadir la clase de estilo de
fondo
a la raz AnchorPane .
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Seleccione el botn OK y seleccione Botn predeterminado en Propiedades de la vista. Esto va a cambiar su color y que ste sea el botn predeterminado cuando el enter tecla es presionada por el usuario. Conecte CSS para PersonOverview.fxml Abra el archivo PersonOverview.fxml en el Generador de escena. Seleccione la raz AnchorPane en la vista de Jerarqua. En Propiedades aadir el DarkTheme.css archivo como hoja de estilos.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Usted ya debe ver algunos cambios ahora: La tabla y los botones son de color negro. Si selecciona un botn y mira la parte CSS en la vista Propiedades, ver que ya hay una clase de estilo por defecto llamada botn .
Todos los estilos de clase . botn de caspian.css aplican a esos botones. Ya hemos redefinido (y por lo tanto anulado) algunos de esos estilos en nuestra costumbre CSS, la apariencia de los botones cambian automticamente. Puede que tenga que ajustar el tamao de los botones para que se muestre todo el texto. Seleccionar la adecuada AnchorPane que est dentro del SplitPane . Vaya a las propiedades de ver y usar el signo ms (+) para agregar una clase de
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Si hay un borde blanco alrededor de la tabla, seleccione la TableView y seleccione 0 para todos los anclajes en la vista Diseo. Ahora, la tabla debe ocupar todo el espacio de la izquierda. Etiquetas con estilo diferente En este momento, todas las etiquetas en la parte derecha tienen el mismo tamao. Ya hay algunas formas que se indican en el archivo css llamado .
etiqueta de encabezado
para el estilo an ms las etiquetas. Seleccione la persona Detalles etiqueta y aadir etiquetas de
encabezado
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Para cada etiqueta en la columna de la derecha (donde se muestran los detalles reales por persona), agregue la clase de estilo CSS etiqueta
brillante
El archivo de icono
Un lugar posible para obtener los iconos libres es Icon Buscador . He descargado un pequeo icono de la libreta de direcciones . Crear una carpeta (normal) dentro de su proyecto denominado AddressApp recursos y una subcarpeta llamada imgenes en l. Coloque el icono de su eleccin dentro de la carpeta de imgenes. Su estructura de carpetas debe ser algo como esto ahora:
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Para establecer el icono de nuestra escena aada la siguiente lnea al comienzo (...) mtodo MainApp.java
1 this.primaryStage.getIcons().add(new Image("file:resources/images/address_book_32.png"));
(...)
El conjunto inicial
MainApp.java
public void start(Stage primaryStage) { 1 this.primaryStage = primaryStage; 2 this.primaryStage.setTitle("AddressApp"); 3 // Set the application icon 4 this.primaryStage.getIcons().add(new 5 Image("file:resources/images/address_book_32.png")); 6 7 try { 8 // Load the root layout from the fxml file 9 FXMLLoader loader = new 10 FXMLLoader(MainApp.class.getResource("view/RootLayout.fxml")); 11 rootLayout = (BorderPane) loader.load(); 12 Scene scene = new Scene(rootLayout); 13 primaryStage.setScene(scene); 14 primaryStage.show(); 15 } catch (IOException e) { 16 // Exception gets thrown if the fxml file could not be loaded 17 e.printStackTrace(); 18 } 19 20 showPersonOverview(); }
Tambin puede aadir un icono a la etapa del dilogo de edicin persona, por supuesto.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
La persistencia de datos como XML Usando el JavaFX FileChooser Uso de la JavaFX Men Ahorro de la ltima ruta del archivo abierto en las preferencias del usuario
Parte I - Generador de Escena Parte II - Modelo y TableView Parte III - Interactuar con el usuario Parte IV - CSS Styling Parte V - Almacenamiento de datos como XML Parte VI - Estadsticas Grfico Parte VII - Despliegue con e (fx) clipse
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
31 32 33 34 35 36 37 } primaryStage.setTitle("AddressApp - " + file.getName()); } else { prefs.remove("filePath"); // Update the stage title primaryStage.setTitle("AddressApp"); }
Por qu XML?
Una de las maneras ms comunes para conservar los datos es el uso de una base de datos. Las bases de datos suelen contener algn tipo de datos relacionales (como tablas), mientras que los datos que necesitamos para salvar son objetos. Esto se conoce como la diferencia de impedancia objetorelacional . Es un poco de trabajo para que coincida con los objetos a las tablas de bases de datos relacionales. Hay algunos de los marcos que ayudan con el juego (por ejemplo, Hibernate , el ms popular), pero todava requiere un poco de trabajo de configurar. En nuestro modelo de datos simple es mucho ms fcil de usar XML. Vamos a utilizar una biblioteca llamada XStream . Con slo unas pocas lneas de cdigo que esto nos permitir generar XML de salida como esta:
sample.xml
1 <list> 2 <person> 3 <firstName>Hans</firstName> 4 <lastName>Muster</lastName> 5 <street>some street</street> 6 <postalCode>1234</postalCode> 7 <city>some city</city> 8 <birthday> 9 <time>1354035227734</time> 10 <timezone>Europe/Berlin</timezone> 11 </birthday> 12 </person>
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
13 <person> 14 <firstName>Anna</firstName> 15 <lastName>Best</lastName> 16 <street>some street</street> 17 <postalCode>1234</postalCode> 18 <city>some city</city> 19 <birthday> 20 <time>1354035227734</time> 21 <timezone>Europe/Berlin</timezone> 22 </birthday> 23 </person> 24 </list>
/** * Helper class for reading and writing files. */ public class FileUtil { /** * The character set. UTF-8 works good for windows, mac and Umlaute. */ private static final Charset CHARSET = Charset.forName("UTF-8"); /** * Reads the specified file and returns the content as a String. * * @param file * @return * @throws IOException thrown if an I/O error occurs opening the file
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 */ public static String readFile(File file) throws IOException { StringBuffer stringBuffer = new StringBuffer(); BufferedReader reader = Files.newBufferedReader(file.toPath(), CHARSET); String line = null; while ((line = reader.readLine()) != null) { stringBuffer.append(line); } reader.close(); return stringBuffer.toString(); } /** * Saves the content String to the specified file. * * @param content * @param file * @throws IOException thrown if an I/O error occurs opening or creating the file */ public static void saveFile(String content, File file) throws IOException { BufferedWriter writer = Files.newBufferedWriter(file.toPath(), CHARSET); writer.write(content, 0, content.length()); writer.close(); } }
Usando XStream
Para utilizar XStream necesitamos tres bibliotecas. Agregue las siguientes bibliotecas para el proyecto lib carpeta y aadirlos a la ruta de compilacin (clic derecho sobre las bibliotecas).
xstream-1.4.3.jar biblioteca principal XStream xmlpull-1.1.3.1.jar - XmlPull para detectar analizadores disponibles xpp3_min-1.1.4c.jar - Xpp3, un analizador tirn rpido Tambin puede descargar las tres bibliotecas de la pgina de descarga XStream . Haremos nuestro MainApp clase responsable de la lectura y escritura de los datos de la persona.Aadir los dos mtodos siguientes hasta el final del MainApp.java :
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
MainApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 /** * Loads person data from the specified file. The current person data will * be replaced. * * @param file */ @SuppressWarnings("unchecked") public void loadPersonDataFromFile(File file) { XStream xstream = new XStream(); xstream.alias("person", Person.class); try { String xml = FileUtil.readFile(file); ArrayList<Person> personList = (ArrayList<Person>) xstream.fromXML(xml); personData.clear(); personData.addAll(personList); setPersonFilePath(file); } catch (Exception e) { // catches ANY exception Dialogs.showErrorDialog(primaryStage, "Could not load data from file:\n" + file.getPath(), "Could not load data", "Error", e); } } /** * Saves the current person data to the specified file. * * @param file */ public void savePersonDataToFile(File file) { XStream xstream = new XStream(); xstream.alias("person", Person.class); // Convert ObservableList to a normal ArrayList ArrayList<Person> personList = new ArrayList<>(personData); String xml = xstream.toXML(personList); try { FileUtil.saveFile(xml, file); setPersonFilePath(file); } catch (Exception e) { // catches ANY exception Dialogs.showErrorDialog(primaryStage, "Could not save data to file:\n" + file.getPath(), "Could not save data", "Error", e); } }
El mtodo de almacenamiento utiliza xstream.toXML (...) para convertir la lista de Personas objetos en una representacin XML. El mtodo de
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
carga utiliza xstream.fromXML (...) para convertir los datos XML de vuelta a una lista de persona s. Si algo sale mal, un dilogo de error se presenta al usuario.
Sugerencia: Con el acelerador ajuste en propiedades que se pueden configurar teclas de acceso directo a los elementos del men.
El RootLayoutController
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Para el manejo de las acciones del men que necesitaremos una nueva clase de controlador. Crear una clase RootLayoutController dentro del paquete controlador ch.makery.address . Aadir el contenido siguiente al controlador:
(RootLayoutController.java) download
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package ch.makery.address; import java.io.File; import javafx.fxml.FXML; import javafx.scene.control.Dialogs; import javafx.stage.FileChooser; /** * The controller for the root layout. The root layout provides the basic * application layout containing a menu bar and space where other JavaFX * elements can be placed. * * @author Marco Jakob */ public class RootLayoutController { // Reference to the main application private MainApp mainApp; /** * Is called by the main application to give a reference back to itself. * * @param mainApp */ public void setMainApp(MainApp mainApp) { this.mainApp = mainApp; } /** * Creates an empty address book. */ @FXML private void handleNew() { mainApp.getPersonData().clear(); mainApp.setPersonFilePath(null); } /** * Opens a FileChooser to let the user select an address book to load. */ @FXML
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 private void handleOpen() { FileChooser fileChooser = new FileChooser(); // Set extension filter FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter( "XML files (*.xml)", "*.xml"); fileChooser.getExtensionFilters().add(extFilter); // Show save file dialog File file = fileChooser.showOpenDialog(mainApp.getPrimaryStage()); if (file != null) { mainApp.loadPersonDataFromFile(file); } } /** * Saves the file to the person file that is currently open. If there is no * open file, the "save as" dialog is shown. */ @FXML private void handleSave() { File personFile = mainApp.getPersonFilePath(); if (personFile != null) { mainApp.savePersonDataToFile(personFile); } else { handleSaveAs(); } } /** * Opens a FileChooser to let the user select a file to save to. */ @FXML private void handleSaveAs() { FileChooser fileChooser = new FileChooser(); // Set extension filter FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter( "XML files (*.xml)", "*.xml"); fileChooser.getExtensionFilters().add(extFilter); // Show save file dialog File file = fileChooser.showSaveDialog(mainApp.getPrimaryStage()); if (file != null) { // Make sure it has the correct extension if (!file.getPath().endsWith(".xml")) { file = new File(file.getPath() + ".xml"); } mainApp.savePersonDataToFile(file); } }
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
104 105 /** 106 * Opens an about dialog. 107 */ 108 @FXML 109 private void handleAbout() { 110 Dialogs.showInformationDialog(mainApp.getPrimaryStage(), 111 "Author: Marco Jakob\nWebsite: http://edu.makery.ch", "AddressApp", 112 "About"); 113 } /** * Closes the application. */ @FXML private void handleExit() { System.exit(0); } }
El controlador contiene un FXML @ mtodo para cada elemento del men. FileChooser Tome nota de los mtodos que utilizan la FileChooser clase dentro de RootLayoutController arriba. En primer lugar, un nuevo objeto de la clase FileChooser se crea. A continuacin, se aade un filtro de extensin de manera que slo los archivos que terminan en . xml se muestran. Por ltimo, el selector de archivos se muestra en la parte superior de la primera etapa. Si el usuario cierra el cuadro de dilogo sin seleccionar un archivo, nula se devuelve. De lo contrario, se obtiene el archivo seleccionado y podemos pasarlo al loadPersonDataFromFile (...) o savePersonDataToFile
(...)
Mtodo de MainApp .
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
usted no ve las opciones en Accin : Debido a un bug en el Generador de escena tiene que quitar el controlador de la raz, pulse intro y agregarlo de nuevo. Tuve que hacer esto despus de cada reinicio del Constructor escena! ( fijado en escena Constructor 1.1 beta 17 y ms arriba! )
3. Cerrar Escena Builder y golpe Refresh (F5) en la carpeta raz del proyecto. Esto har que Eclipse conscientes de los cambios que ha realizado en el Generador de escena.
MainApp.java
@Override public void start(Stage primaryStage) { this.primaryStage = primaryStage; this.primaryStage.setTitle("AddressApp"); this.primaryStage.getIcons().add(new Image("file:resources/images/address_book_32.png")); try { // Load the root layout from the fxml file FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/RootLayout.fxml")); rootLayout = (BorderPane) loader.load(); Scene scene = new Scene(rootLayout); primaryStage.setScene(scene);
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 }
// Give the controller access to the main app RootLayoutController controller = loader.getController(); controller.setMainApp(this); primaryStage.show(); } catch (IOException e) { // Exception gets thrown if the fxml file could not be loaded e.printStackTrace(); } showPersonOverview(); // Try to load last opened person file File file = getPersonFilePath(); if (file != null) { loadPersonDataFromFile(file); }
Observe los dos cambios: Las lneas que dan acceso al controlador de la aplicacin principal y las tres ltimas lneas para cargar el ltimo archivo abierto persona .
Cmo funciona?
Hacer una prueba de manejo de su solicitud, usted debe ser capaz de utilizar los mens para guardar los datos de la persona a un archivo y cargarlo de nuevo. Despus de un reinicio, debe cargar automticamente el ltimo archivo utilizado. Vamos a ver cmo funciona todo en conjunto: 1. La aplicacin se inicia con el principal (...) mtodo dentro de MainApp . 2. El constructor pblico MainApp () es llamado y aade algunos datos de muestra. 3. MainApp s comienzo (...) se llama al mtodo y se inicializa el diseo raz de RootLayout.fxml .El archivo fxml tiene la informacin acerca de qu controlador utilizar y enlaza el objeto de su RootLayoutController . 4. El MainApp recupera el RootLayoutController desde el cargador fxml y pasa una referencia a s misma al controlador. Con esta referencia el controlador ms tarde puede tener acceso a los mtodos (pblica) de MainApp .
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
5. Al final de la partida (...) mtodo que tratamos de conseguir el ltimo archivo abierto persona dePreferencias . Si las preferencias saben acerca de un archivo como XML, vamos a cargar los datos desde el archivo XML. Esto aparentemente sobrescribir los datos de la muestra del constructor.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Parte II - Modelo y TableView Parte III - Interactuar con el usuario Parte IV - CSS Styling Parte V - Almacenamiento de datos como XML Parte VI - Estadsticas Grfico Parte VII - Despliegue con e (fx) clipse
Estadsticas de cumpleaos
Todas las personas en el AddressApp celebra su cumpleaos. No sera bueno tener algunas estadsticas acerca de que nuestro pueblo celebran su cumpleaos. Vamos a utilizar un grfico de barras que contiene una barra para cada mes. Cada barra muestra cuntas personas tienen su cumpleaos en ese mes particular.
El controlador de Estadsticas
En el paquete del controlador ch.makery.address crear una clase Java llamada BirthdayStatisticsController.java .
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Primero echemos un vistazo a toda la clase del controlador antes de empezar a explicar:
Parte I - Generador de Escena Parte II - Modelo y TableView Parte III - Interactuar con el usuario Parte IV - CSS Styling
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Parte V - Almacenamiento de datos como XML Parte VI - Estadsticas Grfico Parte VII - Despliegue con e (fx) clipse
Estadsticas de cumpleaos
Todas las personas en el AddressApp celebra su cumpleaos. No sera bueno tener algunas estadsticas acerca de que nuestro pueblo celebran su cumpleaos. Vamos a utilizar un grfico de barras que contiene una barra para cada mes. Cada barra muestra cuntas personas tienen su cumpleaos en ese mes particular.
El controlador de Estadsticas
En el paquete del controlador ch.makery.address crear una clase Java llamada BirthdayStatisticsController.java . Primero echemos un vistazo a toda la clase del controlador antes de empezar a explicar:
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
El Barchar : Tiene el tipo de cadena y de Integer . La cadena se utiliza para el mes en el eje x y el nmero entero se utiliza para el nmero de personas en un mes especfico. Vamos a utilizar la referencia al BarChart establecer nuestros datos.
2. La inicializacin () mtodo rellena el eje x con una lista de todos los meses. 3. El setPersonData (...) mtodo se accede por la MainApp clase para establecer los datos de la persona. Se recorre todas las personas y cuenta los cumpleaos por mes. 4. Los createMonthDataSeries (...) mtodo toma la matriz con un nmero para cada mes y crea los datos del grfico. Por cada mes un nuevo XYChart.Data objeto se crea con el nombre del mes y el nmero de personas que tienen su cumpleaos en este mes. Cada XYChart.Data objeto representar a una de las barras en el grfico.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Vamos a utilizar el mismo mecanismo para nuestras estadsticas de cumpleaos que utilizamos para el dilogo de persona edicin : Un dilogo emergente simple que contiene. Agregue el mtodo siguiente a su MainApp clase:
MainApp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 /** * Opens a dialog to show birthday statistics. */ public void showBirthdayStatistics() { try { // Load the fxml file and create a new stage for the popup FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("view/BirthdayStatistics.fxml")); AnchorPane page = (AnchorPane) loader.load(); Stage dialogStage = new Stage(); dialogStage.setTitle("Birthday Statistics"); dialogStage.initModality(Modality.WINDOW_MODAL); dialogStage.initOwner(primaryStage); Scene scene = new Scene(page); dialogStage.setScene(scene); // Set the persons into the controller BirthdayStatisticsController controller = loader.getController(); controller.setPersonData(personData); dialogStage.show(); } catch (IOException e) { // Exception gets thrown if the fxml file could not be loaded e.printStackTrace(); } }
Todo est establecido, pero no tenemos a nadie que realmente llama la nueva showBirthdayStatistics () mtodo. Afortunadamente ya tenemos un men en RootLayout.fxml que se puede utilizar para este propsito.
http://edu.makery.ch/blog/2012/11/16/javafx-tutorial-addressapp-1/
Ahora abra el RootLayout.fxml archivo con el Generador de escena. Seleccione el Mostrar Estadsticas MenuItem y elija #
handleShowBirthdayStatistics
Recuerde: Es posible que tenga que quitar el controlador de la raz, pulse intro y configurarlo de nuevo si el mango ... no aparece mtodo. Debido a un bug en el Generador de escena ( fijado en escena Constructor 1.1 beta 17 y ms arriba! ).