获取附加到javafx选项卡的对象



我在javafx选项卡上遇到了一些问题。我需要在新表上获取附加的对象,即BillingTable类。我希望将其分配给字段表,但我不断收到一个异常,告诉我强制转换不起作用。选项卡存储在带有名称选项卡的选项卡窗格中。这是我的代码:

tabs.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
            @Override
            public void changed(ObservableValue<? extends Tab> ov, Tab oldTab, Tab newTab) {
                System.out.println("Tab Selection changed");
                TreeTableView<BillingTable> treeTableView = (TreeTableView<BillingTable>) newTab.getContent();
                table = treeTableView.getRoot().getValue();
            }
        });

BillingTable类别:

public class BillingTable {
private TreeTableView<BillingTableRow> table;
private TreeItem<BillingTableRow> root;
private TreeTableColumn<BillingTableRow, String> nameColumn;
private TreeTableColumn<BillingTableRow, Double> totalColumn;
private TreeTableColumn<BillingTableRow, Double> dayColumn;
private TreeTableColumn<BillingTableRow, Double> eveningColumn;
private TreeTableColumn<BillingTableRow, Double> nightColumn;
private TreeTableColumn<BillingTableRow, Double> weekendColumn;
private TreeTableColumn<BillingTableRow, Double> holidayColumn;
private TreeTableColumn<BillingTableRow, Boolean> billedColumn;
/**
 * Create a new billing table.
 */
public BillingTable() {
    initiateTable();
}
/**
 * Add row to the billing table.
 * 
 * @return Added row.
 */
public TreeItem<BillingTableRow> addRow(BillingTableRow row) {
    TreeItem<BillingTableRow> child = new TreeItem<>(row);
    root.getChildren().add(child);
    return child;
}
/**
 * Add TreeItem to the table root.
 * 
 * @param treeItem
 *            TreeItem to add to the root.
 * @return Added row.
 */
public TreeItem<BillingTableRow> addRow(TreeItem<BillingTableRow> treeItem) {
    root.getChildren().add(treeItem);
    root.getValue().addChild(treeItem.getValue());
    return treeItem;
}
/**
 * Add client to the billing table.
 * 
 * @param client
 *            Client to add.
 * @return Created row in billing table.
 */
public TreeItem<BillingTableRow> addClient(Client client) {
    TreeItem<BillingTableRow> row = new TreeItem<>(new BillingTableRow(client));
    addRow(row);
    return row;
}
/**
 * Initiate TreeTableView of billing data.
 */
private void initiateTable() {
    table = new TreeTableView<>();
    // Define columns
    nameColumn = new TreeTableColumn<>("Namn");
    totalColumn = new TreeTableColumn<>("Summa");
    dayColumn = new TreeTableColumn<>("Dag");
    eveningColumn = new TreeTableColumn<>("Kväll");
    nightColumn = new TreeTableColumn<>("Natt");
    weekendColumn = new TreeTableColumn<>("Helg");
    holidayColumn = new TreeTableColumn<>("Storhelg");
    billedColumn = new TreeTableColumn<>("Faktureras");
    // Change column sizing
    nameColumn.setPrefWidth(150);
    totalColumn.setPrefWidth(60);
    dayColumn.setPrefWidth(60);
    eveningColumn.setPrefWidth(60);
    nightColumn.setPrefWidth(60);
    weekendColumn.setPrefWidth(60);
    holidayColumn.setPrefWidth(60);
    billedColumn.setPrefWidth(80);
    // Bind columns to variables
    nameColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("name"));
    totalColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("timeTotal"));
    dayColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("timeDay"));
    eveningColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("timeEvening"));
    nightColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("timeNight"));
    weekendColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("timeWeekend"));
    holidayColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("timeHoliday"));
    billedColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("billed"));
    // Make cells editable for all columns
    makeEditableCells();
    // Add columns to table
    table.getColumns().add(nameColumn);
    table.getColumns().add(totalColumn);
    table.getColumns().add(dayColumn);
    table.getColumns().add(eveningColumn);
    table.getColumns().add(nightColumn);
    table.getColumns().add(weekendColumn);
    table.getColumns().add(holidayColumn);
    table.getColumns().add(billedColumn);
    root = new TreeItem<BillingTableRow>(new BillingTableRow("Root"));
    root.setExpanded(true);
    table.setRoot(root);
    table.setShowRoot(false);
    table.setTableMenuButtonVisible(true);
}
...

