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

时间:2014-11-24 17:20:54

标签: java javafx

我正在尝试实施类似于剧院,电影院等席位选择以及他们的不同意见。

使用此代码:

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

我能够得到这个,这是我想要的视觉效果(没有样式)。 Example image

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

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

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

2 个答案:

答案 0 :(得分:1)

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<BooleanProperty> 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);
    }
}

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

class DisponibilityCell extends TableCell<MyObject, Boolean> {
    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<MyObject> table = new TableView<>();
    table.setPrefSize(800, 600);

    int[] rowsColumns = new int[]{10,20}; // [0] = rows : [1] = columns
    ObservableList<MyObject> list = FXCollections.observableArrayList();
    for (int i = 0; i < rowsColumns[0]; i++) {
        list.add(new MyObject(rowsColumns[1],true));
    }

    List<TableColumn<MyObject,Boolean>> tableColumns = new ArrayList<>(rowsColumns[1]);
    IntStream.range(0, rowsColumns[1]).boxed().forEach(i-> {
        TableColumn<MyObject,Boolean> 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("");
        });
    });

答案 1 :(得分:0)

我不会使用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<Node> myPages = new LinkedList<Node>();
    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