В данном учебном примере предлагается создать тестовые данные прямо в главном классе приложения, а также вызывать из него метод JavaFX-контроллера setMainApp(MainApp mainApp)
, который даст доступ к данным personData
. Другими словами, контроллер и главный класс приложения жёстко связаны.
Приведённый ниже код пока что НЕ мой:
MainApp.java
public class MainApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private ObservableList<Person> personData = FXCollections.observableArrayList();
public MainApp() {
personData.add(new Person("Hans", "Muster"));
personData.add(new Person("Ruth", "Mueller"));
// ... и другие
}
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("AddressApp");
initRootLayout();
showPersonOverview();
}
public static void main(String[] args) {
launch(args);
}
// ...
public void showPersonOverview() {
try {
// Загружаем сведения об адресатах.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/PersonOverview.fxml"));
AnchorPane personOverview = (AnchorPane) loader.load();
// Помещаем сведения об адресатах в центр корневого макета.
rootLayout.setCenter(personOverview);
// Даём контроллеру доступ к главному приложению.
PersonOverviewController controller = loader.getController();
controller.setMainApp(this);
} catch (IOException e) {
e.printStackTrace();
}
}
/** Возвращает данные в виде наблюдаемого списка адресатов. */
public ObservableList<Person> getPersonData() {
return personData;
}
}
PersonOverviewController.java
public class PersonOverviewController {
// ...
// Ссылка на главное приложение.
private MainApp mainApp;
public PersonOverviewController() {}
/**
* Инициализация класса-контроллера. Этот метод вызывается автоматически
* после того, как fxml-файл будет загружен.
*/
@FXML
private void initialize() {
// Инициализация таблицы адресатов с двумя столбцами.
firstNameColumn.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
lastNameColumn.setCellValueFactory(cellData -> cellData.getValue().lastNameProperty());
}
/** Вызывается главным приложением, которое даёт на себя ссылку. */
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
// Добавление в таблицу данных из наблюдаемого списка
personTable.setItems(mainApp.getPersonData());
}
}
Модифицируя данное учебное приложение, я решил получать данные не из главного класса, из Spring-бина PeopleRepository
:
public class PeopleRepository implements IPeopleRepository {
public ObservableList<Person> getPeople() {
ObservableList<Person> people = FXCollections.observableArrayList();
people.add(new Person( "Muster", "Hans"));
people.add(new Person("Mueller", "Ruth"));
// ... и другие
return people;
}
}
Я не знаю, зачем ещё кроме данных нам нужен доступ к главному классу приложения, но теперь, когда мы можем получить данные из бина, setMainApp
нам вроде как больше не нужен. Исходя из того, что мы загружаем FXML с помощью FXMLLoader
в главном классе приложения, связь между главным классом приложения и View есть, а во View есть ссылка на соответствующие контроллеры. На основе этой логики, я упростил PersonOverviewController
следующим образом:
public class PersonOverviewController {
@FXML
private TableView<Person> peopleTable;
@FXML
private TableColumn<Person, String> familyNameColumn;
@FXML
private TableColumn<Person, String> givenNameColumn;
@FXML
private Label familyNameLabel;
@FXML
// ... и другие компоненты
public PersonOverviewController() {}
@FXML
private void initialize() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml");
IPeopleRepository peopleRepository = (PeopleRepository) applicationContext.getBean("PeopleRepository");
familyNameColumn.setCellValueFactory(cellData -> cellData.getValue().familyNameProperty());
givenNameColumn.setCellValueFactory(cellData -> cellData.getValue().givenNameProperty());
peopleTable.setItems(peopleRepository.getPeople());
}
}
Хотя приложение собирается Maven-ом без ошибок, метод initialize()
просто-напросто не вызывается (System.out.println("test");
в данном метода не выполняется). Естественно, в таблице никаких данных нет. Что я сделал неправильно?
Полный листинг главного класса приложения:
public class MainApp extends javafx.application.Application {
private Stage primaryStage;
private BorderPane rootLayout;
public static void main (String[] args) {
launch();
}
@Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("JavaFX тест");
initializeRootLayout();
showPersonOverview();
}
private void initializeRootLayout() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/RootLayout.fxml"));
try {
rootLayout = loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException exception) {
exception.printStackTrace();
}
}
private void showPersonOverview() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/PersonOverview.fxml"));
try {
AnchorPane personOverview = loader.load();
rootLayout.setCenter(personOverview);
} catch (IOException exception) {
exception.printStackTrace();
}
}
}
Не понял до конца, в чём дело, но всё разрешилось, когда я изменил способ поиска шаблонов.
В туториале изначально был предложен такой способ поиска шаблонов:
loader.setLocation(MainApp.class.getResource("view/PersonOverview.fxml"));
В JavaFX 11 это не работает. Кроме того,
Создайте новый класс внутри пакета view и назовите его PersonOverviewController.java. (Мы должны разместить этот класс-контроллер в том же пакете, где находится файл разметки PersonOverview.fxml, иначе Scene Builder не сможет его найти.
тоже нынче не актуально. Рабочим же является это решение (ссылка на англоязычный оригинал):
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/main.fxml"));
Parent content = loader.load();
Шаблон main.fxml будет найден, если его положить в папку src/main/resources
. После того, как я это сделал, основная проблема данного вопроса была также решена.
Как сделать генерацию чисел от 0 до 1Если выпадет 0 то человек победил и в консоле выводит это
использую JTabbedPane в "текстовом редакторе" и хне знаю как получить содержимое вкладки JTabbedPaneПробовал делать через getTabComponentAt() он возвращает...
У меня есть переменная d которую пользователь задает сам, она принимает значения от 1 до 99, каждое число должно исполнять свою роль, например...