Введение
Приветствую. Недавно столкнулся с новой и интересной для меня технологией на Java – JavaFX. Душа моя тянется больше к русскому языку, чем к английскому, поэтому я приступил к поиску русскоязычных туториалов по данной технологии. Меня ждало разочарование, так как в сети достаточно мало гайдов на эту тему. Пришлось все изучать самому, читая нудную документацию.
Я хочу написать серию небольших гайдов для тех, кто только знакомится с данной технологией. Статьи будут рассчитаны для новичков и будут иметь «подробно-поясняющий» характер.
Это моя первая статья, копирайтер с меня не очень хороший, поэтому прошу: не судите строго. Программист я тоже только начинающий и, если можно, не критикуйте код в пух и прах, но все советы обязательно выслушаю и учту.
О JavaFX
JavaFX – достаточно молодая технология, которая должна была прийти и затмить собой всем известную технологию Swing. Со дня своего основания она перетерпела множество изменений и на данный момент мы имеем достаточно стабильную и функциональную версию. Я не работал с SilverLight, но, судя по комментариям, JavaFX существенно уступает продукту Microsoft.
Я выделяю два главных преимущества описываемой технологии:
- упрощенное создание эффектов, анимации и других «красивых штучек»;
- поддержка CSS стилей, с помощью которых внешний вид каждого компонента можно настраивать очень гибко.
О чем тут?
Данная статья вас только познакомит с JavaFX. Здесь не будут показаны даже основные возможности технологии, так как это будет в последующих статьях. Статья покажет вам, как создаются окна, как сделать их нестандартной формы и… все.
Подготовка
Я пользуюсь средой разработки NetBeans, так как считаю ее достаточно удобной, красивой и мощной (и все это бесплатно). Чтобы не заморачиваться с установкой SDK, рекомендую просто скачать NetBeans с уже установленной платформой JavaFX.
Для тех, кто любит мышекликательное программирование, существует дополнительный инструмент, который называется JavaFX Scene Builder. После того, как вы его скачаете и установите, зайдите в NetBeans, в главном меню выберете «Сервис» -> «Параметры», далее переходите во вкладку «Java» -> «JavaFX». Там устанавливаете начальную страницу для Scene Builder путем выбора директории с Builder’ом. Теперь, после специальных манипуляций, вы сможете разрабатывать дизайн формы в данном редакторе.
Первый проект
Начнем создание нашего первого приложения. Выбираем в главном меню «Файл» -> «Создать проект». В представленных категориях выберем «JavaFX» и справа – «ПриложениеJavaFX»; далее все стандартно.
Созданный класс уже имеет некоторую функциональность. Ниже приведен код с комментариями.
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 TestClass extends Application {
/**
* Метод, с которого начинается выполнение программы. Аналог main() в стандартной программе на Java.
*/
@Override
public void start(Stage primaryStage) {
//Создание станартной кнопки.
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);
//Создание сцены. Выступает в роли контейнера (я ее приравниваю к панеле в Swing).
Scene scene = new Scene(root, 300, 250);
//primaryStage - объект нашего окна.
//Устанавливаем заголовок окна.
primaryStage.setTitle("Hello World!");
//Устанавливаем текущую сцену
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Создаем простенький проект
Теперь приступим к более сложной части, но и более интересной. Создадим небольшое окно входа в какое-либо приложение. Признаюсь честно: я его «выдрал» из своего курсового проекта, отдельно оно практической пользы не несет, но на нем я хочу показать несколько интересных моментов. Проект реализован на шаблоне MVC.
Ссылка на архив с необходимыми картинками.
Приступим
Создайте пакет «view». Кликаем ПКМ по созданному пакету, выбираем «Новый» -> «Класс Java». Называете, как желаете; я назову его «EnterScreen».
Наследуем его от класса «Application» и реализуем абстрактный метод.
package view;
import javafx.application.Application;
import javafx.stage.Stage;
public class EnterScreen extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
}
public static void main(String[] args) {
launch(args);
}
}
Создадим в нашем классе поле (его назначение будет видно ниже).
package view;
import javafx.application.Application;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class EnterScreen extends Application {
Stage mainStage = null;
@Override
public void start(Stage primaryStage) throws Exception {
mainStage = new Stage(StageStyle.TRANSPARENT);
}
public static void main(String[] args) {
launch(args);
}
}
Все действия по созданию окна я сделаю в одном методе start().Для начала я создам фон нашего окна и добавлю поля для ввода логина и пароля. Далее код с комментариями:
package view;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class EnterScreen extends Application {
public Stage mainStage = null;
@Override
public void start(Stage primaryStage) throws Exception {
//Создаем объект окна и при этом говорим, что оно будет без внешней границы и заголовка
mainStage = new Stage(StageStyle.TRANSPARENT);
//Создаем главный слой
StackPane root = new StackPane();
//screen - наш фон. Инициализируем его картинкой с прозрачностью.
ImageView screen = new ImageView("pict/EnterScreen.png");
//Добавляем наш фон на слой
root.getChildren().add(screen);
//Создаем еще один слой/менеджер компоновки
AnchorPane anPane = new AnchorPane();
//И добавляем его на главный слой
root.getChildren().add(anPane);
//Создаем текстовое поле и поле ввода пароля
TextField login = new TextField("login");
PasswordField password = new PasswordField();
//Устанавливаем размеры наших полей
login.setPrefSize(179, 24);
password.setPrefSize(179, 24);
//Теперь самое интересное: установка компонентов на свои места.
//Следующие методы задают расположение компонентов путем смещения их от левой части окна. Значения в пикселях, но параметр вещественный
AnchorPane.setLeftAnchor(login,519.0);
AnchorPane.setLeftAnchor(password, 519.0);
// Аналогично, только смещение идет от верха окна
AnchorPane.setTopAnchor(login, 297.0);
AnchorPane.setTopAnchor(password, 347.0);
//Теперь добавляем наши компоненты на слой
anPane.getChildren().add(login);
anPane.getChildren().add(password);
//Создаем сцену. Первый параметр: главный слой. Второй и третий: ширина и высота соответсвенно. Четвертый: цвет заливки (делаем его значением null,чтобы создать нестандартный вид формы)
Scene scene = new Scene(root, 1024, 768, null);
mainStage.setScene(scene);
mainStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Создайте еще один пакет под названием «pict» и поместите туда картинки.
Это уже рабочая часть, только у нас еще нет кнопок. Но есть уже два поля ввода и окно нестандартного вида.
Создайте еще два пакета: «controller» и «model». В первом у нас будут обработчики событий, а во втором маленькая бизнес-логика.
Теперь добавим кнопку выхода (реализуем правую кнопку).
package view;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class EnterScreen extends Application {
public Stage mainStage = null;
@Override
public void start(Stage primaryStage) throws Exception {
mainStage = new Stage(StageStyle.TRANSPARENT);
StackPane root = new StackPane();
ImageView screen = new ImageView("pict/EnterScreen.png");
root.getChildren().add(screen);
AnchorPane anPane = new AnchorPane();
root.getChildren().add(anPane);
TextField login = new TextField("login");
PasswordField password = new PasswordField();
login.setPrefSize(179, 24);
password.setPrefSize(179, 24);
AnchorPane.setLeftAnchor(login,519.0);
AnchorPane.setLeftAnchor(password, 519.0);
AnchorPane.setTopAnchor(login, 297.0);
AnchorPane.setTopAnchor(password, 347.0);
anPane.getChildren().add(login);
anPane.getChildren().add(password);
//Создаем картинку с изображением нашей кнопки (картинка имеет прозрачность)
ImageView rightButton = new ImageView("pict/RightButton.png");
//Добавляем обработчики событий для карттинки-кнопки
rightButton.setOnMouseEntered(new EnterScreenEvents.OnMouseEnterRB());
rightButton.setOnMouseExited(new EnterScreenEvents.OnMouseExitRB());
rightButton.setOnMouseClicked(new EnterScreenEvents.OnMouseClickedRB(this));
//Задаем расположение картинки-кнопки
AnchorPane.setLeftAnchor(rightButton, 567.0);
AnchorPane.setTopAnchor(rightButton, 420.0);
//Добавляем картинку-кнопку на слой
anPane.getChildren().add(rightButton);
Scene scene = new Scene(root, 1024, 768, null);
mainStage.setScene(scene);
mainStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Наше приложение работать не будет, так как еще не созданы классы-обработчики. Что ж, давайте их создадим. В пакете «controller» создайте класс EnterScreenEvents. В данном классе создадим статические внутренние классы, которые и будут обработчиками. Все они будут реализовывать интерфейс «EventHandler». Далее следуйте по следующему коду:
package controller;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.image.ImageView;
import view.EnterScreen;
public class EnterScreenEvents {
public static class OnMouseEntered implements EventHandler{
@Override
public void handle(Event event) {
ImageView iv = (ImageView) event.getSource();
iv.setImage(resManager.getRightPressedButtonImage());
}
}
public static class OnMouseExit implements EventHandler{
@Override
public void handle(Event event) {
ImageView iv = (ImageView) event.getSource();
iv.setImage(resManager.getRightButtonImage());
}
}
public static class OnMouseClickedRB implements EventHandler{
private EnterScreen ES = null;
public OnMouseClickedRB(EnterScreen ES) {
this.ES = ES;
}
@Override
public void handle(Event event) {
}
}
}
Классы-обработчики созданы. Теперь реализуем модель. В модели мы сделаем менеджер ресурсов, у которого будут статические методы для загрузки изображений и возврата объектов с ними. Создайте в пакете «model» класс «resManager» и опишите, как показано ниже:
package model;
import javafx.scene.image.Image;
public class resManager {
public static Image getEnterScreenBackground(){
return new Image("pict/EnterScreen.png");
}
public static Image getRightButtonImage(){
return new Image("pict/RightButton.png");
}
public static Image getRightPressedButtonImage(){
return new Image("pict/RightPressedButton.png");
}
}
Теперь картинка-кнопка работает, но еще не закрывает окно. Не забудьте в представлении изменить жесткую ссылку фона на метод из модели. Теперь создадим метод в окне, который сможет его закрывать. Добавьте в класс такие строчки кода:
public void close() {
Platform.runLater(new closing());
}
private class closing implements Runnable {
@Override
public void run() {
mainStage.close();
}
}
Почему я организовал закрытие именно так? Другого пути я не нашел, так как в иных случаях выбрасывается исключение о недостатке привилегий у потока (только поток приложения и платформы может закрыть окно или выполнить другую операцию по смене состояния окна). Не забудьте добавить в обработчик клика мышки метод, закрывающий окно.
Заключение
Вот небольшое и нестандартное окно входа готово. Правда его функционал состоит только в том, чтобы оно закрывалось, но писать тут бесконечно тоже не получится. Если моя статья не будет опозорена в комментариях, то я продолжу цикл и расскажу про возможности технологии, уже более глубокие и эффективные: работа с CSS-стилями, основными компонентами, создание эффектов и анимации, а также многое другое.
Спасибо за внимание. До следующих встреч.
P.S> Отдельное спасибо Георгию Тихолазу (XMAITER) за создание кнопки и фонового рисунка.
P.S.S> Ссылка на экспортированный в ZIP-файл проект.
Автор: MorrisDecker
Здравствуйте, я очень позитивно воспринял Ваш материал. Сейчас хочу создать универсальную информационную систему. Для этого хочу использовать фреймы как набор атрибутов описания объектов и процессов, на основе которых создаю конкретные описания объектов или процессов. Некоторые атрибуты принимают собственные значения, а другие атрибуты просто ссылаются на существующие значения других атрибутов. Базу данных спроектировал на основе постгрескуль. Начал осваивать яву и пишу программки с ориентацией на TreeView. Могу ли я получить какую-то консультацию у вас по этой тематике.
С уважением, Борис.