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>
33
demandé sur Syon 2013-10-25 15:01:41

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' ListViewObservableList (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.

72
répondu Anvay 2015-04-03 20:50:43

L'exemple ci-dessus par @ Anvay a besoin de quelques retouches pour fonctionner. Ce sont les choses simples à définir sur la piste.

  1. le ListViewController doit être exécuté sur le thread D'application JavaFX.
  2. vous pouvez seulement appeler les éléments injectés @FXML de la JavaFX initialiser ()
  3. Besoin d'appeler setListView()
  4. 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);
    }
}
4
répondu will 2014-12-17 01:29:38

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:

  1. supprimer l'énoncé des données d'importation de listCellItem.fxml
  2. comme l'indique le commentaire sous le post dans les données.java mettre hBox = fmxlLoader.charger()
  3. 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.

1
répondu Velo 2018-07-04 10:46:39