HelloWorld из примера, предложенного Oracle в «Getting Started with JavaFX», на ПК с Windows. Развитие простейшего приложения до окна ввода логина и пароля. По-прежнему с использованием командной строки с приоткрытием недоговоренностей туториала, в котором приведен код этого приложения.
В предыдущем посте получилось завести пример из первого раздела Getting Started with JavaFX.
package helloworld;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloWorld extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
}
Пример был скомпилирован, запущен, упакован в jar и запущен из jar с помощью командной строки.
@"C:Program FilesJavajdk1.7.0_40binjavac" -d out -classpath "C:Program FilesJavajre7libjfxrt.jar" srchelloworldHelloWorld.java
@"C:Program FilesJavajdk1.7.0_40binjava" -classpath "C:Program FilesJavajre7libjfxrt.jar;.out" helloworld.HelloWorld
@"C:Program FilesJavajdk1.7.0_40binjavafxpackager" -createjar -appclass helloworld.HelloWorld -srcdir .out -outfile HelloWorld -v
@"C:Program FilesJavajre7binjava.exe" -jar HelloWorld.jar
@pause
Каждая команда для удобства была спрятана в файл .cmd. Забавно, но наглядно. Продолжим использовать эти команды.
Во втором разделе предлагается сделать форму ввода логина и пароля, с блэкдже элементами управления. Попробуем развить имеющийся пример, оставив как есть пакет и класс &mdash helloworld.HelloWorld. jfxpub-get_started предлагает создать новый проект в NetBeans. Однако, пропустим первые три пункта из «Create the Project», а четвертый, замену тела метода «start» кодом из примера 2-1, применим к имеющемуся у нас файлу HelloWorld.java:
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX Welcome");
primaryStage.show();
}
Задача сводится к удалению строк с 18 по 29 и замене заголовка primaryStage. В таком виде файл откомпилируется и запустится, но такая ерунда получится, ничего интересного. Далее туториал предлагает использовать GridPane layout, потому что оно позволяет создавать столбцы и строки для размещения элементов управления, и это вроде как удобно. Послушаемся, и добавим код перед primaryStage.show():
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 25, 25, 25));
Scene scene = new Scene(grid, 300, 275);
primaryStage.setScene(scene)
А вот это уже не откомпилируется:
srchelloworldHelloWorld.java:18: error: cannot find symbol
GridPane grid = new GridPane();
^
symbol: class GridPane
location: class HelloWorld
srchelloworldHelloWorld.java:18: error: cannot find symbol
GridPane grid = new GridPane();
^
symbol: class GridPane
location: class HelloWorld
srchelloworldHelloWorld.java:19: error: cannot find symbol
grid.setAlignment(Pos.CENTER);
^
symbol: variable Pos
location: class HelloWorld
srchelloworldHelloWorld.java:22: error: cannot find symbol
grid.setPadding(new Insets(25, 25, 25, 25));
^
symbol: class Insets
location: class HelloWorld
4 errors
Итого: не найдены классы GridPane, Pos и Insets. А где их искать? Я тоже не знал. Но на сайте Oracle нашел вот такой «справочник». Из него ясно, что
GridPane - Class in javafx.scene.layout GridPane lays out its children within a flexible grid of rows and columns. Pos - Enum in javafx.geometry A set of values for describing vertical and horizontal positioning and alignment. Insets - Class in javafx.geometry A set of inside offsets for the 4 side of a rectangular area
Это значит, что надо добавить строчки импорта:
import javafx.scene.layout.GridPane;
import javafx.geometry.*;
Теперь файл откомпилируется и запустится, но все еще ничего интересного. Продолжим наполнять по рекомендациям туториала. Добавим код с элементами управления после строчки, устанавливающей свойство Padding таблицы grid, то есть, перед Scene scene = new Scene(grid, 300, 275).
Text scenetitle = new Text("Welcome");
scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
grid.add(scenetitle, 0, 0, 2, 1);
Label userName = new Label("User Name:");
grid.add(userName, 0, 1);
TextField userTextField = new TextField();
grid.add(userTextField, 1, 1);
Label pw = new Label("Password:");
grid.add(pw, 0, 2);
PasswordField pwBox = new PasswordField();
grid.add(pwBox, 1, 2);
Button btn = new Button("Sign in");
HBox hbBtn = new HBox(10);
hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
hbBtn.getChildren().add(btn);
grid.add(hbBtn, 1, 4);
final Text actiontarget = new Text();
grid.add(actiontarget, 1, 6);
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent e) {
actiontarget.setFill(Color.FIREBRICK);
actiontarget.setText("Sign in button pressed");
}
});
Получаем длинную простыню ошибок. Но они уже знакомы и понятны. Мы, оказывается, не в курсе, кто такие Text, Font, Label, Color и еще некоторые их друзья. Пороемся в упомянутом справочнике, посмотрим, в каких пакетах их родина. Добавим импорт:
import javafx.scene.text.*;
import javafx.scene.control.*;
import javafx.scene.paint.*;
import javafx.scene.layout.HBox;
Такое вот у меня здесь произвольное отношение к звездочкам. Пожалуй, лучше поменьше звездочек — чем меньше импорта, тем быстрее загрузится. Наверное. Для учебных целей сойдет и так. Кстати, import javafx.scene.* не импортирует автоматом javafx.scene.text.* и import javafx.scene.paint.*.
Теперь компилируется и работает. Надо коротенько разобрать наделанное:
- javafx.application.Application — главный класс приложения JavaFX.
- Его метод start() является точкой входа.
- Класс Stage — контейнер верхнего уровня для создания пользовательского интерфейса (окно).
- Класс Scene — контейнер следующего уровня и содержит все элементы.
- Наша сцена основана на GridPane, которая является как бы таблицей, в ячейках которой можно расположить элементы интерфейса. HGap и VGap определяют зазор между столбцами и строками соответственно. Padding задает зазор между краем таблицы и краем окна, который таблица постарается по возможности выдерживат. Строчка «grid.setGridLinesVisible(true);» покажет таблицу в окне — сделает ее линии видимыми.
- Интересно, что количество строк и столбцов таблицы не задается ее свойствами. Вместо этого мы располагаем некоторые элементы в определенных ячейках (задавая столбец и строку), а таблица «сама» разрастается до нужного количества. Метод grid.add добавляет элемент (первый параметр) в указанную ячейку (второй и третий параметр — столбец, строка). Можно добавить четвертый и пятый параметры (как при добавлении scenetitle) — сколько столбцов и строк использовать под элемент.
- Метод main() не является необходимым для приложений JavaFX, если JAR-файл создан с помощью javafxpackager (он внедряет JavaFX Launcher в JAR-файл). Однако, полезно оставить этот метод, чтобы иметь возможность запускать JAR-файл, созданный без JavaFX Launcher, например, в IDE с неполной интеграцией с JavaFX. Опять же, Swing-приложения, включающие код JavaFX, требуют метод main().
- HBox — это такая специальная панелька, которая позволяет задать выравнивание кнопки, засунутой в эту панельку, отличающимся от остальных элементов — с правого края.
- Остальное достаточно очевидно из кода.
Осталось раскрасить это все с помощью CSS, нарисовать с помощью FXML и объединить эти буквы вместе в одном приложении.
И еще один интересный момент, которым хотелось бы поделиться напоследок. В прошлом посте я упомянул, что если в коде приложения пакет обозвать package HelloWorld, то в папке ./out создастся папка HelloWorld, программа откомпилируется, но не запустится — не будет найден класс. Поправим обратно регистр символов в названии пакета — все снова заработает, хотя регистр символов папки останется «неправильным». ОС Windows на регистр имени папки совершенно плевать, и пересоздавать или переименовывать ее система не будет. На запуск программы из файла HelloWorld.class это не повлияет. А вот если теперь упаковать в .JAR и попытаться его выполнить — полезут ошибки. В архиве папка будет с неправильным (уже без кавычек) регистром двух символов, и этого достаточно, чтобы не найти главный класс приложения. Придется стереть папку ./out/HelloWorld, заново откомпилировать и создать .jar.
Автор: RomeoGolf