JavaFX:键入safe TilePane/ListView with tiles

JavaFX:键入safe TilePane/ListView with tiles,javafx,Javafx,编辑: 好吧,我想我基本上解决了我自己的问题,或者至少我有了一些有效的东西,但它感觉很粗糙,而且不安全。。。我基本上只是在TilePane中添加了一些逻辑,让它做我想做的事情,但是它有很多自定义代码。不确定这是否是正确的方法,但它确实有效。。。发布我的解决方案,以防将来有人有反馈或类似问题。这样行吗 我最想知道的是,当我在TilePane中单击节点时,是否可以将节点投射到CardView?我可以用ListView做得更好吗?有没有一种方法可以用一个不同的组件来实例化最少的屏幕外节点 原件: 我正

编辑: 好吧,我想我基本上解决了我自己的问题,或者至少我有了一些有效的东西,但它感觉很粗糙,而且不安全。。。我基本上只是在TilePane中添加了一些逻辑,让它做我想做的事情,但是它有很多自定义代码。不确定这是否是正确的方法,但它确实有效。。。发布我的解决方案,以防将来有人有反馈或类似问题。这样行吗

我最想知道的是,当我在TilePane中单击节点时,是否可以将节点投射到CardView?我可以用ListView做得更好吗?有没有一种方法可以用一个不同的组件来实例化最少的屏幕外节点

原件: 我正在做一个JavaFX纸牌游戏,我想知道如何才能得到一个类型安全的TilePane,如果这有意义的话。现在我正在做游戏中的甲板建造部分。我想显示从卡片列表生成的卡片,如果可能的话,我想将它们显示为3行。我想要TilePane的布局,但需要ListView的类型安全性

ListView是类型安全的,但它的元素只能显示为列表(水平或垂直),而TilePane提供了我想要的布局,但不是类型安全的

有什么东西我都可以得到吗?我应该做一个自定义组件吗

这是一个(更完整的)最小可复制示例

甲板建筑控制器

导入javafx.beans.binding.Bindings;
导入javafx.collections.FXCollections;
导入javafx.collections.MapChangeListener;
导入javafx.collections.observemap;
导入javafx.fxml.fxml;
导入javafx.scene.Node;
导入javafx.scene.control.Label;
导入javafx.scene.input.MouseEvent;
导入javafx.scene.layout.TilePane;
导入javafx.scene.layout.VBox;
导入java.util.ArrayList;
导入java.util.HashMap;
公共类DeckBuilderControllerMRE{
@FXML TilePane可提供Cards、cardsInDeck;
//从可用卡列表映射到牌组中这些卡的数量
ObservaleMap currentDeckMap=FXCollections.ObservaleMap(新的HashMap());
//这些映射从卡数据对象映射到视图节点,这是浪费,但有效。。。
HashMap AvailableViewMap=new HashMap(),deckViewsMap=new HashMap();
公共无效初始化(){
//虚拟卡数据
ArrayList allCards=新的ArrayList();
所有卡片。添加(新卡片(“剑客”,5));
添加(新卡(“箭头人”,3));
添加(新卡(“Shabalago”,10000000));
所有卡片。添加(新卡片(“guy#4”,4));
添加(新卡(“邪恶博士”,7));
所有卡片。添加(新卡片(“一张多”、-5));
//这会将卡映射到可用的总数量,因为每张卡只允许您拥有一定数量的卡
HashMap cardQuantilities=新的HashMap();
对于(int i=0;i{
//检查我是否单击了容器而不是卡
if(event.getTarget()==availableCards)
返回;
//否则,我会跳转到容器节点CardView
Node Node=(Node)event.getTarget();
while(node.getParent()!=availableCards)
node=node.getParent();
//然后我将节点强制转换为CardView
//这是我认为可能需要修复的部分
CardView selectedView=(CardView)节点;
Card selectedCard=selectedView.Card;
//然后我更新了地图,它更新了quantityLabel
currentDeckMap.put(selectedCard,currentDeckMap.get(selectedCard)+1);
event.consume();
});
//这也会做同样的事情,但会移除它们
cardsInDeck.addEventHandler(MouseEvent.MOUSE_单击,事件->{
if(event.getTarget()==cardsInDeck)
返回;
Node Node=(Node)event.getTarget();
while(node.getParent()!=cardsInDeck)
node=node.getParent();
CardView selectedView=(CardView)节点;
Card selectedCard=selectedView.Card;
currentDeckMap.put(selectedCard,currentDeckMap.get(selectedCard)-1);
event.consume();
});
currentDeckMap.addListener((MapChangeListener)更改->{
Card Card=change.getKey();
int stillAvailable=cardQuantilities.get(card)-currentDeckMap.get(card);
如果(仍然可用==0)
availableCards.getChildren().remove(AvailableViewMap.get(card));
如果(stillAvailable==1&&!availableCards.getChildren().contains(AvailableViewMap.get(card)))
availableCards.getChildren().add(AvailableViewMap.get(卡片));
如果(currentDeckMap.get(卡)==0)
cardsInDeck.getChildren().remove(deckViewsMap.get(card));
如果(currentDeckMap.get(card)==1&&!cardsInDeck.getChildren().contains(deckViewsMap.get(card)),则为else
卡森戴克·盖奇
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="900.0" prefWidth="1300.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="DeckBuilderControllerMRE">
   <left>
      <ScrollPane hbarPolicy="NEVER" minHeight="-Infinity" minViewportHeight="200.0" minViewportWidth="400.0" minWidth="-Infinity" prefHeight="200.0" prefViewportHeight="200.0" prefViewportWidth="400.0" prefWidth="400.0" BorderPane.alignment="CENTER">
         <content>
            <TilePane fx:id="availableCards" hgap="10.0" prefColumns="3" tileAlignment="TOP_LEFT" vgap="10.0" />
         </content>
         <BorderPane.margin>
            <Insets />
         </BorderPane.margin>
      </ScrollPane>
   </left>
   <right>
      <ScrollPane hbarPolicy="NEVER" minHeight="-Infinity" minViewportHeight="200.0" minViewportWidth="400.0" minWidth="-Infinity" prefHeight="200.0" prefViewportHeight="200.0" prefViewportWidth="400.0" prefWidth="400.0" BorderPane.alignment="CENTER">
         <content>
            <TilePane fx:id="cardsInDeck" hgap="10.0" prefColumns="3" tileAlignment="TOP_LEFT" vgap="10.0" />
         </content>
         <BorderPane.margin>
            <Insets />
         </BorderPane.margin>
      </ScrollPane>
   </right>
</BorderPane>