Нужна помощь с динамическим размещением элементов на панели в JavaFX
Я только начал осваивать JavaFX.
Разрабатываю приложение, в котором можно создавать различные голосования. У меня есть задача - динамически размещать в панели названия голосований и кнопки, по которым можно будет перейти в другое окно и посмотреть подробную информацию о голосовании.
Насколько я понял технологию, нужно в обработчике события окна авторизации выгрузить данные с БД, затем загрузить FXML файл моего меню, и туда прямо из кода вставить мои кнопки и названия.
Проблема возникла в том, что у меня не получается получить панель, в которую я хочу вставить эти элементы. Правильный ли у меня ход мыслей касательно алгоритма добавления элементов, и где я ошибся?
Контроллер окна авторизации
package sample;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Objects;
public class LogInController
{
@FXML
private TextField loginField;
@FXML
private PasswordField passwordField;
@FXML
private Button loginButton;
@FXML
private Button signUpButton;
@FXML
private Text notCorrectInfo;
@FXML
void initialize()
{
loginButton.setOnAction(actionEvent -> {
try {
if (Database.authUser(loginField.getText(), passwordField.getText()))
{
Stage stage = (Stage) ((Node) actionEvent.getSource()).getScene().getWindow();
Parent parent = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("assets/menu.fxml")));
// Adding to votesPane elements
Scene scene = new Scene(parent);
AnchorPane pane = (AnchorPane) scene.lookup("#votesPane"); // Тут не получается получить панель (pane = null)
for (Vote vote :
Database.loadVotes()) {
Label name = new Label(vote.getName());
name.setTextFill(Color.BLACK);
pane.getChildren().add(name);
pane.getChildren().add(new Button("Открыть"));
}
stage.setScene(scene);
}
else
notCorrectInfo.setVisible(true);
} catch (IOException | ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
});
}
}
FXML-файл меню, куда я хочу динамически вставить элементы
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" styleClass="outerPane" stylesheets="@style.css"
xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="sample.MenuController">
<Button fx:id="createVoteButton" layoutX="435.0" layoutY="21.0" mnemonicParsing="false" prefHeight="38.0"
prefWidth="144.0" styleClass="greenButton" text="Create vote">
<font>
<Font name="Segoe UI" size="20.0"/>
</font>
</Button>
<ScrollPane hbarPolicy="NEVER" layoutX="18.0" layoutY="80.0" prefHeight="306.0" prefWidth="565.0"
styleClass="scrollPane">
<AnchorPane fx:id="votesPane" minHeight="0.0" minWidth="0.0" prefHeight="306.0" prefWidth="565.0"
styleClass="scrollPane">
</AnchorPane>
</ScrollPane>
</AnchorPane>
Ответы (1 шт):
Прежде чем мы начнем :
Замечания по коду :
ScrollPane отсутствует fx:id
Button не нужен fx:id, назначьте ему setOnAction. Имя метода должно соответствовать имени метода в контроллере.
Вам не нужен lookup, у вас есть ГЛАВНАЯ ПАНЕЛЬ, прописанная в FXML, для этого fx:id и существует : связать ваш элемент с кодом.
Настоятельно рекомендую почитать про MVC в JavaFX
public class MenuController { @FXML private AnchorPane mainPane; @FXML private Button createVoteButton; @FXML private AnchorPane votesPane; public void initialize(){ createVoteButton.setOnAction(e->pushButton()); } private void pushButton(){ System.out.println("Нажатие кнопки!!!!"); // Можно заменить на setOnAction в SceneBuilder generete(); } private void generete(){ // Сделующий цикл генерирует случайное кол-во кнопок // Можно вызвать в блоке initialize, т.е загрузится само. for (int i = 0 ; i < randomDeleteThisTest(); i++){ int finalI = i; Platform.runLater(()->{ Button button = new Button("Button # = " + finalI); button.setLayoutX(finalI*50); // AnchorPane накладывает кнопки друг на друга без // явного указания setLayoutX mainPane.getChildren().add(button); }); // Platform.runLater(()->{ // Ваш код }); // Эта конструкция позволяет ОТЛОЖИТЬ изменения визуальной информации // они не происходят сию минуту // Использовать такое, без проверок, не совсем хорошо // Но сейчас в качестве примера сойдёт } } private static int randomDeleteThisTest(){ Random r = new Random(); return r.nextInt(15); }}
/////////////////////////////// FXML /////////////////////////////////
<AnchorPane prefHeight="400.0" prefWidth="600.0" styleClass="outerPane"
xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="sample.MenuController"
fx:id="mainPane">
<Button fx:id="createVoteButton" layoutX="435.0" layoutY="21.0" mnemonicParsing="false" prefHeight="38.0"
prefWidth="144.0" styleClass="greenButton" text="Create vote">
<font>
<Font name="Segoe UI" size="20.0"/>
</font>
</Button>
<ScrollPane hbarPolicy="NEVER" layoutX="18.0" layoutY="80.0" prefHeight="306.0" prefWidth="565.0"
styleClass="scrollPane">
<AnchorPane fx:id="votesPane" minHeight="0.0" minWidth="0.0" prefHeight="306.0" prefWidth="565.0"
styleClass="scrollPane">
</AnchorPane>
</ScrollPane>