Pull to refresh

JavaFX, HelloWorld — продолжение

Reading time 6 min
Views 26K
HelloWorld из примера, предложенного Oracle в «Getting Started with JavaFX», на ПК с Windows. Развитие простейшего приложения до окна ввода логина и пароля. По-прежнему с использованием командной строки с приоткрытием недоговоренностей туториала, в котором приведен код этого приложения.



В предыдущем посте получилось завести пример из первого раздела Getting Started with JavaFX.
HelloWorld.java
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 Files\Java\jdk1.7.0_40\bin\javac" -d out -classpath "C:\Program Files\Java\jre7\lib\jfxrt.jar" src\helloworld\HelloWorld.java
@"C:\Program Files\Java\jdk1.7.0_40\bin\java" -classpath "C:\Program Files\Java\jre7\lib\jfxrt.jar;.\out" helloworld.HelloWorld
@"C:\Program Files\Java\jdk1.7.0_40\bin\javafxpackager" -createjar -appclass helloworld.HelloWorld -srcdir .\out -outfile HelloWorld -v
@"C:\Program Files\Java\jre7\bin\java.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)

А вот это уже не откомпилируется:
Ошибки компиляции
src\helloworld\HelloWorld.java:18: error: cannot find symbol
		GridPane grid = new GridPane();
		^
  symbol:   class GridPane
  location: class HelloWorld
src\helloworld\HelloWorld.java:18: error: cannot find symbol
		GridPane grid = new GridPane();
		                    ^
  symbol:   class GridPane
  location: class HelloWorld
src\helloworld\HelloWorld.java:19: error: cannot find symbol
		grid.setAlignment(Pos.CENTER);
		                  ^
  symbol:   variable Pos
  location: class HelloWorld
src\helloworld\HelloWorld.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).
Добавка к HelloWorld.java
	    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;

Такое вот у меня здесь произвольное отношение к звездочкам. Для учебных целей сойдет и так.

Теперь компилируется и работает. Надо коротенько разобрать наделанное:
  • 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.
Tags:
Hubs:
+2
Comments 9
Comments Comments 9

Articles