Personnaliser ListView dans JavaFX avec FXML
je veux faire une vue de liste personnalisée dans javafx. Ici, je dois lier plusieurs composants dans la cellule de liste comme suit, comme un label, un textfield, un bouton sous une HBox et deux boutons, un hyperlien, une étiquette dans une autre HBox et ces HBox viennent sous une VBox et cette VBox vient sous la cellule de liste simple et il va répéter et de faire une liste.
le code est
<ListView fx:id="ListView" layoutX="0" layoutY="30" prefWidth="600" prefHeight="300">
<HBox fx:id="listBox" alignment="CENTER_LEFT">
<padding><Insets top="5" bottom="5" left="5"></Insets> </padding>
<HBox alignment="CENTER_LEFT" prefWidth="170" minWidth="88">
<Label fx:id="surveyName" text="Field A" styleClass="Name"></Label>
</HBox>
<VBox styleClass="Description" prefWidth="155" minWidth="86">
<HBox>
<HBox styleClass="surveyDesIcon" prefWidth="20" prefHeight="16"></HBox>
<Label fx:id="surveyCode" text="PRW3456HJ"></Label>
</HBox>
<HBox>
<HBox styleClass="DateIcon" prefWidth="20" prefHeight="16"></HBox>
<Label fx:id="Date" text="PRW3456HJ"></Label>
</HBox>
</VBox>
<HBox fx:id="Status" prefWidth="160" minWidth="80">
<Label fx:id="StatusLabel" text="Checking Files.."/>
</HBox>
<HBox fx:id="StatusIcon1" prefWidth="50" prefHeight="50" alignment="CENTER">
<Label styleClass="StatusIcon1" prefWidth="24" prefHeight="24" alignment="CENTER"/>
</HBox>
<HBox fx:id="StatusIcon2" prefWidth="50" prefHeight="50" styleClass="StatusIconBox" alignment="CENTER">
<Hyperlink styleClass="StatusIcon2" prefWidth="24" maxHeight="24" alignment="CENTER"/>
</HBox>
</HBox>
</ListView>
3 réponses
je comprends votre question. Il y a principalement deux façons de définir des éléments dans un Listview
:
1. Créer ObservableList
et régler les éléments de l' ListView
ObservableList
(listView.setItems(observableList)
).
2.setCellFactory()
méthode de l' ListView
classe.
Vous préférez utiliser le setCellFactory()
la méthode, parce que cette approche simplifie le processus ainsi que cela aide à séparer la logique d'affaires et L'UI (FXML).
Voici une explication plus détaillée:
1. créer un nouveau fichier FXML avec le nom listview.fxml
contenir le ListView
, et réglez l'option ListViewController
classe de contrôleur:
Fichier: listview.fxml:
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.ListView?>
<?import demo.ListViewController?>
<GridPane xmlns:fx="http://javafx.com/fxml" alignment="CENTER">
<ListView fx:id="listView"/>
</GridPane>
2. Créer le contrôleur et le nom ListViewController
.
Le contrôleur peut charger listview.fxml
classez et accédez au listview
.
Fichier: ListViewController.java:
package demo;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.util.Callback;
import java.io.IOException;
import java.util.Set;
public class ListViewController
{
@FXML
private ListView listView;
private Set<String> stringSet;
ObservableList observableList = FXCollections.observableArrayList();
public ListViewController()
{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/listview.fxml"));
fxmlLoader.setController(this);
try
{
Parent parent = (Parent)fxmlLoader.load();
Scene scene = new Scene(parent, 400.0 ,500.0);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public void setListView()
{
stringSet.add("String 1");
stringSet.add("String 2");
stringSet.add("String 3");
stringSet.add("String 4");
observableList.setAll(stringSet);
listView.setItems(observableList);
listView.setCellFactory(new Callback<ListView<String>, javafx.scene.control.ListCell<String>>()
{
@Override
public ListCell<String> call(ListView<String> listView)
{
return new ListViewCell();
}
});
}
}
3. vous devez d'Abord définir la valeur de l' ObservableList
. C'est très important.
Ensuite, définissez les éléments de la liste en utilisant le ObservableList
et l'appel de l' setCellFactory()
méthode ListView
. Dans l'exemple donné, je prends juste le String
valeurs les ajouter à l' String
set (le Set<String> stringSet
).
4. quand le setCellFactory()
la méthode est appelée sur le ListView
, il sera de retour l' ListCell
. Donc, par souci de simplicité, j'ai ajouté une classe qui étend le ListCell
et setGraphic()
la méthode est présente pour le ListCell()
et régler les éléments de l' ListCell
.
Fichier: ListViewCell.java:
package demo;
import javafx.scene.control.ListCell;
public class ListViewCell extends ListCell<String>
{
@Override
public void updateItem(String string, boolean empty)
{
super.updateItem(string,empty);
if(string != null)
{
Data data = new Data();
data.setInfo(string);
setGraphic(data.getBox());
}
}
}
5. je viens d'ajouter une classe qui va charger le listCellItem.fxml
et retour le HBox
qui contiendra les autres composants, comme les enfants.
HBox
est défini à ListCell
.
Fichier: listCellItem.fxml:
<?import demo.Data?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Label?>
<HBox xmlns:fx="http://javafx.com/fxml" fx:id="hBox">
<children>
<Label fx:id="label1"/>
<Label fx:id="label2"/>
</children>
</HBox>
Fichier: Données.java:
package demo;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import java.io.IOException;
public class Data
{
@FXML
private HBox hBox;
@FXML
private Label label1;
@FXML
private Label label2;
public Data()
{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/listCellItem.fxml"));
fxmlLoader.setController(this);
try
{
fxmlLoader.load();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
public void setInfo(String string)
{
label1.setText(string);
label2.setText(string);
}
public HBox getBox()
{
return hBox;
}
}
vous pouvez utiliser setCellFactory()
méthode pour séparer les choses qui sont logiques d'affaires et FXML.
J'espère que c'est utile.
L'exemple ci-dessus par @ Anvay a besoin de quelques retouches pour fonctionner. Ce sont les choses simples à définir sur la piste.
- le ListViewController doit être exécuté sur le thread D'application JavaFX.
- vous pouvez seulement appeler les éléments injectés @FXML de la JavaFX initialiser ()
- Besoin d'appeler setListView()
- Le stringSet dans l'exemple doit être alloué à un nouveau avant d'appeler setListView ().
le ListViewController ci-dessous fonctionne avec ces changements. J'ai changé "stringSet" pour une liste, "stringList". Le contrôleur est à peu près le contrôleur d'échantillon fourni par Scene Builder 2
public class ListViewController
{
@FXML private ResourceBundle resources;
@FXML private URL location;
@FXML private ListView listView;
private List<String> stringList = new ArrayList<>(5);
private ObservableList observableList = FXCollections.observableArrayList();
public void setListView(){
stringList.add("String 1");
stringList.add("String 2");
stringList.add("String 3");
stringList.add("String 4");
observableList.setAll(stringList);
listView.setItems(observableList);
listView.setCellFactory(
new Callback<ListView<String>, javafx.scene.control.ListCell<String>>() {
@Override
public ListCell<String> call(ListView<String> listView) {
return new ListViewCell();
}
});
}
@FXML
void initialize() {
assert listView != null : "fx:id=\"listView\" was not injected: check your FXML file 'CustomList.fxml'.";
setListView();
}
}//ListViewController
la plate-forme JavaFX doit être lancée dans la méthode main() à partir d'une Application JavaFX. Netbeans fournit de manière conviviale la plupart de cette structure à partir de L'application JavaFX de Maven modèle.
public class MainApp extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/CustomList.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add("/styles/Styles.css");
stage.setTitle("CustomList");
stage.setScene(scene);
stage.show();
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
*
* @param args the command line arguments
**/
public static void main(String[] args) {
launch(args);
}
}
La réponse par Anvay pour une raison quelconque n'a pas fonctionné pour moi, ce que j'avais à faire c'était juste quelques très légères modifications:
- supprimer l'énoncé des données d'importation de listCellItem.fxml
- comme l'indique le commentaire sous le post dans les données.java mettre hBox = fmxlLoader.charger()
j'ai eu aussi une classe principale (intellij généré automatiquement).
public class MainMain extends Application { @Override public void start(Stage primaryStage) throws Exception{ FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MainController.fxml")); try { Parent root = fxmlLoader.load(); Scene scene = new Scene(root); primaryStage.setScene(scene); primaryStage.setTitle("Title"); primaryStage.show(); } catch (IOException e) { throw new RuntimeException(e); } } public static void main(String[] args) { launch(args); }
je sais que c'est probablement évident pour la plupart des experts ici, mais ces questions j'ai été perplexe pendant des heures pendant que je déboguais.