如何在JavaFX中实现独立单元?

我正在努力实现类似于剧院,电影院等座位选择以及他们的不同意见。

使用此代码:

int[] rowsColumns = getRowsNColumns(); // [0] = rows : [1] = columns TableColumn [] tableColumns = new TableColumn[rowsColumns[1]]; Callback cellFactory = new Callback() { @Override public TableCell call(TableColumn p) { TableCell cell = new DisponibilityCell(); cell.addEventFilter(MouseEvent.MOUSE_CLICKED, new EventHandler()); return cell; } }; for (int i = 0; i < rowsColumns[1]; i++) { tableColumns[i] = new TableColumn(String.valueOf(i+1)); tableColumns[i].setPrefWidth((table.getPrefWidth()-15)/rowsColumns[1]); tableColumns[i].setCellValueFactory(new PropertyValueFactory("disponibility")); tableColumns[i].setCellFactory(cellFactory); tableColumns[i].setSortable(false); } table.getColumns().addAll(tableColumns); List list = new ArrayList(); for (int i = 0; i < rowsColumns[0]; i++) { list.add(new MyObject(i,true)); } table.getItems().addAll(list); table.getSelectionModel().setCellSelectionEnabled(true); 

我能够得到这个,这是我想要的视觉效果(没有样式)。 示例图片

问题是它实际上是为第一列生成行,而另一个只是值的副本。

我想我理解这一点,但不知道如何实际解决。 如果我理解正确,它会考虑每一行的一个对象,并在所有列中显示对象属性( disponibility ),因为它们都使用相同的get。

我希望每个对象都由一个单元格表示,而不是一行。 来自所有行的所有单元格都具有相同的属性,即座位的disponibility性,但每个单元格应该是一个独立的对象。

使用TableView工作解决方案可能是这样的:

首先,我们需要在MyObject保存给定行的每一列的信息。 为此,我们使用带有列的所有布尔属性的ObservableList

 class MyObject { public MyObject(int tam, boolean disponibility){ cols = FXCollections.observableArrayList(); IntStream.range(0, tam).boxed() .forEach(i->cols.add(new SimpleBooleanProperty(disponibility))); } private final ObservableList cols; public void setColDisponibility(int col, boolean disponibility){ cols.get(col).set(disponibility); } public boolean getColDisponibility(int col){ return cols.get(col).get(); } public BooleanProperty colDisponibilityProperty(int col){ return cols.get(col); } } 

现在我们将基于CheckBox定义我们的自定义单元DisponibilityCell以简化。 通过调用setColDisponibility() ,此框上的监听器将帮助我们保持模型的同步。

 class DisponibilityCell extends TableCell { private final CheckBox box = new CheckBox(); public DisponibilityCell(int col){ box.setOnAction(e -> { getTableView().getItems().get(getIndex()).setColDisponibility(col, box.isSelected()); }); } @Override protected void updateItem(Boolean item, boolean empty) { super.updateItem(item, empty); if(item!=null && !empty){ box.setSelected(item); setGraphic(box); } else { setText(null); setGraphic(null); } } } 

