JavaFX наглядное создание простого приложения и нативная упаковка в Eclipse
Сегодня я вам расскажу, как поэтапно с нуля создать простое приложение на JavaFX, что для этого потребуется, покажу как сделать установщик Windows (msi) для вашего приложения.
Для начала нам потребуется среда разработки, будем использовать Eclipse, на данный момент самая последняя версия называется Neon (релиз 22 июня 2016 года) его можно скачать здесь.
Далее качаем инсталлятор, выбираем версию для Java разработчиков, будет предложен путь по умолчанию С:\Users\%USERNAME%\eclipse, экзешник будет лежать там в каталоге java-neon\eclipse.
После запуска Eclipse сразу будет предложено выбрать рабочую директорию, можно оставить дефолтную, только следите, чтобы путь до нее не содержал русских букв, в частности из-за %USERNAME%, иначе в дальнейшем могу возникнуть проблемы с этими путями. Если вы все-таки выбрали такую директорию в качестве рабочего пространства, не беда, ее можно поменять в последующем: File -> Switch Workspace -> Other…
Теперь для разработки JavaFX приложений и последующей сборки нам потребуется плагин для Eclipse, подробную инструкцию по установке можно найти здесь: www.eclipse.org/efxclipse/install.html
Важно! Перед тем как приступать к созданию приложения, необходимо стандартно применяемую JRE без компилятора поменять на JDK. Подключим предварительно скачанную JDK и сделаем ее дефолтной: заходим в настройки Window->Preferences:
Выбираем стандартную виртуальную машину:
Указывает путь к директории на вашем компьютере, где лежит, предварительно скаченная версия JDK:
После нажатия на Finish, устанавливаем JDK как дефолтный:
Также укажем ее как дефолтную для JavaSE-1.8:
Теперь приступим к самому интересному, создадим новый проект JavaFX File->New->Project…
Настраиваем проект, думаю тут все очевидно:
Напишем наше небольшое приложение (в директории с Main.java должны лежать: иконка favicon-16×16.png и звук click.wav):
package application; import java.net.URL; import javafx.application.Application; import javafx.geometry.Insets; import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.scene.Cursor; import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.control.Alert.AlertType; import javafx.scene.layout.AnchorPane; import javafx.scene.media.AudioClip; public class Main extends Application < @Override public void start(Stage primaryStage) < try < AnchorPane root = new AnchorPane(); root.setPadding(new Insets(5.0)); Button button = createButton(); AnchorPane.setBottomAnchor(button, 0.0); AnchorPane.setTopAnchor(button, 0.0); AnchorPane.setBottomAnchor(button, 0.0); AnchorPane.setRightAnchor(button, 0.0); AnchorPane.setLeftAnchor(button, 0.0); root.getChildren().add(button); Scene scene = new Scene(root, 300, 300); primaryStage.setTitle("Хабрахабр"); primaryStage.getIcons().add(new Image(getResource("favicon-16x16.png").toExternalForm())); primaryStage.setScene(scene); primaryStage.show(); >catch(Exception e) < e.printStackTrace(); >> private Button createButton() < Button result = new Button("Жми"); result.setTooltip(new Tooltip("Не бойся, жми!")); result.setCursor(Cursor.HAND); result.setOnMouseClicked(mouseEvent ->< new AudioClip(getResource("click.wav").toString()).play(); showDialog(); >); return result; > private URL getResource(String name) < return getClass().getResource(name); >private void showDialog() < Alert dialog = new Alert(AlertType.INFORMATION); dialog.initStyle(StageStyle.UTILITY); dialog.setTitle("Инфо"); dialog.setHeaderText("Привет мир!"); dialog.showAndWait(); >public static void main(String[] args) < launch(args); >>
Отлично, теперь нам надо запаковать это приложения для конечного пользователя, в корневой директории лежит предназначенный для этого файл build.fxbuild, который генерирует xml файл, использующийся в свою очередь сборщиком Ant, настроим этот файл:
Если нажать в правой части Generate ant build.xml only, то создается корневой папке создается конфигурационный билд для Ant build\build.xml перед тем, как запускать его, необходимо скачать Wix Toolset с ресурса: wix.sf.net (если генерируется exe, то для него требуется Inno Setup с ресурса jrsoftware.org) иначе Ant сгенерирует все, кроме нужного нам .msi в консоли при сборке напишет про это. После того как вы установили Wix, необходимо прописать в переменных среды путь к bin директории и перегрузить компьютер.
После сборки появится установщик msi, который можно запускать (приложение по дефолты ставится в C:\Program Files\HabrApp):
Эта стать-памятка про нативную сборку установочного файла средствами Eclipse, она не разбирает тонкостей JavaFx. Всем спасибо за внимание.
Java15/Examples
This is an informal page listing examples of features that are implemented by the Java 15 Support, which can be installed from the Marketplace. You are welcome to try out these examples. If you find bugs, please file a bug after checking for a duplicate entry here
Watch out for additional examples being added soon.
- TextBlock is standard features in Java 15.
- Records is also another preview feature in Java 15. They are not enabled by default and can by enabled using —enable-preview.
- Instanceof Pattern Matching is also another preview feature in Java 15. They are not enabled by default and can by enabled using —enable-preview.
- In Eclipse, —enable-preview can be enabled from the Preferences. It is implicitly added while launching a java program if the feature has been enabled for the project/workspace.
public class Test { public static void main(String[] args) { String tb = """ Hello World """; System.out.println(tb); } }
public class Test { public static void main(String[] args) { String tb = """ Hello World ""; > >
@SuppressWarnings("preview") record Point(int x, int y) { } public class X1 { public static void main(String[] args) { Point p = new Point(100, 200); System.out.println(p.x()); } }
class X2 { public static void main(String[] args) { System.out.println(0); } @SuppressWarnings("preview") record Point(int x, int y) { } }
class X3 { public static void main(String[] args) { System.out.println(0); } } @SuppressWarnings("preview") final record Point(int x, int y) { }
@SuppressWarnings("preview") record R() { } class X4 { public static void main(String[] args) { System.out.println(new R().hashCode()); } }
import java.lang.annotation.Target; import java.lang.annotation.ElementType; @Target({ ElementType.PARAMETER }) @interface MyAnnot { } @SuppressWarnings("preview") record R(@MyAnnot()int i, int j) { } class X5 { public static void main(String[] args) { System.out.println(new R(100, 200).hashCode() != 0); } }
class X6 { @SuppressWarnings("preview") public static void main(String[] args) { record R(int x,int y){} R r = new R(100, 200); System.out.println(r.x()); } }
@SuppressWarnings("preview") abstract record Point(int x, int y){ } class X7 { public static void main(String[] args){ System.out.println(0); } }
@SuppressWarnings("preview") record Point1(int myInt, char myChar) implements I { public Point1 { this.myInt = myInt; this.myChar = myChar; } } public class X8 { public static void main(String[] args) { System.out.println(0); } } interface I { }
class record { public static void main(String[] args) { System.out.println(0); } }
@SuppressWarnings("preview") public class X { public boolean isBlank(Object o) { return (o instanceof String s) && s.isBlank(); } }
@SuppressWarnings("preview") public class X { public int size(Object obj) { if (obj instanceof String s) { return s.le } return -1; } }
package p; @SuppressWarnings("preview") public class X { public int size(Object obj) { if (obj instanceof String s) { return s.length(); } return s.length(); // s not in scope } }
@SuppressWarnings("preview") public class X { public void foo(Object obj) { String s = null; if (obj instanceof Integer s) { } else if (obj instanceof String) { } } }
@SuppressWarnings("preview") sealed class Y permits X { } @SuppressWarnings("preview") non-sealed class X extends Y { public static void main(String[] args) { System.out.println(0); } }
@SuppressWarnings("preview") sealed interface I extends SI { } @SuppressWarnings("preview") non-sealed class X implements SI { public static void main(String[] args) { System.out.println(0); } } @SuppressWarnings("preview") sealed interface SI permits X,I { } @SuppressWarnings("preview") non-sealed interface I2 extends I { }
@SuppressWarnings("preview") sealed class X permits Y { public static void main(String[] args) { System.out.println(100); } } @SuppressWarnings("preview") non-sealed class Y extends X { }
@SuppressWarnings("preview") sealed public class XT> { public static void main(String[] args) { System.out.println(100); } } @SuppressWarnings({ "preview", "rawtypes" }) non-sealed class Y extends X { }
@SuppressWarnings("preview") sealed public sealed class X { public static void main(String[] args) { System.out.println(100); } }
— Sealed class lacks the permits clause and no top level or nested class from the same compilation unit declares X as its direct superclass
— Duplicate modifier for the type X»