例外情况:

Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: gui.BillingTableRow cannot be cast to gui.BillingTable
at application.Main$1.changed(Main.java:136)
at application.Main$1.changed(Main.java:1)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(Unknown Source)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(Unknown Source)
at javafx.beans.property.ReadOnlyObjectWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(Unknown Source)
at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(Unknown Source)
at javafx.beans.property.ObjectPropertyBase.markInvalid(Unknown Source)
at javafx.beans.property.ObjectPropertyBase.set(Unknown Source)
at javafx.scene.control.SelectionModel.setSelectedItem(Unknown Source)
at javafx.scene.control.TabPane$TabPaneSelectionModel.select(Unknown Source)
at javafx.scene.control.TabPane$TabPaneSelectionModel.select(Unknown Source)
at javafx.scene.control.TabPane$TabPaneSelectionModel.findNearestAvailableTab(Unknown Source)
at javafx.scene.control.TabPane$TabPaneSelectionModel.lambda$new$17(Unknown Source)
at javafx.scene.control.TabPane$TabPaneSelectionModel$$Lambda$66/1951002621.onChanged(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(Unknown Source)
at javafx.collections.ObservableListBase.fireChange(Unknown Source)
at javafx.collections.ListChangeBuilder.commit(Unknown Source)
at javafx.collections.ListChangeBuilder.endChange(Unknown Source)
at javafx.collections.ObservableListBase.endChange(Unknown Source)
at javafx.collections.ModifiableObservableListBase.add(Unknown Source)
at java.util.AbstractList.add(Unknown Source)
at application.Main.addTab(Main.java:705)
at application.Main.start(Main.java:142)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(Unknown Source)
at com.sun.javafx.application.LauncherImpl$$Lambda$69/1795971577.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(Unknown Source)
at com.sun.javafx.application.PlatformImpl$$Lambda$45/1051754451.run(Unknown Source)
at com.sun.javafx.application.PlatformImpl.lambda$null$164(Unknown Source)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/1600778379.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(Unknown Source)
at com.sun.javafx.application.PlatformImpl$$Lambda$46/1775282465.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(Unknown Source)
at com.sun.glass.ui.win.WinApplication$$Lambda$37/1109371569.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

发布涉及异常的问题时的请求:

你能总是指出代码中的哪一行正在生成异常吗?堆栈跟踪告诉我们是第136行,但无法从您发布的代码片段中知道哪一行是136行。

我只想从关于强制转换的消息中猜测,生成异常的行实际上是

table = treeTableView.getRoot().getValue();

(而不是带有显式强制转换的行)。

如果你有一个TreeTableView<BillingTable>,那么它的根就是TreeItem<BillingTable>。因此,treeTableView.getRoot()返回一个TreeItem<BillingTable>,并在其上调用getValue()返回BillingTable,这可能是table的类型(否则它不会编译)。

错误消息显示,在运行时评估treeTableView.getRoot().getValue()实际上返回了BillingTableRow类型的对象,而不是预期的计费表。

发生这种情况的唯一方法是在初始化过程中使用原始类型。参数化的类型在运行时基本上不会被记住("类型擦除"),因此类型检查都是编译器检查。如果使用原始类型,编译器将允许您在TreeItem中放置错误类型的对象,或在TreeTableView中放置错误的TreeItem

因此,在初始化过程的某个地方,你做了一些类似的事情

TreeTableView<BillingTable> treeTableView = new TreeTableView<>();
TreeItem root = new TreeItem(someBillingTableRow);
treeTableView.setRoot(root);

或者你做了

TreeTableView treeTableView = new TreeTableView();
TreeItem<BillingTableRow> root = new TreeItem<>(someBillingTableRow);
treeTableView.setRoot(root);

这是错误的,因为在这两种情况下,都将树表视图的根设置为具有BillingTableRow而不是BillingTable值的树项。

如果你正确地为所有内容提供类型,那么你就可以避免这些问题(我的意思是,你会得到编译器错误,而不是运行时错误,这更容易修复):

TreeTableView<BillingTable> treeTableView = new TreeTableView();
TreeItem<BillingTable> root = new TreeItem<>(...);
treeTableView.setRoot(root);

编译器现在将强制您传递给TreeItem构造函数的任何内容都是正确的类型。

编辑

当然,如果你的TreeTableView真的是TreeTableView<BillingTableRow>,那么你就做

TreeTableView<BillingTableRow> treeTableView = new TreeTableView();
TreeItem<BillingTableRow> root = new TreeItem<>(...);
treeTableView.setRoot(root);

那么TreeTableView的根中的值就是BillingTableRow,所以您可以相应地修复代码:

BillingTableRow table ;
tabs.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
            @Override
            public void changed(ObservableValue<? extends Tab> ov, Tab oldTab, Tab newTab) {
                System.out.println("Tab Selection changed");
                TreeTableView<BillingTableRow> treeTableView = (TreeTableView<BillingTableRow>) newTab.getContent();
                table = treeTableView.getRoot().getValue();
            }
        });

您必须为所有选项卡设置内容(TreeTableView)以及对于选项卡中的所有TreeTableView setRoot(TreeItem);我希望是解决方案。

您可以看到以下示例代码:

    table=new BillingTable();

    TabPane tabs=new TabPane();
    tabs.setPrefWidth(400);
    tabs.setPrefHeight(400);
    Tab tab = new Tab();
    tab.setText("Tab1");
    Tab tab1 = new Tab();
    tab1.setText("Tab2");
    Tab tab2 = new Tab();
    tab2.setText("Tab3");
    tabs.getTabs().add(tab);
    tabs.getTabs().add(tab1);
    tabs.getTabs().add(tab2);
    TreeTableView<BillingTable> tt=new TreeTableView<BillingTable>();
    tt.getColumns().add(new TreeTableColumn<BillingTable,String>(){});
    tt.setRoot(new TreeItem<BillingTable>());

    tab.setContent(tt);
    tab1.setContent(tt);
    tab2.setContent(tt);
    tabs.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
        @Override
        public void changed(ObservableValue<? extends Tab> ov, Tab oldTab, Tab newTab) {
            System.out.println("Tab Selection changed");
            TreeTableView<BillingTable> treeTableView = (TreeTableView<BillingTable>) newTab.getContent();
            table = treeTableView.getRoot().getValue();
        }
    });

最新更新