如何解决JavaFX:无法在微调器的增量方法中捕获异常
我无法在我的 JavaFX 应用程序中捕获 Exception
(特别是 IllegalArgumentException
,尽管我认为问题与此无关)。
对于上下文,当尝试动态设置微调器的最大值时会出现这种情况。或者更准确地说(因为最大值在创建后无法更改),如果出现 IllegalArgumentException
则不会增加。为此,我设置了自己的 DynamicIntegerSpinnerValueFactory
,它扩展了 JavaFX 提供的 IntegerSpinnerValueFactory
。
由于微调器用于 TableView
,我还实现了一个 IntegerSpinnerTableCellFactory
来制作一列微调器。我已经包含了代码只是为了能够提供 MWE,但是您(原则上)可以忽略这一点,因为问题不应该存在。
Furnishing
是我用来填充表格的对象。如果我们设置的数量超过一定数量,owned
的 setter 会抛出一个 IllegalArgumentException
。
fxml
和 FurnishingsTabController
只是你用来制作窗口、加载表格等的工具...... Main
类只是为了制作一个列表虚拟值并启动程序。
摘要
这是我动态绑定微调器的思考过程:让 setter 在特定条件下抛出 IllegalArgumentException
并拥有微调器工厂 {{1} 的 increment
和 decrement
方法捕获该异常。当被捕获时,这些方法不会增加/减少值。
要重现该问题,请运行 DynamicIntegerSpinnerValueFactory
并将一个微调器增加到 10 个以上。异常应该在控制台中抛出,但不会被 Main
...{1 }}在try
中。
PS:下面提供了所有代码。
代码
catch
(未捕获到 DynamicIntegerSpinnerValueFactory
)
DynamicIntegerSpinnerValueFactory
Exception
(setter 抛出 import javafx.scene.control.SpinnerValueFactory.IntegerSpinnerValueFactory;
public class DynamicIntegerSpinnerValueFactory extends IntegerSpinnerValueFactory{
public DynamicIntegerSpinnerValueFactory(int min,int max) {
super(min,max);
}
public DynamicIntegerSpinnerValueFactory(int min,int max,int initialValue) {
super(min,max,initialValue);
}
public DynamicIntegerSpinnerValueFactory(int min,int initialValue,int amountToStepBy) {
super(min,initialValue,amountToStepBy);
}
@Override
public void decrement(int steps) {
int newValue = getValue() - steps;
int min = getMin();
if (newValue >= min)
setValue(newValue);
}
@Override
public void increment(int steps) {
int newValue = getValue() + steps;
int max = getMax();
if (newValue <= max) {
try {
setValue(newValue);
}
catch(IllegalArgumentException e) {
System.out.println("Hello"); //Exception not being caught since Hello is not being printed!
}
catch(Throwable t) {
System.out.println("World"); //Problem is not related with IllegalArgumentException since this isn't caught either...
}
}
}
}
)
Furnishing
IllegalArgumentException
public class Furnishing {
private String name;
private int owned;
public Furnishing(String name,int owned) {
this.name = name;
this.owned = owned;
}
public int getowned() {
return owned;
}
public void setowned(int owned) {
if (owned < 0)
throw new IllegalArgumentException("Owned amount must be >= 0.");
if (owned > 10) //Just a small number to be easier to trigger the exception
throw new IllegalArgumentException("Limiting the amount of owned to 10");
this.owned = owned;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Main
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String args[]) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Furnishing> furnishings = FXCollections.observableArrayList();
furnishings.add(new Furnishing("Curtains",2));
furnishings.add(new Furnishing("Cushions",4));
furnishings.add(new Furnishing("Sofas",1));
//Load the fxml
FXMLLoader loader = new FXMLLoader(getClass().getResource("/FurnishingsTab.fxml"));
Parent root = loader.load();
//Get the controller
FurnishingsTabController furnishingsTabController = loader.getController();
//Load tables
furnishingsTabController.loadTable(furnishings);
//Set the stage
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
FurnishingsTableController
(工厂提供import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
public class FurnishingsTabController {
//Furnishings table
@FXML private TableView<Furnishing> furnishingsTableView;
//Furnishings table columns
@FXML private TableColumn<Furnishing,String> furnishingsTabItemColumn;
@FXML private TableColumn<Furnishing,Integer> furnishingsTabOwnedColumn;
//Spinner factories
private IntegerSpinnerTableCellFactory<Furnishing> ownedColumnSpinnerFactory = new IntegerSpinnerTableCellFactory<>();
public void initialize() {
//Item column
furnishingsTabItemColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
//Owned column
furnishingsTabOwnedColumn.setCellValueFactory(new PropertyValueFactory<>("owned"));
furnishingsTabOwnedColumn.setCellFactory(ownedColumnSpinnerFactory);
ownedColumnSpinnerFactory.setUpdater((furnishing,newValue) -> {
furnishing.setowned(newValue);
});
return;
}
public void loadTable(ObservableList<Furnishing> furnishings) {
furnishingsTableView.setItems(furnishings);
}
}
中的微调器;这里用于 MWE,但您可能可以忽略它)
IntegerSpinnerTableCellFactory
TableCells
import java.util.function.BiConsumer;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
import javafx.util.Duration;
public class IntegerSpinnerTableCellFactory<S> implements Callback<TableColumn<S,Integer>,TableCell<S,Integer>> {
private BiConsumer<S,Integer> updater = null;
public void setUpdater(BiConsumer<S,Integer> updater) {
this.updater = updater;
}
@Override
public TableCell<S,Integer> call(TableColumn<S,Integer> param) {
return new TableCell<S,Integer>() {
SpinnerValueFactory<Integer> factory = new DynamicIntegerSpinnerValueFactory(0,Integer.MAX_VALUE,0);
//Spinner<Integer> spinner = new Spinner<>(0,maxValue,0);
Spinner<Integer> spinner = new Spinner<>(factory);
{
//Set the duration between changes (when pressing and holding the arrow) to 30 ms
spinner.repeatDelayproperty().set(new Duration(30));
//Set the style for horizontal split arrows
spinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
spinner.valueproperty().addListener((obs,oldValue,newValue) -> {
if (updater != null)
updater.accept(getTableView().getItems().get(getIndex()),newValue);
});
}
protected void updateItem(Integer item,boolean empty) {
super.updateItem(item,empty);
if (empty) {
setGraphic(null);
}
else {
spinner.getValueFactory().setValue(getItem());
setGraphic(spinner);
}
}
};
}
}
解决方法
当然它永远不会命中getter,因为表格单元格值工厂使用反射来获取或设置值。
furnishingsTabOwnedColumn.setCellValueFactory(new PropertyValueFactory<>("owned"));
这个工厂依赖反射来访问值。
因此,您必须在 spinner factory 的 increment/decrement 方法或设置值中抛出异常(或限制值)。
,我设法绕过了这个问题。由于某种原因(这正是我想问的),我无法从微调器工厂捕获 increment()
中的异常。
我所做的是使用自定义 QuadriConsumer
更新程序(而不是 BiConsumer
更新程序),并将 spinner
和 oldValue
传递给它。然后我可以在控制器中捕获 Exception
并防止微调器改变,这是我最初的目标。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。