JavaFX ListView自定义单元格

我试图为ListView创建自定义单元格,但是什么也没有出现...

我在使用ListView的菜单控制器中必须包含项目:

FXML(仅空白页面进行测试):

<AnchorPane fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="50.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.exalow.easymind.ui.factory.ProjectCell" />
public class MenuController extends Controller implements Initializable {
 
    private final ListView<Project> projectListView = new ListView<>();
 
    public MenuController(EasyMind api,Stage stage) {
        super(api,stage);
    }
 
    @Override
    public void initialize(URL location,ResourceBundle resources) {
 
        ObservableList<Project> observableList = FXCollections.observableArrayList();
        observableList.addAll(api.getProjects());
        projectListView.setItems(observableList);
 
        FXMLLoader loader = new FXMLLoader(getclass().getResource("/view/fxml/ProjectCell.fxml"));
 
        try {
            loader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        projectListView.setCellFactory(cellFactory -> loader.getcontroller());
    }

还有我的细胞控制器

public class ProjectCell extends ListCell<Project> implements Initializable {
 
    private Project project;
 
    @FXML
    private AnchorPane root;
 
    @FXML
    private ImageView imageView;
 
    @FXML
    private Label nameLabel;
 
    @FXML
    private Label descriptionLabel;
 
    @FXML
    private Label createDateLabel;
 
    @Override
    public void initialize(URL location,ResourceBundle resources) {
        setGraphic(root);
    }
 
    @Override
    protected void updateItem(Project item,boolean empty) {
 
        super.updateItem(item,empty);
 
        if (empty || item == null) {
            setText(null);
            setGraphic(null);
        } else {
 
            if (project.hasImage()) {
                imageView.setImage(new Image(project.getImageUrl()));
            } else imageView.setImage(new Image(project.getDefaultImage()));
 
            nameLabel.setText(item.getName());
            descriptionLabel.setText(item.getDescription());
            createDateLabel.setText(item.getcreateDate().toString());
        }
 
        this.project = item;
    }
}

我没有错误,但是打开应用程序时,ListView中没有单元格。

可复制的示例:

任何ProjectCell都已创建...

public class ProjectCellController {

    @FXML
    private AnchorPane root;

    @FXML
    private ImageView imageView;

    @FXML
    private Label nameLabel;

    @FXML
    private Label descriptionLabel;

    @FXML
    private Label createDateLabel;

    private Project project;

    public void setProject(Project project) {

        if (project.hasImage()) {
            imageView.setImage(new Image(project.getImageUrl()));
        } else imageView.setImage(new Image(project.getDefaultImage()));

        nameLabel.setText(project.getName());
        descriptionLabel.setText(project.getDescription());
        createDateLabel.setText(project.getcreateDate().toString());

        this.project = project;
    }
}
public class ProjectCell extends ListCell<Project> {

    private AnchorPane root;

    private ProjectCellController controller;

    public ProjectCell() {

        try {
            FXMLLoader loader = new FXMLLoader(getclass().getResource("/view/fxml/ProjectCell.fxml"));
            root = loader.load();
            controller = loader.getcontroller();
        } catch (IOException exc) {
            throw new RuntimeException(exc);
        }
    }

    @Override
    protected void updateItem(Project project,boolean empty) {
        if (empty || project == null) {
            setGraphic(null);
        } else {
            controller.setProject(project);
            setGraphic(root);
        }
    }
}

和FXML(基本的空白锚定窗格):

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.AnchorPane?>


<AnchorPane fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="50.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.exalow.easymind.ui.controllers.ProjectCellController" />
iCMS 回答:JavaFX ListView自定义单元格

您的代码有很多问题。

  1. 您正在为每个单元分配相同的单元实例(因为您的单元工厂每次调用都会返回相同的实例)。这违反了UI元素只能添加到场景图一次的规则。
  2. 如果在空白单元格上调用updateItem(),则将图形设置为null。在任何情况下,您都不会将图形设置回其他任何位置。因此,如果某个单元格 ever 用作一个空单元格(通常在第一次创建或显示ListView时发生这种情况),那么即使该单元格一直没有内容,即使它以后变为非空。
  3. 控制器通常不应是UI组件。该规则有一些例外情况(例如,使用custom component pattern),但这通常是一个坏主意,因为它会混淆控制器和视图。

因此,此处的策略应该是将单元工厂设置为创建新单元实例的工厂。该单元可以在构造函数中加载FXML文件(因此,每个单元都加载UI的新实例,但是每个单元仅加载一次)。在updateItem()方法中,如果单元格为空,则将图形设置为null,否则根据该项目配置控制器,并将图形设置为从FXML加载的UI。

类似的东西:

public class ProjectCellController  {
 
 
    @FXML
    private AnchorPane root;
 
    @FXML
    private ImageView imageView;
 
    @FXML
    private Label nameLabel;
 
    @FXML
    private Label descriptionLabel;
 
    @FXML
    private Label createDateLabel;
 
    public void setProject(Project project) {
        if (project.hasImage()) {
            imageView.setImage(new Image(project.getImageUrl()));
        } else imageView.setImage(new Image(project.getDefaultImage()));
 
        nameLabel.setText(project.getName());
        descriptionLabel.setText(project.getDescription());
        createDateLabel.setText(project.getCreateDate().toString());
    }
}

然后

public class ProjectCell extends ListCell<Project> {

    private AnchorPane root ;
    private ProjectCellController controller ;

    public ProjectCell() {

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/fxml/ProjectCell.fxml"));
            root = loader.load();
            controller = loader.getController();
        } catch (IOException exc) {
            // this is basically fatal,so just bail here:
            throw new RuntimeException(exc);
        }
    }

    @Override
    protected void updateItem(Project project,boolean empty) {
        super.updateItem(project,empty);
        if (empty || project == null) {
            setGraphic(null);
        } else {
            controller.setProject(project);
            setGraphic(root);
        }
    }
}

最后,相应地更改FXML文件的fx:controller属性,并设置控制器工厂:

projectListView.setCellFactory(listView -> new ProjectCell());

这是一个简化但完整的示例:

Project.java:

public class Project {
    private final String name ;
    public Project(String name) {
        this.name = name ;
    }
    public String getName() {
        return name ;
    }
}

Main.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.ListView?>
<?import javafx.geometry.Insets?>

<BorderPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="MainController">
   <center>
      <ListView fx:id="list" />
   </center>
   <padding>
      <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
   </padding>
</BorderPane>

MainController.java:

import javafx.fxml.FXML;
import javafx.scene.control.ListView;

public class MainController {

