使用FXML在JavaFX中自定义ListView

使用FXML在JavaFX中自定义ListView,javafx,fxml,Javafx,Fxml,我想在javafx中创建一个自定义列表视图。这里我需要在列表单元格中绑定多个组件,如下所示 一个标签、一个文本字段、一个HBox下的一个按钮和 两个按钮、一个超链接、另一个HBox中的一个标签和 这些HBox属于一个VBox和 此VBox位于单个列表单元格下,并且 它将重复并生成一个列表视图 代码是 <ListView fx:id="ListView" layoutX="0" layoutY="30" prefWidth="600" prefHeight="300"> <

我想在javafx中创建一个自定义列表视图。这里我需要在列表单元格中绑定多个组件,如下所示 一个标签、一个文本字段、一个HBox下的一个按钮和 两个按钮、一个超链接、另一个HBox中的一个标签和 这些HBox属于一个VBox和 此VBox位于单个列表单元格下,并且 它将重复并生成一个列表视图

代码是

<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>

我理解你的问题。在
列表视图中设置项目的方法主要有两种:

1.创建
可观察列表
,并使用
可观察列表
设置
列表视图
的项目(
列表视图.setItems(可观察列表)

2.使用
ListView
类的
setCellFactory()
方法

您更愿意使用
setCellFactory()
方法,因为这种方法简化了流程,并且有助于分离业务逻辑和UI(FXML)


这里有一个更详细的解释:


1。创建一个名为
listview.FXML
的新FXML文件,以包含
listview
,并将
ListViewController
类设置为其控制器:

文件:listview.fxml:


3。首先需要设置
可观察列表的值这非常重要。
然后,使用
observeList
设置列表项,并调用
ListView
上的
setCellFactory()
方法。在给定的示例中,我只需获取
字符串
值,然后将它们添加到
字符串
集合(即
集合字符串集


4.
ListView
上调用
setCellFactory()
方法时,它将返回
ListCell
。因此,为了简单起见,我添加了一个类来扩展
ListCell
,并且
setGraphic()
方法用于
ListCell()
,并将设置
ListCell
的项

文件:ListViewCell.java:

文件:Data.java:


通过这种方式,您可以使用
setCellFactory()
方法来分离业务逻辑和FXML


希望这会有所帮助。

以上Anvay的例子需要一些调整才能奏效。这些都是要走上正轨的简单事情

  • ListViewController需要在JavaFX应用程序线程上运行
  • 只能从JavaFXinitialize()方法调用注入的@FXML元素
  • 需要调用setListView()
  • 在调用setListView()之前,需要为示例中的stringSet分配一个新的
  • 下面的ListViewController可以处理这些更改。我将“stringSet”更改为列表“stringList”。该控制器几乎是由场景生成器提供的示例控制器

     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
    

    Anvay出于某种原因给出的答案对我不起作用,我要做的只是一些非常小的调整:

  • 从listCellItem.fxml中删除导入数据语句
  • 正如Data.java put hBox=fmxlLoader.load()中post下面的注释所述
  • 我还有一个主类(intellij自动生成)


  • 我知道这对这里的大多数专家来说是显而易见的,但在我调试时,这些问题困扰了我好几个小时。

    您是否尝试过cell factory for listview?请看。这个答案最适合在MVC上设计的javafx应用程序。嘿,谢谢Anvay,我期待的组件与您在这里提到的完全相同。多谢了,真的很管用。尽管在listcell类上使用updateItem有问题。您不应该每次调用该方法时都“膨胀”FXML。考虑在ListCype的构造函数中创建数据对象,并仅在UpDeTeI目方法上更新其内容。(仅膨胀一次)如何在运行时在自定义listview中添加新项??我猜
    fxmloader.load()
    应替换为
    hBox=fxmloader.load()
    
    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();
                }
            });
        }
    }
    
    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());
            }
        }
    }
    
     <?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>
    
    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;
        }
    }
    
     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
    
    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);
        }
    }
    
    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);
    }