JavaFX:如果所选选项卡的数据验证失败,则禁止选择其他选项卡

时间:2014-03-31 21:16:49

标签: validation tabs javafx

我正在创建一个将数据存储在本地h2数据库中的CRUD应用程序。我是JavaFX的新手。我使用TabPane使用Tab创建了jfxml至3 Scene Builder 2.0。每个标签都包含AncorPane,其中包含所有控件:LabelEditText等。使用一个控制器管理TabPaneTabs。此函数用于创建和更新数据。它是从显示所有数据的网格调用的。一个非常基本的CRUD应用程序。

我陷入了验证阶段:当用户更改选项卡时,通过选择另一个选项卡,它被称为相应选项卡的验证方法。如果选项卡的验证失败,我希望选择保留在此选项卡上。

为实现这一目标,我在ChangeListener的{​​{1}}上实施了以下SelectionModel

TabPane

我不确定这是正确的做法,因为:

  1. 事件boolean processingTabValidationOnChange = false; tabPane.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) { if (processingTabValidationOnChange == false) { boolean success; switch (t.intValue()) { case 0: success = validationTab1Passed(); break; case 1: success = validationTab2Passed(); break; case 1: success = validationTab3Passed(); break; default: success = false; } if (success == false) { processingTabValidationOnChange = true; // select the previous tab tabPane.getSelectionModel().select(t.intValue()); processingTabValidationOnChange = false; } } } }); 被触发两次,一次用于用户选择,一次用于changed。为了避免这种情况,我使用了一个全局字段布尔.select(t.intValue()) ...我知道的很脏。
  2. processingTabValidationOnChange TabPane显示正确的选项卡后,选项卡的内容为空,就好像隐藏了.select(t.intValue())一样。我无法再次选择包含错误的选项卡,因为它已被选中。
  3. 任何帮助都将不胜感激。

    埃尔维斯

3 个答案:

答案 0 :(得分:2)

正如我对詹姆斯的答案所评论的那样,我正在寻找一种干净的解决方案来解决我所提出的问题。简而言之,防止用户在当前选项卡的验证失败时更改为其他选项卡。我提出了一个实施ChangeListener的解决方案,但正如我所解释的那样:它不是很清楚&#34;清洁&#34; (小细节)它不起作用!

好的,问题是用于切换回上一个标签的代码:

tabPane.getSelectionModel().select(t.intValue());

在切换标签本身之前调用它已完成,因此它最终被选中......但是隐藏了。

为了防止这种情况,我使用了Platform.runLater()。更改选项卡后执行代码.select()。完整的代码变为:

//global field, to prevent validation on .select(t.intValue());
boolean skipValidationOnTabChange = false;

tabPane.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {

    @Override
    public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
        if (skipValidationOnTabChange == false) {
            boolean success;

            switch (t.intValue()) {
                case 0:
                    success = validationTab1Passed();
                    break;
                case 1:
                    success = validationTab2Passed();
                    break;
                case 1:
                    success = validationTab3Passed();
                    break;
                default:
                    success = false;
            }
            if (success == false) {
                Platform.runLater(new Runnable() {

                    @Override
                    public void run() {
                        skipValidationOnTabChange = true;
                        tabPane.getSelectionModel().select(t.intValue());
                        skipValidationOnTabChange = false;
                    }
                });
            }
        }
    }
});

无论如何,如果有人有更好的解决方案来实现这一点,那么欢迎你。在示例中使用consume()之类的方法来阻止选项卡被选中两次。这样我就可以消除全局字段skipValidationOnTabChange

埃尔维斯

答案 1 :(得分:1)

我会以非常不同的方式处理这个问题。而不是等待用户选择不同的选项卡,并在当前选项卡的内容无效时还原,阻止用户首先更改选项卡。

Tab类有一个disableProperty。如果设置为true,则无法选择选项卡。

定义一个BooleanProperty或BooleanBinding,表示第一个选项卡中的数据是否无效。您可以根据选项卡中控件的状态创建此类绑定。然后将第二个选项卡的disableProperty绑定到它。这样,第二个选项卡会自动变为禁用或启用,因为第一个选项卡中的数据变为有效或无效。

您可以根据需要将其扩展到尽可能多的选项卡,按照逻辑指示绑定它们的属性。

这是simple example

更新:上面链接的示例现在有点简单了。它将根据字段是否有效动态更改文本字段的颜色,并通过控制器中的绑定定义验证规则。此外,每页顶部都有标题窗格,标题显示页面上的验证错误数,以及展开标题窗格时的消息列表。所有这些都动态地绑定到控件中的值,因此它为用户提供了持续,清晰但不显眼的反馈。

答案 2 :(得分:0)

我需要实现类似的事情。我通过覆盖com.sun.javafx.scene.control.behavior.TabPaneBehaviour方法更改selectTab类来完成此操作:

class ValidatingTabPaneBehavior extends TabPaneBehavior {

        //constructors etc...

        @Override
        public void selectTab(Tab tab) {
            try {
                Tab current = getControl().getSelectionModel().getSelectedItem();
                if (current instanceof ValidatingTab) {
                    ((ValidatingTab) current).validate();
                }
                //this is the method we want to prevent from running in case of error in validation
                super.selectTab(tab);
            }catch (ValidationException ex) {
                //show alert or do nothing tab won't be changed
            }
        }
    });

ValidatingTab是我自己Tab的扩展名:

public class ValidatingTab extends Tab {
       public void validate() throws ValidationException {
           //validation
       }
}

这是&#34;清洁部分&#34;诀窍。现在我们需要将ValidatingTabPaneBehavior放入TabPane。

首先,您需要将整个com.sun.javafx.scene.control.skin.TabPaneSkin复制(!)到新类,以便更改其构造函数。这是一个很长的类,所以这里只是切换Behavior类时的部分:

public class ValidationTabPaneSkin extends BehaviorSkinBase<TabPane, TabPaneBehavior> {

//copied private fields

public ValidationTabPaneSkin(TabPane tabPane) {
    super(tabPane, new ValidationTabPaneBehavior(tabPane));

    //the rest of the copied constructor
}

最后一件事是更改tabPane实例中的皮肤:

 tabPane.setSkin(new ValidationTabPaneSkin(tabPane));