JavaFx:如何禁用切换到不同的选项卡?

时间:2017-05-15 07:24:44

标签: java validation javafx tabs fxml

我正在使用Javafx开发一个应用程序,其中我在tabpane中有不同的选项卡。所以每个项目都有不同的控制器,比如Tabs有不同的控制器,每个tabpane都有独立的控制器。

我想要做的是用户无法切换到另一个标签,除非他填写当前标签上的所有元素,如文本字段,复选框等。

我做了研究,发现了一个接近我的问题的解决方案,但是开发人员在application中使用的方法与我的方法没什么不同,他将所有内容放在主控制器中,如:

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javafx.beans.InvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.ListBinding;
import javafx.beans.binding.LongBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.css.PseudoClass;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.Pane;
import javafx.scene.web.WebView;

public class MainController {
    @FXML
    private TextField firstNameTextField ;
    @FXML
    private TextField lastNameTextField ;
    @FXML
    private TextField emailTextField ;
    @FXML
    private TextField zipCodeTextField ;
    @FXML
    private Tab nameTab ;
    @FXML
    private Tab contactTab ;
    @FXML
    private Tab confirmationTab ;
    @FXML
    private TabPane tabPane ;
    @FXML
    private TitledPane nameTabErrorList ;
    @FXML
    private Pane nameTabErrorMessages ;
    @FXML
    private TitledPane contactTabErrorList ;
    @FXML
    private Pane contactTabErrorMessages ;
    @FXML
    private WebView browser ;
    @FXML
    private Label nameTabErrorInstructions ;
    @FXML
    private Label contactTabErrorInstructions ;

    public void initialize() {
        // Bit of a hack. Probably need a ValidationBinding extends BooleanBinding with a message property:
        Map<BooleanBinding, String> messages = new HashMap<>();

        tabPane.getSelectionModel().select(nameTab);
        BooleanBinding firstNameInvalid = emptyTextFieldBinding(firstNameTextField, "First Name is required", messages);
        BooleanBinding lastNameInvalid = emptyTextFieldBinding(lastNameTextField, "Last Name is required", messages);
        final Pattern emailPattern = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*@[a-zA-Z][a-zA-Z0-9_]+(\\.[a-zA-Z][a-zA-Z0-9_]*)+");
        BooleanBinding emailInvalid = patternTextFieldBinding(emailTextField, emailPattern, "You must enter a valid email", messages);
        final Pattern zipPattern = Pattern.compile("[0-9]{5}");
        BooleanBinding zipInvalid = patternTextFieldBinding(zipCodeTextField, zipPattern, "You must enter a 5-digit zip code", messages);

        BooleanBinding[] nameTabBindings = { firstNameInvalid, lastNameInvalid } ;
        BooleanBinding[] contactTabBindings = { emailInvalid, zipInvalid } ;

        BooleanBinding nameTabInvalid = any(nameTabBindings);
        BooleanBinding contactTabInvalid = any(contactTabBindings);

        contactTab.disableProperty().bind(nameTabInvalid);
        confirmationTab.disableProperty().bind(nameTabInvalid.or(contactTabInvalid));

        nameTabErrorInstructions.visibleProperty().bind(nameTabInvalid);
        contactTabErrorInstructions.visibleProperty().bind(contactTabInvalid);

        bindMessageLabels(nameTabBindings, nameTabErrorMessages.getChildren(), messages);

        final LongBinding nameTabErrorCount = count(nameTabBindings);
        nameTabErrorList.textProperty().bind(Bindings.format("%d %s on this page", nameTabErrorCount,
                Bindings.when(nameTabErrorCount.isEqualTo(1)).then("error").otherwise("errors")));

        bindMessageLabels(contactTabBindings, contactTabErrorMessages.getChildren(), messages);

        final LongBinding contactTabErrorCount = count(contactTabBindings);
        contactTabErrorList.textProperty().bind(Bindings.format("%d %s on this page", contactTabErrorCount,
                Bindings.when(contactTabErrorCount.isEqualTo(1)).then("error").otherwise("errors")));

        browser.getEngine().load("http://www.google.com");
    }

    private void bindMessageLabels(BooleanBinding[] validationBindings, List<Node> labelList, Map<BooleanBinding, String> messages) {
        ListBinding<Node> nodeListBinding = new ListBinding<Node>() {

            { 
                // calling bind(...) here won't work, neither will using WeakInvalidationListeners. Not sure why....
                InvalidationListener invalidationListener = obs -> invalidate();
                Arrays.stream(validationBindings).forEach(binding -> 
                    binding.addListener(invalidationListener));
            }

            @Override
            protected ObservableList<Node> computeValue() {
                return FXCollections.observableList(
                    Arrays.stream(validationBindings)
                        .filter(BooleanBinding::get)
                        .map(messages::get).map(Label::new)
                        .collect(Collectors.toList())
                );
            }
        };

        Bindings.bindContent(labelList, nodeListBinding);
    }

