0

What do I want to do?

I am facing a problem with a fxml based javafx application. I want to create a simple form sheet to enter some numerical values that are supposed to be stored in a file uppon confirmation.

What is the problem?

The form does perfectly what it is supposed to do, except that I cannot mouse click the elements within the two GridPanes. I can enter the values via switching TextFields by pressing the tab button, but that is of course not the ideal way. I have already added TextFields and CheckBoxes within the AnchorPane directly, and they are clickable, but within the GridPanes this does not work. The FlowPane within the same AnchorPane also works perfectly fine.

To me it seems that the GridPanes act as if it was set to mouseTransparent="true", but this is not the case and I already tried explicitly setting it to false as well. I cannot find the reason for this behavior so perhaps somebody of you has an idea.

EDIT: After playing around with an addtional GridPane in the same tab I found out that it is not a general GridPane issue in this file. For a GridPane with only checkboxes and only one Anchor the element can be accessed. Is there some overlap preventing accessability via mouse?

Within an initializer function of a separate class the scene is set:

        BorderPane root = FXMLLoader.load(getClass().getResource("..\\initializeSeason\\InitializeSeason.fxml"));
        Scene scene = new Scene(root,600,900);
        stage.setScene(scene);
        stage.show();

The xfml file is build as follows (I'm sorry for the German names):

            <?xml version="1.0" encoding="UTF-8"?>

    <?import javafx.scene.layout.BorderPane?>
    <?import javafx.scene.control.TabPane?>
    <?import javafx.scene.control.Tab?>
    <?import javafx.scene.layout.FlowPane?>
    <?import javafx.scene.control.Button?>
    <?import javafx.scene.layout.AnchorPane?>
    <?import javafx.scene.layout.GridPane?>
    <?import javafx.scene.text.Text?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.control.TextField?>
    <?import javafx.scene.layout.ColumnConstraints?>
    <?import javafx.scene.control.RadioButton?>
    <?import javafx.scene.control.CheckBox?>

    <BorderPane  xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"  fx:controller="application.LeagueRulesController" >
        <center>
            <TabPane  tabClosingPolicy="UNAVAILABLE" >
                <tabs>
                    <Tab style="-fx-font-weight:bold" text="Liga Regeln" >
                        <AnchorPane  >
                            <children>
                                <GridPane AnchorPane.topAnchor="10.0" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" hgap="15" vgap="15" >
                                        <columnConstraints>
                                            <ColumnConstraints hgrow="ALWAYS" />
                                        </columnConstraints> 

                                    <children>
                                        <Label text="Anzahl der Zeichen im Teamnamen: " GridPane.columnIndex="0" GridPane.rowIndex="0"/>
                                        <TextField fx:id="numberOfShortNameChars" alignment="BASELINE_RIGHT" prefWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="0"/>

                                        <Label text="Anzahl der Touchdown Differenz Einträge: " GridPane.columnIndex="0" GridPane.rowIndex="1"/>
                                        <TextField fx:id="numberOfTDDiffEntries" alignment="BASELINE_RIGHT" prefWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="1"/>

                                        <GridPane fx:id="tdDiffEntrys" hgap="15" vgap="15" GridPane.columnIndex="1" GridPane.rowIndex="2" />

                                        <Label text="Erhält Gewinnerteam bei Spielaufgabe maximale Punktzahl?:" GridPane.columnIndex="0" GridPane.rowIndex="3"/>
                                        <CheckBox  fx:id="isConcedeMaxWin" GridPane.columnIndex="1" GridPane.rowIndex="3"></CheckBox>
                                    </children>
                                </GridPane>

                                <FlowPane  orientation="HORIZONTAL" alignment="BOTTOM_RIGHT" hgap="5" AnchorPane.topAnchor="10.0" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0">
                                    <Button fx:id="okButton" text="OK" onAction="#handleOK"> </Button>
                                    <Button fx:id="abbrechenButton" text="Abbrechen"  onAction="#handleAbbrechen"> </Button>                    
                                </FlowPane> 
                            </children>
                        </AnchorPane>
                    </Tab>
                    <Tab style="-fx-font-weight:bold" text="Teams verwalten">

                    </Tab>      
                </tabs>
            </TabPane>
        </center>
    </BorderPane>

Although I am sure the problem can be found within the .fxml file I also add the LeagueRulesController class.

            package application;

    import java.net.URL;
    import java.util.ArrayList;
    import java.util.ResourceBundle;

    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.geometry.Pos;
    import javafx.scene.control.Button;
    import javafx.scene.control.CheckBox;
    import javafx.scene.control.Label;
    import javafx.scene.control.TextField;
    import javafx.scene.layout.GridPane;
    import javafx.stage.Stage;

    public class LeagueRulesController implements Initializable{


        private ArrayList<TextField> tdDiffs;
        private ArrayList<TextField> points;



        @FXML
        private CheckBox isConcedeMaxWin;

        @FXML
        private Button okButton;
        @FXML
        private Button abbrechenButton;

        @FXML
        private void handleAbbrechen(ActionEvent actionEvet) {
            Stage stage = (Stage) abbrechenButton.getScene().getWindow();
            // do what you have to do
            stage.close();
        }

        @FXML
        private void handleOK(ActionEvent actionEvet) {

            Stage stage = (Stage) abbrechenButton.getScene().getWindow();
            stage.close();
        }

        @FXML
        private TextField numberOfShortNameChars;
        @FXML
        private TextField numberOfTDDiffEntries;    
        @FXML
        private GridPane tdDiffEntrys;

        @Override
        public void initialize(URL arg0, ResourceBundle arg1) {
            numberOfShortNameChars.setText("25");
            numberOfShortNameChars.textProperty().addListener(new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                    numberFieldListener(numberOfShortNameChars, oldValue,newValue);
                }
            });

            numberOfTDDiffEntries.setText("5");

            initializeTDDiffArray();

            numberOfTDDiffEntries.textProperty().addListener(new ChangeListener<String>() {

                @Override
                public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                    numberFieldListener(numberOfTDDiffEntries, oldValue,newValue);
                    initializeTDDiffArray();
                }
            });
        }

        private void initializeTDDiffArray() {
            tdDiffEntrys.getChildren().clear();
            tdDiffs = new ArrayList<>();
            points = new ArrayList<>();

            tdDiffEntrys.add(new Label("TD Diff"), 0, 0);
            tdDiffEntrys.add(new Label("Punkte"), 1, 0);

            int numberOfTDDiffEntriesInt;
            if(numberOfTDDiffEntries.getText().equals(""))
                numberOfTDDiffEntriesInt = 1;
            else
                numberOfTDDiffEntriesInt =Integer.parseInt(numberOfTDDiffEntries.getText());

            for (int i = 0; i < numberOfTDDiffEntriesInt; i++) {
                tdDiffs.add(new TextField());
                points.add(new TextField());
                tdDiffs.get(tdDiffs.size()-1).setText(Integer.toString(i-numberOfTDDiffEntriesInt/2));
                points.get(points.size()-1).setText(Integer.toString(i+1));

                tdDiffs.get(tdDiffs.size()-1).setAlignment(Pos.BASELINE_RIGHT);
                points.get(points.size()-1).setAlignment(Pos.BASELINE_RIGHT);

                tdDiffs.get(tdDiffs.size()-1).setPrefWidth(1);
                points.get(points.size()-1).setPrefWidth(1);

                tdDiffs.get(tdDiffs.size()-1).textProperty().addListener(new ChangeListener<String>() {
                    @Override
                    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                        numberFieldListener(tdDiffs.get(tdDiffs.size()-1), oldValue,newValue);
                    }
                });
                points.get(points.size()-1).textProperty().addListener(new ChangeListener<String>() {
                    @Override
                    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                        numberFieldListener(points.get(points.size()-1), oldValue,newValue);
                    }
                });

                tdDiffEntrys.add(tdDiffs.get(tdDiffs.size()-1), 0, i+1);
                tdDiffEntrys.add(points.get(points.size()-1), 1,  i+1);
            }

        }

        private void numberFieldListener(TextField textField, String oldValue,String newValue) {

            if(!newValue.matches("\\d*")) {
                textField.setText(newValue.replaceAll("[^\\d]", ""));
            }
        }

    }