最后,我们可以创建表。 首先,我们提供所有数据,设置为每个单元格为真。 然后我们创建列。 对于每一列,我们设置其id以跟踪列数。 我们提供基于colDisponibilityProperty(int col)属性的单元格值工厂,以及基于DisponibilityCell的单元工厂。

 @Override public void start(Stage primaryStage) { TableView table = new TableView<>(); table.setPrefSize(800, 600); int[] rowsColumns = new int[]{10,20}; // [0] = rows : [1] = columns ObservableList list = FXCollections.observableArrayList(); for (int i = 0; i < rowsColumns[0]; i++) { list.add(new MyObject(rowsColumns[1],true)); } List> tableColumns = new ArrayList<>(rowsColumns[1]); IntStream.range(0, rowsColumns[1]).boxed().forEach(i-> { TableColumn tableColumn = new TableColumn<>(String.valueOf(i+1)); tableColumn.setId(String.valueOf(i)); tableColumn.setPrefWidth((table.getPrefWidth()-15)/rowsColumns[1]); tableColumn.setCellValueFactory(param -> { int col=Integer.parseInt(param.getTableColumn().getId()); return param.getValue().colDisponibilityProperty(col); }); tableColumn.setCellFactory(param -> new DisponibilityCell(Integer.parseInt(param.getId()))); tableColumn.setSortable(false); tableColumns.add(tableColumn); }); table.getColumns().addAll(tableColumns); table.getItems().addAll(list); table.getSelectionModel().setCellSelectionEnabled(true); table.setEditable(true); Scene scene = new Scene(table, 800, 600); primaryStage.setScene(scene); primaryStage.show(); } 

请注意,您可以随时访问更新的模型。 例如,您可以根据某个按钮点击打印它:

 button.setOnMouseClicked(e->{ table.getItems().forEach(r->{ IntStream.range(0, rowsColumns[1]).boxed() .forEach(i->System.out.print(" "+(r.getColDisponibility(i)?1:0))); System.out.println(""); }); }); 

我不会使用TableView,它会将座位布局强制执行严格的行/列布局。 剧院或其他地方的座位大多不同。 所以我会根据剧院规范建立自己的座位布局,例如:

 public class Seats extends Application { String theater1 = "20x__16x\n.20x__16x\n__18x__14x\n.20x__16x\n20x__16x\n.20x__16x\n20x__16x\n"; String theater2 = "11x_10x_11x\n11x_10x_11x\n11x_10x_11x\n\n11x_10x_11x\n11x_10x_11x\n11x_10x_11x\n"; static class Seat extends Group { Color freeColor = Color.rgb(30, 250, 40); Color reservedColor = Color.rgb(170, 40, 40); BooleanProperty iamReserved = new SimpleBooleanProperty(false); int myNo; public Seat(int no) { myNo = no; Circle pillow = new Circle(12); pillow.setFill(freeColor); pillow.setStrokeWidth(1); pillow.setStroke(Color.rgb(30, 40, 40)); getChildren().add(pillow); Text lable = new Text(""+no); lable.setFont(lable.getFont().font(7)); lable.setTextAlignment(TextAlignment.CENTER); lable.setTextOrigin(VPos.CENTER); lable.setLayoutX(-lable.getLayoutBounds().getWidth()/2); getChildren().add(lable); iamReserved.addListener((e, o, n) -> { pillow.setFill(n ? reservedColor : freeColor); }); setOnMouseClicked(m -> { iamReserved.set(!iamReserved.get()); }); } static double width() { return 26; } static double height() { return 36; } } Pane theater1(Pane pane, String theater) { double x = 20; double y = 40; int no = 1; for (String row : theater.split("\n")) { int count = 0; for (int c : row.toCharArray()) { switch (c) { case 'x': while (count-- > 0) { Seat seat = new Seat(no++); seat.setLayoutX(x); x+= Seat.width(); seat.setLayoutY(y); pane.getChildren().add(seat); } count = 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case'6': case '7': case '8': case '9': count = 10*count + (c-'0'); break; case '_': x+= Seat.width(); break; case '.': x+= Seat.width()/2; break; default: System.out.println("Unknown char: '"+(char)c+"'"); } } y += Seat.height(); count = 0; x = 20; } return pane; } LinkedList myPages = new LinkedList(); void addTab(String label, Region node) { myPages.add(node); node.setBackground(new Background(new BackgroundFill(Color.rgb(200, 170, 200), new CornerRadii(0), new Insets(0)))); } @Override public void start(Stage primaryStage) throws Exception { primaryStage.setTitle("Background of Panes"); BorderPane border = new BorderPane(); Pagination pages = new Pagination(); Scene scene = new Scene(border,900,400,Color.WHITE); primaryStage.setScene(scene); addTab("1", theater1(new Pane(), theater1)); addTab("2", theater1(new Pane(), theater2)); pages.setPageCount(myPages.size()); pages.setPageFactory(no -> myPages.get(no)); border.setCenter(pages); primaryStage.show(); } public static void main(String[] args) { launch(args); } } 

产生免费布局,如:

theater1

theater2