    private BooleanBinding emptyTextFieldBinding(TextField textField, String message, Map<BooleanBinding, String> messages) {
        BooleanBinding binding = Bindings.createBooleanBinding(() -> 
            textField.getText().trim().isEmpty(), textField.textProperty());
        configureTextFieldBinding(binding, textField, message, messages);
        return binding ;
    }

    private BooleanBinding patternTextFieldBinding(TextField textField, Pattern pattern, String message, Map<BooleanBinding, String> messages) {
        BooleanBinding binding = Bindings.createBooleanBinding(() -> 
            !pattern.matcher(textField.getText()).matches(), textField.textProperty());
        configureTextFieldBinding(binding, textField, message, messages);
        return binding ;
    }

    private void configureTextFieldBinding(BooleanBinding binding, TextField textField, String message, Map<BooleanBinding, String> messages) {
        messages.put(binding, message);
        if (textField.getTooltip() == null) {
            textField.setTooltip(new Tooltip());
        }
        String tooltipText = textField.getTooltip().getText();
        binding.addListener((obs, oldValue, newValue) -> {
            updateTextFieldValidationStatus(textField, tooltipText, newValue, message);
        });
        updateTextFieldValidationStatus(textField, tooltipText, binding.get(), message);
    }

    private BooleanBinding any(BooleanBinding[] bindings) {
        return Bindings.createBooleanBinding(() -> 
            Arrays.stream(bindings).anyMatch(BooleanBinding::get), bindings);
    }

    private LongBinding count(BooleanBinding[] bindings) {
        return Bindings.createLongBinding(() -> 
            Arrays.stream(bindings).filter(BooleanBinding::get).collect(Collectors.counting()), bindings);
    }

    private void updateTextFieldValidationStatus(TextField textField,
            String defaultTooltipText, boolean invalid, String message) {
        textField.pseudoClassStateChanged(PseudoClass.getPseudoClass("validation-error"), invalid);
        String tooltipText ;
        if (invalid) {
            tooltipText = message;
        } else {
            tooltipText = defaultTooltipText;
        }
        if (tooltipText == null || tooltipText.isEmpty()) {
            textField.setTooltip(null);
        } else {
            Tooltip tooltip = textField.getTooltip();
            if (tooltip == null) {
                textField.setTooltip(new Tooltip(tooltipText));
            } else {
                tooltip.setText(tooltipText);
            }
        }
    }

}

但在很多情况下,因为我为每个标签设置了不同的控制器,我如何才能与不同的控制器实现相似:

TabPaneManager.java

public class TabPaneManager {

    @FXML
    private TabPane tabPane ;
    @FXML
    private Tab aTab ;
    @FXML
    private Tab bTab ;
    @FXML
    private Tab cTab ;

    public void initialize() {


    }


} 

aTabController.java

public class aTabController {

    @FXML
    private JFXCheckBox aCheckBox ;
    @FXML
    private JFXCheckBox bCheckBox ;
    @FXML
    private JFXComboBox<String> aComboBox ;
    @FXML
    private JFXTextField aTextField ;
    @FXML
    private JFXTextField bTextField ;
    @FXML
    private JFXTextField cTextField ;

    public void initialize() {

    }


}

bTabController.java

public class bTabController {

        @FXML
        private JFXCheckBox aCheckBox ;
        @FXML
        private JFXTextField aTextField ;
        @FXML
        private JFXTextField bTextField ;

        public void initialize() {

        }


    }

cTabController.java

public class cTabController {

            @FXML
            private JFXTextField aTextField ;
            @FXML
            private JFXTextField bTextField ;
            @FXML
            private JFXTextField cTextField ;
            @FXML
            private JFXButton aButton ;

            public void initialize() {

            }


        }

1 个答案:

答案 0 :(得分:0)

如果符合要求,只需广告跟随标签。

aTabComboBoxKeyActionPerformed(KeyEvent evt){
    if(evt.getKeyCode()==KeyEvent.VK_RETURN) 
        if(combo1.getSelectedIndex()!=-1 && textField.getText().matches("Your idea")||et.c.)
            tabbedPanel.addTab(bTab);
}