JavaFX自定义列表视图

JavaFX自定义列表视图,java,listview,javafx,cellrenderer,Java,Listview,Javafx,Cellrenderer,我想问一下在JavaFX中使用自定义对象创建ListView的最佳方法,我想要一个列表,每个项目如下所示: 我搜索发现大多数人都是用细胞工厂的方法来做的。还有别的办法吗?例如,使用custome fxml 这是我的fmxl档案 <?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.ListView?> <?import javafx.scene.control.Menu?>

我想问一下在JavaFX中使用自定义对象创建ListView的最佳方法,我想要一个列表,每个项目如下所示:

我搜索发现大多数人都是用细胞工厂的方法来做的。还有别的办法吗?例如,使用custome fxml

这是我的fmxl档案

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

<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="557.0" prefWidth="1012.0" style="-fx-background-color: #0288D1;" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="desktop_tasker.FXMLTaskerController">
   <children>
      <SplitPane dividerPositions="0.5" layoutX="-8.0" layoutY="35.0" prefHeight="529.0" prefWidth="1027.0" style="-fx-background-color: #EEEEEE;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="28.0">
        <items>
          <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
               <children>
                  <ListView fx:id="list_todo" onEditStart="#handleButtonAction" prefHeight="527.0" prefWidth="502.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
               </children></AnchorPane>
          <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="527.0" prefWidth="640.0">
               <children>
                  <ListView fx:id="list_done" onEditStart="#handleButtonAction" prefHeight="527.0" prefWidth="502.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
               </children></AnchorPane>
        </items>
      </SplitPane>
      <MenuBar prefHeight="30.0" prefWidth="1012.0">
        <menus>
          <Menu mnemonicParsing="false" text="File">
            <items>
              <MenuItem mnemonicParsing="false" text="Close" />
            </items>
          </Menu>
          <Menu mnemonicParsing="false" text="Edit">
            <items>
              <MenuItem mnemonicParsing="false" text="Delete" />
            </items>
          </Menu>
          <Menu mnemonicParsing="false" text="Help">
            <items>
              <MenuItem mnemonicParsing="false" text="About" />
            </items>
          </Menu>
        </menus>
      </MenuBar>
   </children>
</AnchorPane>

这是我的目标任务:

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by Usuario on 26/10/2017.
 */

public class Task implements Comparable<Task> {
    private String title;
    private String attendant;
    private String comment;
    private String description;
    private int priority;
    private String creationDate;
    private boolean state;
    private boolean visible;

    public Task(String title, String attendant, String comment, String description, int priority) {
        this.title = title;
        this.attendant = attendant;
        this.comment = comment;
        this.description = description;
        this.priority = priority;
        this.creationDate = setCreationDate();
        this.state = false;
        this.visible = true;
    }

    public Task(String title, String attendant, String comment, String description, int priority, String date, boolean state, boolean visible) {
        this.title = title;
        this.attendant = attendant;
        this.comment = comment;
        this.description = description;
        this.priority = priority;
        this.creationDate = date;
        this.state = state;
        this.visible = visible;
    }

