使用Fxml,我的主屏幕上有一个ListView。
然后我做了一个单独的Fxml。这被称为卡片并显示金融股票信息(股票代码和当前价格有2个标签)
我如何创建卡的多个实例,以便它们各自具有不同的股票名称和价格,并且价格可以更新?
public ListView searchList;
public Button searchButton;
@FXML
public void handleSearchButton(ActionEvent event) throws IOException {
loadFxml();
}
public void loadFxml () throws IOException {
Pane newLoadedPane = FXMLLoader.load(getClass().getResource("card.fxml"));
searchList.getItems().add(newLoadedPane);
}
目前,该代码会将卡的硬编码版本添加到ListView。而且我相信它们都是一样的,所以如果我要更新文本,它们都会更新。
答案 0 :(得分:2)
要创建FXML定义的UI组件的多个实例,只需多次加载FXML文件即可。如果希望每个数据都有不同的数据,请在控制器中定义方法以更改数据。那么你基本上可以做到
for (int i = 0 ; i < numberOfStocks ; i++) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("card.fxml"));
Pane stockView = loader.load();
StockController controller = loader.getController();
controller.setXXX(...);
// ...
}
我强烈建议不要使用UI节点填充ListView
,如问题中的代码所示。 UI元素是非常昂贵的对象(它们有数百个属性,并且受CSS支持,可能需要解析等)。您所代表的数据非常简单:一个字符串和一个代表股票代码和价格的双精度数据。 ListView
旨在高效,因为它只为可见数据创建UI元素,重用这些元素,例如,用户滚动它们。因此,您的ListView
应仅在其支持列表中使用数据,而不是UI元素。
因此,创建一个简单的类来表示股票:
public class Stock {
private final String symbol ; // doesn't change
private final DoubleProperty price = new SimpleDoubleProperty() ; // mutable and observable
public Stock(String symbol, double price) {
this.symbol = symbol ;
setPrice(price);
}
public DoubleProperty priceProperty() {
return price ;
}
public final double getPrice() {
return priceProperty().get();
}
public final void setPrice(double price) {
priceProperty().set(price);
}
public String getSymbol() {
return symbol ;
}
}
此Stock
类使用JavaFX properties,以便以后轻松绑定它们(因此,如果价格发生变化,UI可以自动更新)。
现在您可以定义一个简单的FXML:
<!-- imports etc -->
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.StockController"/>
<Label fx:id="symbolLabel"/>
<Label fx:id="priceLabel" />
</VBox>
带有控制器,可以实现标签与正在显示的库存的绑定:
public class StockController {
private Stock stock ;
@FXML
private Label symbolLabel ;
@FXML
private Label priceLabel ;
public void setStock(Stock stock) {
this.stock = stock ;
priceLabel.textProperty().unbind();
if (stock == null) {
symbolLabel.setText(null);
priceLabel.setText(null);
} else {
symbolLabel.setText(stock.getSymbol());
priceLabel.textProperty().bind(stock.priceProperty().asString("Price: $%.2f"));
}
}
}
现在您可以使用FXML创建ListView<Stock>
并使用其cell factory显示每个股票:
public class MainController {
@FXML
private ListView<Stock> searchList ;
public void initialize() {
searchList.setCellFactory(lv -> new StockListCell());
}
}
public class StockListCell extends ListCell<Stock> {
private final Pane stockView ;
private final StockController stockController ;
public StockListCell() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("card.fxml"));
stockView = loader.load();
stockController = loader.getController();
setGraphic(stockView);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} catch (IOException exc) {
// IOException here is fatal:
throw new UncheckedIOException(exc);
}
}
@Override
protected void updateItem(Stock item, boolean empty) {
super.updateItem(item, empty);
stockController.setStock(item);
}
}
请注意,ListView
不会创建多个StockListCell
(每个可见单元格只有一个),因此可以执行相当繁重的工作(例如加载FXML)构造函数。相比之下,updateItem(...)
方法可能会被频繁调用(例如,当用户滚动时),并且应该做最少的工作。在这里,我们只更新我们的UI显示的库存,这实际上只是更改了几个标签的文本。
最后,您可以按照预期使用Stock
填充列表视图:
for (int i = 0 ; i < numberOfStocks ; i++) {
String symbol = "Stock "+i ;
double price = 1000*Math.random();
Stock stock = new Stock(symbol, price) ;
searchList.getItems().add(stock);
}