Thanks in advance, for taking the time.

L.Revan
  • 3
  • 3

1 Answers1

0

Your FlowPane is on top of your GridPane which stops mouse events from reaching the GridPane. In your FXML file you have the AnchorPane constraints for both your GridPane and FlowPane set to 10 (for top, left, bottom, and right). This means both nodes are taking up the same space in the AnchorPane. And since you add your FlowPane second the GridPane gets covered. Note that adding the GridPane second will most likely allow you to click the TextFields but will stop you from being able to click the Buttons.

Instead of an AnchorPane why don't you use something like a VBox? A VBox is designed for laying out nodes vertically. You could also replace the FlowPane with an HBox since that's the behavior you seem to be after. You'd end up with something like:

<Tab>
    <VBox>
        <GridPane>
            <!-- your GirdPane children -->
        </GridPane>
        <HBox>
            <!-- your buttons -->
        </HBox>
    </VBox>
</Tab>

I omitted attributes for brevity. You'd obviously set them to your desired values.

If you go this route you'll need to move your Label - the one with its text set to "Erhält Gewinnerteam bei Spielaufgabe maximale Punktzahl?:" - into the new HBox as the first child. That way it stays in line with the buttons.


Of course, you don't have to replace your AnchorPane. If you want to keep it, you'll have to figure out how to have the FlowPane's top anchor always be equal to how far the bottom of the GridPane is from the top. Since you currently have the GridPane's top anchor at 10 the FlowPane's top anchor would have to be something like 10 + gridPaneHeight. I'm not sure you can do this inside the FXML file which means you'd have to do it in your controller's initialize method. If your app is going to be resizable you may also have to update the top anchor whenever a resize occurs.

Slaw
  • 37,820
  • 8
  • 53
  • 80
  • You're the best! Thank you very much. I was getting closer to the feeling that something was overlapping, but could not quite nail it down to what it was. Thank you very much. – L.Revan Jun 18 '18 at 12:51