我完成了一个Small Java FX项目,我为我的一个列使用了多重绑定,以便它可以即时更新。我遇到的问题是我无法使用绑定打开XML文件,因为它在标题中给出了上述错误。这是我的项目代码
public class Items {
private final StringProperty name;
private final IntegerProperty quantity;
private final DoubleProperty price;
private final DoubleProperty total;
public Items() {
this(null,0,0);
}
public Items(String name, int quantity, double price) {
this.name = new SimpleStringProperty(name);
this.quantity = new SimpleIntegerProperty(quantity);
this.price = new SimpleDoubleProperty(price);
this.total = new SimpleDoubleProperty();
NumberBinding multiplication = Bindings.multiply(
this.priceDoubleProperty(), this.quantityIntegerProperty());
this.totalProperty().bind(multiplication);
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public StringProperty NameProperty() {
return name;
}
public int getQuantity() {
return quantity.get();
}
public void setQuantity(int quantity) {
this.quantity.set(quantity);
}
public IntegerProperty quantityIntegerProperty() {
return quantity;
}
public double getPrice() {
return price.get();
}
public void setPrice(double price) {
this.price.set(price);
}
public DoubleProperty priceDoubleProperty() {
return price;
}
public double getTotal() {
return total.get();
}
public void setTotal(double total) {
this.total.set(total);
}
public DoubleProperty totalProperty() {
return total;
}
}
这是MainApp代码
public class MainApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
public static ObservableList<Items> itemData = FXCollections
.observableArrayList();
public MainApp() {
// Add some sample data
itemData.add(new Items("Hans", 0, 0));
itemData.add(new Items("Ruth", 0, 0));
}
/**
* Returns the data as an observable list of Persons.
*
* @return
*/
public ObservableList<Items> getItemData() {
return itemData;
}
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Shopping Basket");
primaryStage.setMinHeight(400);
primaryStage.setMinWidth(600);
primaryStage.setMaxHeight(600);
primaryStage.setMaxWidth(700);
this.primaryStage.getIcons().add(new Image("file:resources/images/shopping_basket_32.png"));
initRootLayout();
showBasketOverview();
}
/**
* Initializes the root layout.
*/
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class
.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
// Give the controller access to the main app.
RootLayoutController controller = loader.getController();
controller.setMainApp(this);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
// Try to load last opened person file.
File file = getItemFilePath();
if (file != null) {
loadItemDataFromFile(file);
}
}
/**
* Opens a dialog to edit details for the specified person. If the user
* clicks OK, the changes are saved into the provided person object and true
* is returned.
*
* @param person
* the person object to be edited
* @return true if the user clicked OK, false otherwise.
*/
/**
* Shows the person overview inside the root layout.
*/
public void showBasketOverview() {
try {
// Load person overview.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class
.getResource("view/BasketOverview.fxml"));
AnchorPane BasketOverview = (AnchorPane) loader.load();
// Set person overview into the center of root layout.
rootLayout.setCenter(BasketOverview);
// Give the controller access to the main app.
BasketOverviewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the main stage.
*
* @return
*/
public Stage getPrimaryStage() {
return primaryStage;
}
public boolean showBasketEditDialog(Items item) {
try {
// Load the fxml file and create a new stage for the popup dialog.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class
.getResource("view/BasketEditDialog.fxml"));
AnchorPane page = (AnchorPane) loader.load();
// Create the dialog Stage.
Stage dialogStage = new Stage();
dialogStage.setTitle("Edit Basket");
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.initOwner(primaryStage);
Scene scene = new Scene(page);
dialogStage.setScene(scene);
// Set the person into the controller.
BasketEditDialogController controller = loader.getController();
controller.setDialogStage(dialogStage);
controller.setItems(item);
// Show the dialog and wait until the user closes it
dialogStage.showAndWait();
return controller.isOkClicked();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
public File getItemFilePath() {
Preferences prefs = Preferences.userNodeForPackage(MainApp.class);
String filePath = prefs.get("Filepath", null);
if (filePath != null) {
return new File(filePath);
} else {
return null;
}
}
public void setItemFilePath(File file) {
Preferences prefs = Preferences.userNodeForPackage(MainApp.class);
if (file != null) {
prefs.put("filePath", file.getPath());
primaryStage.setTitle("Shopping Basket - " + file.getName());
} else {
prefs.remove("filePath");
primaryStage.setTitle("Shopping Basket");
}
}
public void loadItemDataFromFile(File file) {
try {
JAXBContext context = JAXBContext
.newInstance(BasketListWrapper.class);
Unmarshaller um = context.createUnmarshaller();
BasketListWrapper wrapper = (BasketListWrapper) um.unmarshal(file);
itemData.clear();
itemData.addAll(wrapper.getItems());
setItemFilePath(file);
} catch (Exception e) {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText(e + "Could not load data");
alert.setContentText("Could not load data from file:\n"
+ file.getPath());
alert.showAndWait();
}
}
public void saveItemDataToFile(File file) {
try {
JAXBContext context = JAXBContext
.newInstance(BasketListWrapper.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
BasketListWrapper wrapper = new BasketListWrapper();
wrapper.setItems(itemData);
m.marshal(wrapper, file);
setItemFilePath(file);
} catch (Exception e) {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText("Could not load data");
System.out.println(e);
alert.setContentText("Could not load data from file:\n"
+ file.getPath());
alert.showAndWait();
}
}
public static void main(String[] args) {
launch(args);
}
}
这是错误代码
java.lang.RuntimeException: A bound value cannot be set.
at javafx.beans.property.DoublePropertyBase.set(Unknown Source)
at sb.basket.model.Items.setTotal(Items.java:83)
at sb.basket.model.Items$JaxbAccessorM_getTotal_setTotal_double.set(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.reflect.Accessor.receive(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.endElement(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.endElement(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(Unknown Source)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(Unknown Source)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(Unknown Source)
at sb.basket.MainApp.loadItemDataFromFile(MainApp.java:201)
at sb.basket.view.RootLayoutController.handleOpen(RootLayoutController.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.Trampoline.invoke(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.reflect.misc.MethodUtil.invoke(Unknown Source)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(Unknown Source)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.control.MenuItem.fire(Unknown Source)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(Unknown Source)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$343(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEventImpl(Unknown Source)
at com.sun.javafx.event.EventUtil.fireEvent(Unknown Source)
at javafx.event.Event.fireEvent(Unknown Source)
at javafx.scene.Scene$MouseHandler.process(Unknown Source)
at javafx.scene.Scene$MouseHandler.access$1500(Unknown Source)
at javafx.scene.Scene.impl_processMouseEvent(Unknown Source)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$355(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(Unknown Source)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.handleMouseEvent(Unknown Source)
at com.sun.glass.ui.View.notifyMouse(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$149(Unknown Source)
at java.lang.Thread.run(Unknown Source)
答案 0 :(得分:1)
JavaFX绑定表明属性的值应始终等于某个表达式。具体来说,在你的代码中
NumberBinding multiplication = Bindings.multiply(
this.priceDoubleProperty(), this.quantityIntegerProperty());
this.totalProperty().bind(multiplication);
您声明total
应始终为price x quantity
。
设置绑定值是违法的(因为将其设置为某个值会破坏绑定,即违反绑定所隐含的合同)。
实际上,您已使total
成为&#34;派生属性`:其值完全由其他值确定(在同一对象中,在本例中)。因此:
total
,因为这样做是多余的。发生异常是因为当您通过JAXB解组XML时,反序列化过程会尝试设置总计(存储在XML文件中)。我对JAXB不太熟悉,但以下内容应该有效(请注意,这与以前存储项目的XML文件不兼容;我也修复了一些方法名称,以便它们与JavaFX属性模式匹配):
public class Items {
private final StringProperty name;
private final IntegerProperty quantity;
private final DoubleProperty price;
private final ReadOnlyDoubleWrapper total;
public Items() {
this(null,0,0);
}
public Items(String name, int quantity, double price) {
this.name = new SimpleStringProperty(name);
this.quantity = new SimpleIntegerProperty(quantity);
this.price = new SimpleDoubleProperty(price);
this.total = new ReadOnlyDoubleWrapper();
NumberBinding multiplication = Bindings.multiply(
this.priceDoubleProperty(), this.quantityProperty());
this.total.bind(multiplication);
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
public StringProperty nameProperty() {
return name;
}
public int getQuantity() {
return quantity.get();
}
public void setQuantity(int quantity) {
this.quantity.set(quantity);
}
public IntegerProperty quantityProperty() {
return quantity;
}
public double getPrice() {
return price.get();
}
public void setPrice(double price) {
this.price.set(price);
}
public DoubleProperty priceProperty() {
return price;
}
@XmlTransient
public double getTotal() {
return total.get();
}
public ReadOnlyDoubleProperty totalProperty() {
return total.getReadOnlyProperty();
}
}