使用FXML在JavaFX中自定义ListView
我想在javafx中创建一个自定义列表视图。这里我需要在列表单元格中绑定多个组件,如下所示 一个标签、一个文本字段、一个HBox下的一个按钮和 两个按钮、一个超链接、另一个HBox中的一个标签和 这些HBox属于一个VBox和 此VBox位于单个列表单元格下,并且 它将重复并生成一个列表视图 代码是使用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"> <
<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);
}