    private static String setCreationDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = new Date();
        return sdf.format(date);
    }


    public boolean isVisible() {
        return visible;
    }

    public String getTitle() {
        return title;
    }

    public String getAttendant() {
        return attendant;
    }

    public String getComment() {
        return comment;
    }

    public String getDescription() {
        return description;
    }

    public int getPriority() {
        return priority;
    }

    public String getCreationDate() {
        return creationDate;
    }

    public boolean isState() {
        return state;
    }



    @Override
    public String toString() {
        return "Task{" +
                "title='" + title + '\'' +
                ", attendant='" + attendant + '\'' +
                ", comment='" + comment + '\'' +
                ", description='" + description + '\'' +
                ", priority=" + priority +
                ", creationDate='" + creationDate + '\'' +
                ", state=" + state +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Task task = (Task) o;

        if (priority != task.priority) return false;
        if (state != task.state) return false;
        if (title != null ? !title.equals(task.title) : task.title != null) return false;
        if (attendant != null ? !attendant.equals(task.attendant) : task.attendant != null)
            return false;
        if (comment != null ? !comment.equals(task.comment) : task.comment != null) return false;
        if (description != null ? !description.equals(task.description) : task.description != null)
            return false;
        return creationDate != null ? creationDate.equals(task.creationDate) : task.creationDate == null;
    }

    @Override
    public int hashCode() {
        int result = title != null ? title.hashCode() : 0;
        result = 31 * result + (attendant != null ? attendant.hashCode() : 0);
        result = 31 * result + (comment != null ? comment.hashCode() : 0);
        result = 31 * result + (description != null ? description.hashCode() : 0);
        result = 31 * result + priority;
        result = 31 * result + (creationDate != null ? creationDate.hashCode() : 0);
        result = 31 * result + (state ? 1 : 0);
        return result;
    }


    @Override
    public int compareTo( Task task) {
        int comparePrior = this.getPriority() - (task.getPriority());
        return comparePrior == 0 ? this.getTitle().compareTo(task.getTitle()) : comparePrior;
    }

}
import java.text.simpleDataFormat;
导入java.util.Date;
/**
*由Usuario于2017年10月26日创建。
*/
公共类任务实现了可比性{
私有字符串标题;
私人字符串助理;
私有字符串注释;
私有字符串描述;
私人优先权;
私有字符串创建日期;
私有布尔状态;
私有布尔可见;
公共任务(字符串标题、字符串助理、字符串注释、字符串描述、int优先级){
this.title=标题;
this.attendant=助理;
this.comment=注释;
this.description=描述;
优先权=优先权;
this.creationDate=setCreationDate();
this.state=false;
可见=真实;
}
公共任务(字符串标题、字符串助理、字符串注释、字符串描述、int优先级、字符串日期、布尔状态、布尔可见){
this.title=标题;
this.attendant=助理;
this.comment=注释;
this.description=描述;
优先权=优先权;
this.creationDate=日期;
this.state=状态;
可见的;可见的;
}
私有静态字符串setCreationDate(){
SimpleDataFormat sdf=新SimpleDataFormat(“yyyy-MM-dd”);
日期=新日期();
返回sdf.格式(日期);
}
公共布尔值可见(){
返回可见;
}
公共字符串getTitle(){
返回标题;
}
公共字符串getAttendant(){
回程服务员;
}
公共字符串getComment(){
回复评论;
}
公共字符串getDescription(){
返回说明;
}
public int getPriority(){
返回优先级;
}
公共字符串getCreationDate(){
还肌酐;
}
公共布尔isState(){
返回状态;
}
@凌驾
公共字符串toString(){
返回“任务{”+
“title=”+title+“\”+
“,attendant='”+attendant+'\''+
,comment=''+comment+'\''+
,description=''+description+'\''+
“,priority=“+优先级”+
“,creationDate=”“+creationDate+”\”+
“,state=“+状态+
'}';
}
@凌驾
公共布尔等于(对象o){
如果(this==o)返回true;
如果(o==null | | getClass()!=o.getClass())返回false;
任务任务=(任务)o;
if(priority!=task.priority)返回false;
如果(state!=task.state)返回false;
如果(title!=null?!title.equals(task.title):task.title!=null)返回false;
if(attendant!=null?!attendant.equals(task.attendant):task.attendant!=null)
返回false;
if(comment!=null?!comment.equals(task.comment):task.comment!=null)返回false;
if(description!=null?!description.equals(task.description):task.description!=null)
返回false;
返回creationDate!=null?creationDate.equals(task.creationDate):task.creationDate==null;
}
@凌驾
公共int hashCode(){
int result=title!=null?title.hashCode():0;
result=31*result+(attendant!=null?attendant.hashCode():0);
result=31*result+(comment!=null?comment.hashCode():0);
result=31*result+(description!=null?description.hashCode():0);
结果=31*结果+优先级;
result=31*result+(creationDate!=null?creationDate.hashCode():0);
结果=31*结果+(状态?1:0);
返回结果;
}
@凌驾
公共整数比较(任务){
int comparePrior=this.getPriority()-(task.getPriority());
返回comparePreor==0?this.getTitle().compareTo(task.getTitle()):comparePreor;
}
}

我希望这些物品看起来像单独的容器,但我没有找到任何方法。关于使用什么有什么建议吗?最好的方法是什么?

这是一个使用
FXML
创建自定义
ListCell

首先,创建一个控制器来继承
ListCell
。在该控制器的构造函数中,我们在其视图上加载
FXML
语句

public class TaskCell extends ListCell<Task> {

    @FXML
    private Label titleLabel;

    @FXML
    private Label commentLabel;

    @FXML
    private Label descriptionLabel;

    public TaskCell() {
        loadFXML();
    }

    private void loadFXML() {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("task_cell.fxml"));
            loader.setController(this);
            loader.setRoot(this);
            loader.load();
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void updateItem(Task item, boolean empty) {
        super.updateItem(item, empty);

        if(empty || item == null) {
            setText(null);
            setContentDisplay(ContentDisplay.TEXT_ONLY);
        }
        else {
            titleLabel.setText(item.getTitle());
            commentLabel.setText(item.getComment());
            descriptionLabel.setText(item.getDescription());

            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }
    }
}
我们可以在包含
ListView
控件的视图的
FXML
语句中描述它

<GridPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    <ListView fx:id="listView" GridPane.columnIndex="0" GridPane.rowIndex="0">
        <cellFactory>
            <TaskCellFactory />
        </cellFactory>
    </ListView>
</GridPane>


在第二个版本中,intellij idea
标记了错误的行,但这显然是xml解析器中的一个错误。

您没有回答自己的问题吗?你需要一个细胞工厂来做这件事。这是一个定制的细胞工厂。没有任何东西可以阻止您在FXML中定义内容。它可以工作!我的问题是无法选择列表中的项目。知道为什么吗?@Green\u Sam选择是在
updateItem()
函数中完成的(特别是在
super.updateItem(item,empty);
)。如果它不能正常工作,您可以使用
isSelected()
自己完成,并将单元格的背景更改为
public class TaskCellFactory implements Callback<ListView<Task>, ListCell<Task>> {

    @Override
    public ListCell<Task> call(ListView<Task> param) {
        return new TaskCell();
    }
}
public class Controller {

    @FXML
    private ListView<Task> listView;

    @FXML
    private void initialize() {
        listView.setCellFactory(new TaskCellFactory());
    }
}
<GridPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    <ListView fx:id="listView" GridPane.columnIndex="0" GridPane.rowIndex="0">
        <cellFactory>
            <TaskCellFactory />
        </cellFactory>
    </ListView>
</GridPane>