javafx - Agregar un componente personalizado a SceneBuilder 2.0
javafx-8 (2)
Tengo la necesidad de tener un oyente de selección y un método de selección en un panel para poder monitorear y presentar un resaltado cuando se hace clic en un nodo.
Hice lo siguiente:
public class PaneWithSelectionListener extends Pane {
private ObjectProperty<Annotation> selectedAnnotation = new SimpleObjectProperty<>();
public PaneWithSelectionListener() {
super();
selectedAnnotation.addListener((obs, oldAnno, newAnno) -> {
if (oldAnno != null) {
oldAnno.setStyle("");
}
if (newAnno != null) {
newAnno.setStyle("-fx-border-color: blue;-fx-border-insets: 5;-fx-border-width: 1;-fx-border-style: dashed;");
}
});
setOnMouseClicked(e->selectAnnotation(null));
}
public void selectAnnotation(Annotation ann){
selectedAnnotation.set(ann);
}
}
Y esto funciona muy bien, sin embargo, ya no puedo trabajar con SceneBuilder ya que mi FXML hace referencia a este
PaneWithSelectionListener
lugar de
Pane
.
No estoy seguro de cómo obtener mi panel personalizado en SceneBuilder.
He analizado otras preguntas y todas son una combinación de FXML y Controladores, donde esto es solo un
Pane
.
¿Alguien sabe de una manera de hacer esto, o tal vez cambiar el
Pane
por un
PaneWithSelectionListener
en el momento de la inicialización?
Gracias
Creé un cuadro combinado CustomCB que es del tipo un objeto de usuario.
En mi caso, he usado
<APerson>
como userObject.
Todo el proyecto y el PROBADOR están aquí.
El primero es CustomCB, los componentes y el archivo JAR generado a partir de este código se agregan a la Biblioteca.
Esto se puede cargar en SCENE BUILDER.
A partir de entonces está disponible para el diseño de la escena.
Entonces, por supuesto, tiene un probador CustomCB2, que también puede usar un FXML en lugar de la forma en que lo hice.
De hecho, quiero que los elementos que comienzan con el texto que escribo en el cuadro combinado aparezcan en la lista. Pero no sé cómo hacerlo. Porque el PRIMER NOMBRE o el APELLIDO de la clase PERSON pueden comenzar con ''Pe''. Si encuentro una solución, la publicaré aquí.
Este es el componente personalizado.
package customCB;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
/**
*
* @author Hornigold Arthur
*/
public class APerson {
private final StringProperty firstName;
private final StringProperty lastName;
private final IntegerProperty familyID;
private final IntegerProperty personID;
public APerson() {
this(null, null, 0,0);
}
/**
* Constructor with some initial data.
*
* @param familyID
* @param familyName
*/
public APerson (String firstName, String lastName, int familyID, int personID) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.familyID = new SimpleIntegerProperty(familyID);
this.personID = new SimpleIntegerProperty(personID);
}
public int getFamilyID() {
return familyID.get();
}
public void setFamilyID(int FamilyID) {
this.familyID.set(FamilyID);
}
public IntegerProperty familyIDProperty() {
return familyID;
}
public int getPersonID() {
return personID.get();
}
public void setPersonID(int PersonID) {
this.personID.set(PersonID);
}
public IntegerProperty personIDProperty() {
return personID;
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String FirstName) {
this.firstName.set(FirstName);
}
public StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String LastName) {
this.lastName.set(LastName);
}
public StringProperty lastNameProperty() {
return lastName;
}
public String toString() {
String name = getFirstName() + " " + getLastName()+ " [" + getFamilyID() +"]";
return name;
}
}
Este es el FXML para el componente personalizado.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.layout.VBox?>
<fx:root stylesheets="@application.css" type="javafx.scene.layout.VBox" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1">
<ComboBox fx:id="myCustomCombo" editable="true" onAction="#cbOnAction" prefWidth="300.0" style="-fx-background-color: white;" />
</fx:root>
Este es el controlador para este FXML pero no lo mencione en el archivo FXML. Lanza error.
package customCB;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import org.controlsfx.control.textfield.TextFields;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
public class CustomComboController extends VBox{
@FXML
private ResourceBundle resources;
@FXML
private URL location;
@FXML
private ComboBox<APerson> myCustomCombo;
@FXML
void cbOnAction(ActionEvent event) {
}
@FXML
void initialize() {
assert myCustomCombo != null : "fx:id=/"myCustomCombo/" was not injected: check your FXML file ''CustomLvFXML.fxml''.";
}
public CustomComboController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("customCombo.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void setCBValues(javafx.collections.ObservableList<APerson> values) {
myCustomCombo.setItems(values);
myCustomCombo.setEditable(true);
TextFields.bindAutoCompletion(myCustomCombo.getEditor(), myCustomCombo.getItems());
}
}
Descargue controlesfx-8.40.12.jar de WEB e inclúyalo en la RUTA DE CONSTRUCCIÓN como biblioteca.
Ahora cree un archivo jar para este proyecto. "CustomCB.jar".
Este archivo JAR debe incluirse como control personalizado en Scene Builder. Yo uso la versión 10.0.
Ahora que es parte del generador de escenas, puede usar este componente en el diseño, a menos que pueda hacerlo como lo hice en mi CÓDIGO DE PRUEBA. Debe incluir "CustomCB.jar" como parte de la biblioteca para compilar.
Este es el código para el probador.
package customCB2;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
public class Main extends Application {
static private javafx.collections.ObservableList<APerson> fathers = javafx.collections.FXCollections.observableArrayList();
static private javafx.collections.ObservableList<APerson> mothers = javafx.collections.FXCollections.observableArrayList();
@Override
public void start(Stage stage) throws Exception {
CustomComboController customControl2 = new CustomComboController();
CustomComboController customControl3 = new CustomComboController();
loadFathers();
loadMothers();
customControl2.setCBValues(fathers);
customControl3.setCBValues(mothers);
VBox root = new VBox();
root.getChildren().addAll(customControl2, customControl3);
stage.setScene(new Scene(root));
stage.setTitle("Custom Control Combo box");
stage.setWidth(300);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
private void loadFathers() {
fathers.clear();
fathers.add(new APerson("Hornigold","Arthur",1,63));
fathers.add(new APerson("Andrews","Sundareson",2,60));
fathers.add(new APerson("Christopher","Easweradoss",3,57));
fathers.add(new APerson("Arthur","Kennedy",4,55));
}
private void loadMothers() {
mothers.clear();
mothers.add(new APerson("Victoria","Arthur",1,95));
mothers.add(new APerson("Eliza", "Daniel",1,60));
mothers.add(new APerson("Nesammal", "Rivington",2,57));
mothers.add(new APerson("Ratnammal","Andews",1,55));
}
}
Necesita muchas mejoras. Si alguien puede improvisar, agréguelo aquí.
Si el problema es solo hacer que su clase personalizada esté disponible en SceneBuilder, puede hacerlo con los siguientes pasos:
-
Agrupe su clase personalizada (y cualquier clase de soporte, como
Annotation
) como un archivo jar - En SceneBuilder, active el botón desplegable junto a "Biblioteca" en la parte superior del panel izquierdo:
- Elija "Importar archivo JAR / FXML ..."
- Seleccione el archivo Jar creado desde el paso 1
-
Asegúrese de que la clase a la que necesita acceder en SceneBuilder (
PaneWithSelectionListener
) esté marcada - Presione "Importar componente"
-
PaneWithSelectionListener
ahora aparecerá en SceneBuilder en "Personalizado" en el panel izquierdo:
Notará que el menú desplegable en SceneBuilder tiene una opción de "Carpeta de biblioteca personalizada", desde la cual puede abrir la carpeta donde se almacenan los archivos jar. Para una opción rápida, puede simplemente copiar archivos jar a esta carpeta y (después de un breve retraso), las clases contenidas aparecerán en la lista "Personalizada".