    @FXML
    private ListView<Project> list ;
    
    public void initialize() {
        for (int i = 1 ; i <= 100 ; i++) {
            list.getItems().add(new Project("Project "+i));
        }
        list.setCellFactory(lv -> new ProjectCell());
    }
}

ProjectCell.java:

import java.io.IOException;

import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.ListCell;

public class ProjectCell extends ListCell<Project> {

    private Parent root ;
    private ProjectCellController controller ;
    
    public ProjectCell() {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("ProjectCell.fxml"));
            root = loader.load();
            controller = loader.getController() ;
        } catch (IOException exc) {
            throw new RuntimeException(exc);
        }
    }
    
    @Override
    protected void updateItem(Project project,empty);
        if (empty || project==null) {
            setGraphic(null);
        } else {
            controller.setProject(project);
            setGraphic(root);
        }
    }
}

ProjectCell.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>

<VBox xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ProjectCellController">
    <children>
        <Label fx:id="nameLabel" />
    </children>
</VBox>

ProjectCellController.java:

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class ProjectCellController {

    @FXML
    private Label nameLabel ;
    
    public void setProject(Project project) {
        nameLabel.setText(project.getName());
    }
}

和主要应用程序类:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;


public class App extends Application {

    @Override
    public void start(Stage stage) throws IOException {
        Scene scene = new Scene(FXMLLoader.load(getClass().getResource("Main.fxml")),640,480);
        stage.setScene(scene);
        stage.show();
    }


    public static void main(String[] args) {
        launch();
    }

}
本文链接:https://www.f2er.com/2013100.html

大家都在问