0

I've had a good search and either I'm not using the right terminology or this question hasn't appeared yet. I've been coding in Java for a few years and I've just started playing with Java FX over the last few weeks.

Context:

I'm trying to create an app that is effectively a quiz, but instead of having a new Pane/Tab for each question, I'd like to have them appear side by side.

I have created a questionController for a single question, but I'm unsure of the best way of creating many questionControllers that are all uniquely identifiable by the fx:id's.

I'd like my GUI to be scaleable so the user can select the number of questions displayed per round. I can't seem to work out how to do this without manually setting creating views with different numbers of questionControllers.

Things I've tried

  • Adding controller gridPane,
  • Importing the controller in the FXML

But this aren't scaleable as my buttons just become button0 - buttonN

If you require any more information, please let me know.

Question Controller.java

public class QuestionController implements Initializable {

    @FXML
    private ComboBox<String> chordCombo;

    @FXML
    private Label questionField;

    @FXML
    private Button submitButton;

    @FXML
    private ToggleGroup answerGroup;

    @FXML
    private RadioButton toggle0, toggle1, toggle2, toggle3, toggle4;

    @Override
    public void initialize(URL fxmlFileLocation, ResourceBundle resources) {

        submitButton.setOnAction((event) -> {
            System.out.println("Submit Logic");
        });

        answerGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
            public void changed(ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) {
                if (answerGroup.getSelectedToggle() != null) {
                    System.out.println(answerGroup.getSelectedToggle().toString());
                }
            }
        });

    }

QuestionController.fxml

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="235.0" prefWidth="203.0" styleClass="layout" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="uk.co.temp.QuestionController">
   <children>
      <BorderPane layoutX="-11.0" layoutY="35.0" prefHeight="235.0" prefWidth="203.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <bottom>
            <Button fx:id="submitButton" mnemonicParsing="false" text="Submit" BorderPane.alignment="CENTER">
               <padding>
                  <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
               </padding>
               <BorderPane.margin>
                  <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
               </BorderPane.margin>
            </Button>
         </bottom>
         <top>
            <Label fx:id="questionField" text="Insert Question Here" BorderPane.alignment="CENTER">
               <padding>
                  <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
               </padding>
               <BorderPane.margin>
                  <Insets left="10.0" right="10.0" top="10.0" />
               </BorderPane.margin>
            </Label>
         </top>
         <center>
            <GridPane BorderPane.alignment="CENTER">
              <columnConstraints>
                <ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
              </columnConstraints>
              <rowConstraints>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
              </rowConstraints>
               <children>
                  <RadioButton fx:id="toggle0" mnemonicParsing="false" text="Answer A">
                     <toggleGroup>
                        <ToggleGroup fx:id="answerGroup" />
                     </toggleGroup></RadioButton>
                  <RadioButton fx:id="toggle1" mnemonicParsing="false" text="Answer B" toggleGroup="$answerGroup" GridPane.rowIndex="1" />
                  <RadioButton fx:id="toggle2" mnemonicParsing="false" text="Answer C" toggleGroup="$answerGroup" GridPane.rowIndex="2" />
                  <RadioButton fx:id="toggle3" mnemonicParsing="false" text="Answer D" toggleGroup="$answerGroup" GridPane.rowIndex="3" />
                  <RadioButton fx:id="toggle4" mnemonicParsing="false" text="Answer E" toggleGroup="$answerGroup" GridPane.rowIndex="4" />
               </children>
               <padding>
                  <Insets top="10.0" />
               </padding>
            </GridPane>
         </center>
      </BorderPane>
   </children>
</AnchorPane>
2
  • Hey mate, how about assigning some variables to the buttons that then are being interpreted in the controller? So, instead of creating 40 controllers for 4 questions, your controller just reads Button.getQuestion() (ranges from 0-9) and Button.getAnswer (ranges from 0-4). Commented Jan 25, 2017 at 20:06
  • How are you loading QuestionController.fxml? If you want to load an arbitrary number of copies of it, then surely that's better done in Java (as opposed to FXML using <fx:include>). Then it's trivial to put all the controllers in a list or array. Commented Jan 25, 2017 at 20:12

1 Answer 1

1

I think you are looking for something like this:

TilePane pane = new TilePane(); // or whatever you are putting the questions in...

int numQuestions = ... ;

QuestionController[] controllers = new QuestionController[numQuestions];

for (int questionNumber = 0 ; questionNumber < numQuestions ; questionNumber++) {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/QuestionController.fxml"));
    pane.getChildren().add(loader.load());
    controllers[questionNumber] = loader.getController();
}

Obviously if the TilePane (or whatever) is defined in another FXML file and injected into another controller, you can put the same code in an event handler or initialize method, as needed, in that controller.

Sign up to request clarification or add additional context in comments.

1 Comment

That's perfect. Thank you. I knew it wouldn't be too difficult.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.