微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JavaFX:无法在微调器的增量方法中捕获异常

如何解决JavaFX:无法在微调器的增量方法中捕获异常

我无法在我的 JavaFX 应用程序中捕获 Exception(特别是 IllegalArgumentException,尽管我认为问题与此无关)。

对于上下文,当尝试动态设置微调器的最大值时会出现这种情况。或者更准确地说(因为最大值在创建后无法更改),如果出现 IllegalArgumentException 则不会增加。为此,我设置了自己的 DynamicIntegerSpinnerValueFactory,它扩展了 JavaFX 提供的 IntegerSpinnerValueFactory

由于微调器用于 TableView,我还实现了一个 IntegerSpinnerTableCellFactory 来制作一列微调器。我已经包含了代码只是为了能够提供 MWE,但是您(原则上)可以忽略这一点,因为问题不应该存在。

Furnishing 是我用来填充表格的对象。如果我们设置的数量超过一定数量owned 的 setter 会抛出一个 IllegalArgumentException

fxmlFurnishingsTabController 只是你用来制作窗口、加载表格等的工具...... Main 类只是为了制作一个列表虚拟值并启动程序。

摘要

这是我动态绑定微调器的思考过程:让 setter 在特定条件下抛出 IllegalArgumentException 并拥有微调器工厂 {{1} 的 incrementdecrement 方法捕获该异常。当被捕获时,这些方法不会增加/减少值。

要重现该问题,请运行 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 更新程序),并将 spinneroldValue 传递给它。然后我可以在控制器中捕获 Exception 并防止微调器改变,这是我最初的目标。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。