Je veux créer une vue de liste personnalisée dans javafx. Ici, je dois lier plusieurs composants dans la cellule de la liste comme suit, comme une étiquette, un champ de texte, un bouton sous une HBox et deux boutons, un hyperlien, une étiquette dans une autre HBox et ces HBox relèvent d'une VBox et cette VBox relève de la cellule de liste unique et il se répétera et fera une vue de 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>
Je comprends ta question. Il existe principalement deux façons de définir des éléments dans un Listview
:
1. Créez le ObservableList
et définissez les éléments du ListView
avec le ObservableList
(listView.setItems(observableList)
).
2. Utilisez la méthode setCellFactory()
de la classe ListView
.
Vous préféreriez utiliser la méthode setCellFactory()
, car cette approche simplifie le processus et permet de séparer la logique métier et l'interface utilisateur (FXML).
Voici une explication plus détaillée:
1. Créez un nouveau fichier FXML avec le nom listview.fxml
Pour contenir la ListView
, et définissez la classe ListViewController
comme 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éez le contrôleur et nommez-le ListViewController
.
Le contrôleur peut charger le fichier listview.fxml
Et accéder 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();
}
});
}
}
. Vous devez d'abord définir la valeur de ObservableList
. C'est très important.
Ensuite, définissez les éléments de la liste à l'aide de ObservableList
et appelez la méthode setCellFactory()
sur ListView
. Dans l'exemple donné, je prends simplement les valeurs String
et les ajoute à l'ensemble String
(le Set<String> stringSet
).
4. Lorsque la méthode setCellFactory()
est appelée sur le ListView
, elle renverra le ListCell
. Donc, par souci de simplicité, j'ai ajouté une classe qui étend la ListCell
, et la méthode setGraphic()
est présente pour la ListCell()
et définira les éléments de la 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 chargera le listCellItem.fxml
Et renverra le HBox
, qui contiendra les autres composants en tant qu'enfants.
Le HBox
est alors défini sur le 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: Data.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;
}
}
De cette façon, vous pouvez utiliser la méthode setCellFactory()
pour séparer les éléments qui sont la logique métier et FXML.
J'espère que cela vous sera utile.
L'exemple ci-dessus par @ Anvay a besoin de quelques ajustements pour fonctionner. Ce sont des choses simples à mettre sur la bonne voie.
Le ListViewController ci-dessous fonctionne avec ces modifications. J'ai changé " stringSet " en une liste, " stringList ". Le contrôleur est à peu près l'exemple de contrôleur 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 démarrée dans la méthode main () à partir d'une application JavaFX. Netbeans fournit facilement la plupart de cette structure à partir du modèle d'application Maven JavaFX.
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 d'Anvay pour une raison quelconque n'a pas fonctionné pour moi, ce que je devais faire pour y remédier n'était que de très petits ajustements:
J'avais aussi une classe principale (intellij générée 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'était probablement évident pour la plupart des experts ici, mais ces problèmes m'ont perplexe pendant des heures pendant que je déboguais.