Как стать автором
Обновить

Окошко с кнопками на JavaFX:

Время на прочтение13 мин
Количество просмотров27K
Привет!

Мои знания в создании какого-либо графического интерфейса до недавних пор были нулевыми. Поэтому было принято решение немного пошерстить просторы Интернета и сотворить какое-нибудь окошко с какими-нибудь кнопками, при нажатии которых будет что-то происходить. Возможно, в этом тексте кто-то найдет ответы на возникшие когда-то вопросы; в то же время я надеюсь на серьезную и грамотную критику.

Что будет происходить?


Так как цель у меня — разобраться с JavaFX, нужно придумать какую-то функцию у нашего окна. Идея такая: создадим набор людей (предположим, что они работают в какой-то компании), для каждого из которых будет известно имя, возраст, зарплата и семейное положение. Наше окно, во-первых, будет выводить информацию о каждом из них, во-вторых, изменять зарплату какого-либо сотрудника, в-третьих, иметь возможность добавлять нового сотрудника, и, наконец, в-четверных, будет способно фильтровать сотрудников в зависимости от значений их атрибутов. В результате должно получиться что-то по типу этого:



Начинаем


Перво-наперво создаем главный класс Company, откуда будет происходить запуск приложения:

package company;

public class Company {

	public static void main(String[] args) {
		

	}

}

В этом классе будем расширять возможности класса Application. Из него нам нужен главным образом метод start(), в котором будет происходить основное действие (будем пропускать ошибки, возникающие в этом методе; другими словами, если что-то пойдет не так, наше окно не закроется, но в консоли появится StackTrace ошибки):
package company;

import javafx.application.Application;
import javafx.stage.Stage;

public class Company extends Application {
	
	public void start(Stage primaryStage) throws Exception {
		
	}

	public static void main(String[] args) {
		launch(args);
	}

}

Отлично. Для того, чтобы работать с представителями сотрудников компании, создадим класс User: объекты этого класса и будут выступать в роли сотрудников.

Класс User
package company;

public class User {

	User(String name, int age, int salary, boolean married) {
		this.name = name;
		this.age = age;
		this.salary = salary;
		this.married = married;
	}
	
	public void changeSalary(int x) {
		salary = (salary + x <= 0)? 0: salary + x;
	}
	
	public String toString() {
		return name;
	}
	
	public String getAge() {
		return String.valueOf(age);
	}
	
	public String getSalary() {
		return String.valueOf(salary);
	}
	public String getMarried() {
		return (married)? ("married"):("single");
	}
	
	String name;
	int age;
	int salary;
	boolean married;
}


Создаем


Пока при запуске приложение у нас не происходит ничего. Чтобы появилось хотя бы окошечко, его необходимо добавить. Это и сделаем.

package company;

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Company extends Application {
	
	public void start(Stage primaryStage) throws Exception {
		Scene scene = new Scene(root, WIDTH, HEIGHT);
		primaryStage.setTitle("Company");
		primaryStage.setScene(scene);
		primaryStage.show();
	}

	public static void main(String[] args) {
		launch(args);
	}
	
	Group root = new Group();
	
	final private int WIDTH = 1000;
	final private int HEIGHT = 600;

}

Что мы только что сделали: мы добавили сцену (scene) размером $WIDTH\times HEIGHT$, дали ей название «Company». На нашей сцене присутствует группа root, которая по своей сути является «контейнером», который будет содержать в себе все кнопки.

Добавим выпадающий список с нашими сотрудниками. Создадим HBox, в который положим наш выпадающий список ComboBox userBox и кнопку, которая будет выдавать информацию о сотруднике (сам HBox поместим в VBox):

package company;

import java.util.ArrayList;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Company extends Application {

	public void start(Stage primaryStage) throws Exception {

		users.add(new User("Alice", 20, 150, false));
		users.add(new User("Bob", 34, 300, true));
		users.add(new User("Peter", 18, 100, false));
		users.add(new User("Kate", 38, 300, true));
		users.add(new User("Steve", 31, 250, true));
		users.add(new User("Alan", 62, 500, true));
		users.add(new User("Julia", 33, 320, true));
		users.add(new User("Patric", 37, 300, true));
		users.add(new User("Alexander", 34, 280, true));
		users.add(new User("George", 28, 180, true));
		users.add(new User("Mary", 22, 190, false));

		userBox.getItems().addAll(users);

		root.getChildren().add(strings);

		strings.setPadding(new Insets(10, 30, 10, 30));
		strings.setSpacing(20);

		strings.getChildren().add(new Text("Select the user"));
		strings.getChildren().add(buttonBox);
		
		buttonBox.setSpacing(10);
		buttonBox.getChildren().add(userBox);

		Scene scene = new Scene(root, WIDTH, HEIGHT);
		primaryStage.setTitle("Company");
		primaryStage.setScene(scene);
		primaryStage.show();
	}

	public static void main(String[] args) {
		launch(args);
	}

	Group root = new Group();

	VBox strings = new VBox();

	HBox buttonBox = new HBox();

	ComboBox<User> userBox = new ComboBox<>();

	final private int WIDTH = 1000;
	final private int HEIGHT = 600;

	private ArrayList<User> users = new ArrayList<>();

}



Что такое VBox,HBox и ComboBox

HBox — это набор кнопок, текстов, полей для ввода, каждый объект которого расположен последовательно горизонтально. Аналогичный ему, VBox является тем же самым, но хранит свои объекты (children) по вертикали. Мы будем использовать следующую схему: создатим VBox, в который будем класть несколько HBox'ов, в каждый из которых положим последовательность кнопок и полей.

ComboBox — это сам просто выпадающий список.

Теперь мы хотим создать кнопку, которая будет выдавать информацию о выбранном сотруднике. Добавим саму кнопку (Button) и текстовое поле (TextField), в которое будет выводиться текст. Эти два объекта добавим в HBox:

package company;

/* */

public class Company extends Application {

	public void start(Stage primaryStage) throws Exception {

		/* */
		
		buttonBox.setSpacing(10);
		buttonBox.getChildren().add(userBox);
		buttonBox.getChildren().add(buttonGetInfo);
		buttonBox.getChildren().add(textInfo);

		/* */
	}

	/* */
	
	Button buttonGetInfo = new Button("Info");
	Text textInfo = new Text();

        /* */

}



Но пока эта кнопка ничего не делает. Чтобы она что-то делала, необходимо ей присвоить действие:

buttonGetInfo.setOnAction(new EventHandler<ActionEvent>() {
	@Override
	public void handle(ActionEvent e) {
		User u = (User) userBox.getSelectionModel().getSelectedItem();
		if (u != null) {
			textInfo.setText("Age is " + u.getAge() + ", " + 
			 "Salary is " + u.getSalary() + ", " + 
			 "Relationship: " + u.getMarried());
		} else {
			textInfo.setText("User not selected");
		}
	}
});



Дальнейшие действия


Абсолютно аналогичным образом добавляем еще два HBox'а: во втором будет происходить изменение зарплаты, в третьем — добавляние нового сотрудника. В силу того, что логика здесь абсолютно та же самая, пропустим объяснения этих моментов и сразу покажем результат:



Код
package company;

import java.util.ArrayList;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Company extends Application {

	public void start(Stage primaryStage) throws Exception {

		users.add(new User("Alice", 20, 150, false));
		users.add(new User("Bob", 34, 300, true));
		users.add(new User("Peter", 18, 100, false));
		users.add(new User("Kate", 38, 300, true));
		users.add(new User("Steve", 31, 250, true));
		users.add(new User("Alan", 62, 500, true));
		users.add(new User("Julia", 33, 320, true));
		users.add(new User("Patric", 37, 300, true));
		users.add(new User("Alexander", 34, 280, true));
		users.add(new User("George", 28, 180, true));
		users.add(new User("Mary", 22, 190, false));

		userBox.getItems().addAll(users);

		root.getChildren().add(strings);

		strings.setPadding(new Insets(10, 30, 10, 30));
		strings.setSpacing(20);

		strings.getChildren().add(new Text("Select the user"));
		strings.getChildren().add(buttonBox);
		strings.getChildren().add(new Text("Change the salary"));
		strings.getChildren().add(changeSalaryBox);
		strings.getChildren().add(new Text("Add new User"));
		strings.getChildren().add(addUserBox);

		buttonBox.setSpacing(10);
		buttonBox.getChildren().add(userBox);
		buttonBox.getChildren().add(buttonGetInfo);
		buttonBox.getChildren().add(textInfo);
		
		changeSalaryBox.setSpacing(10);
		changeSalaryBox.getChildren().add(buttonChangeSalary);
		changeSalaryBox.getChildren().add(howMuchChange);
		
		addUserBox.setSpacing(10);
		addUserBox.getChildren().add(new Text("Name: "));
		addUserBox.getChildren().add(name);
		addUserBox.getChildren().add(new Text("Age: "));
		addUserBox.getChildren().add(age);
		addUserBox.getChildren().add(new Text("Salary: "));
		addUserBox.getChildren().add(salary);
		addUserBox.getChildren().add(new Text("Married: "));
		addUserBox.getChildren().add(married);
		addUserBox.getChildren().add(buttonAddUser);
		
		buttonGetInfo.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				User u = (User) userBox.getSelectionModel().getSelectedItem();
				if (u != null) {
					textInfo.setText("Age is " + u.getAge() + ", " + 
									 "Salary is " + u.getSalary() + ", " + 
									 "Relationship: " + u.getMarried());
				} else {
					textInfo.setText("User not selected");
				}
			}
		}); 
		
		buttonChangeSalary.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				
				User u = (User) userBox.getSelectionModel().getSelectedItem();
				if(u != null) {
					u.changeSalary(Integer.parseInt(howMuchChange.getText()));
					textInfo.setText("Age is " + u.getAge() + ", " + 
							 "Salary is " + u.getSalary() + ", " + 
							 "Relationshp: " + u.getMarried());
					howMuchChange.clear();
				}  
			}
		});
		
		buttonAddUser.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				String m = married.getText();
				boolean mm = (m.equals("married"))? true:false;
				User u = new User(name.getText(), Integer.parseInt(age.getText()), 
										Integer.parseInt(salary.getText()), mm);
				users.add(u);
				userBox.getItems().addAll(u);
				name.clear();
				age.clear();
				salary.clear();
				married.clear();
			}
		});

		Scene scene = new Scene(root, WIDTH, HEIGHT);
		primaryStage.setTitle("Company");
		primaryStage.setScene(scene);
		primaryStage.show();
	}

	public static void main(String[] args) {
		launch(args);
	}

	Group root = new Group();

	VBox strings = new VBox();

	HBox buttonBox = new HBox();
	ComboBox<User> userBox = new ComboBox<>();
	Button buttonGetInfo = new Button("Info");
	Text textInfo = new Text();
	
	HBox changeSalaryBox = new HBox();
	Button buttonChangeSalary = new Button("Change salary");
	TextField howMuchChange = new TextField();
	
	HBox addUserBox = new HBox();
	Button buttonAddUser = new Button("Add User");
	TextField name = new TextField();
	TextField age = new TextField();
	TextField salary = new TextField();
	TextField married = new TextField();

	final private int WIDTH = 1000;
	final private int HEIGHT = 600;

	private ArrayList<User> users = new ArrayList<>();

}


Фильтры


Теперь добавим «фильтрацию» сотрудников по признакам. Опять же, списки для фильтров будем добавлять с использованием ComboBox по той же самой логике.

package company;

/* */

public class Company extends Application {

	public void start(Stage primaryStage) throws Exception {

		/* */
		
		ageFilterBox.getItems().addAll(
				"no matter", 
				"over 20",
				"over 30", 
				"over 40"
				);
		
		salaryFilterBox.getItems().addAll( 
				"no matter",
				"over 150",
				"over 250",
				"over 500"
				);
		
		relationshipFilterBox.getItems().addAll( 
				"no matter",
				"married",
				"single"
				);


		/* */
		strings.getChildren().add(filters);
		strings.getChildren().add(resultFilter);

		/* */
		
		filters.setSpacing(10);
		filters.getChildren().add(new Text("Age"));
		filters.getChildren().add(ageFilterBox);
		filters.getChildren().add(new Text("Salary"));
		filters.getChildren().add(salaryFilterBox);
		filters.getChildren().add(new Text("Relationship"));
		filters.getChildren().add(relationshipFilterBox);
		filters.getChildren().add(filter);
		
		/* */
		
		filter.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				int age;
				int index = ageFilterBox.getSelectionModel().getSelectedIndex();
				age = (index == 0)? 0: (index == 1)? 21: (index == 2)? 31: 41;
				
				int salary;
				index = salaryFilterBox.getSelectionModel().getSelectedIndex();
				salary = (index == 0)? 0 : (index == 1)? 151 : (index == 2)? 251:501;
				
				boolean relate;
				index = relationshipFilterBox.getSelectionModel().getSelectedIndex();
				relate = (index == 1)? true: (index == 2)? false: true;
				
				List<User> list;
				if(index != 0) {  list = users.stream().
				filter(u -> u.age > age).
				filter(u -> u.salary > salary).
				filter(u -> u.married == relate).
				collect(Collectors.toList()); }
				
				else { list = users.stream().
				filter(u -> u.age > age).
				filter(u -> u.salary > salary).
				collect(Collectors.toList()); }
				
				String res = "";
				for(User u: list) {
					res += u.toString() + ", ";
				}
				
				resultFilter.setText(res);
				
			}
		});

		/* */
	}

	/* */
	
	HBox filters = new HBox();
	ComboBox<String> ageFilterBox = new ComboBox<>();
	ComboBox<String> salaryFilterBox = new ComboBox<>();
	ComboBox<String> relationshipFilterBox = new ComboBox<>();
	Button filter = new Button("filter");
	Text resultFilter = new Text();

	/* */

}



Готово!

Полный код
Класс Company (главный)
package company;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Company extends Application {

	@Override
	public void start(Stage primaryStage) throws Exception {

		users.add(new User("Alice", 20, 150, false));
		users.add(new User("Bob", 34, 300, true));
		users.add(new User("Peter", 18, 100, false));
		users.add(new User("Kate", 38, 300, true));
		users.add(new User("Steve", 31, 250, true));
		users.add(new User("Alan", 62, 500, true));
		users.add(new User("Julia", 33, 320, true));
		users.add(new User("Patric", 37, 300, true));
		users.add(new User("Alexander", 34, 280, true));
		users.add(new User("George", 28, 180, true));
		users.add(new User("Mary", 22, 190, false));

		userBox.getItems().addAll(users);
		
		ageFilterBox.getItems().addAll(
				"no matter", 
				"over 20",
				"over 30", 
				"over 40"
				);
		
		salaryFilterBox.getItems().addAll( 
				"no matter",
				"over 150",
				"over 250",
				"over 500"
				);
		
		relationshipFilterBox.getItems().addAll( 
				"no matter",
				"married",
				"single"
				);

		root.getChildren().add(strings);
		
		strings.setPadding(new Insets(10, 30, 10, 30));
		strings.setSpacing(20);
		
		strings.getChildren().add(new Text("Select the user"));
		strings.getChildren().add(buttonBox);
		strings.getChildren().add(new Text("Change the salary"));
		strings.getChildren().add(changeSalaryBox);
		strings.getChildren().add(new Text("Add new User"));
		strings.getChildren().add(addUserBox);
		strings.getChildren().add(filters);
		strings.getChildren().add(resultFilter);

		buttonBox.setSpacing(10);
		buttonBox.getChildren().add(userBox);
		buttonBox.getChildren().add(buttonGetInfo);
		buttonBox.getChildren().add(textInfo);
		
		changeSalaryBox.setSpacing(10);
		changeSalaryBox.getChildren().add(buttonChangeSalary);
		changeSalaryBox.getChildren().add(howMuchChange);
		
		addUserBox.setSpacing(10);
		addUserBox.getChildren().add(new Text("Name: "));
		addUserBox.getChildren().add(name);
		addUserBox.getChildren().add(new Text("Age: "));
		addUserBox.getChildren().add(age);
		addUserBox.getChildren().add(new Text("Salary: "));
		addUserBox.getChildren().add(salary);
		addUserBox.getChildren().add(new Text("Married: "));
		addUserBox.getChildren().add(married);
		addUserBox.getChildren().add(buttonAddUser);
		
		filters.setSpacing(10);
		filters.getChildren().add(new Text("Age"));
		filters.getChildren().add(ageFilterBox);
		filters.getChildren().add(new Text("Salary"));
		filters.getChildren().add(salaryFilterBox);
		filters.getChildren().add(new Text("Relationship"));
		filters.getChildren().add(relationshipFilterBox);
		filters.getChildren().add(filter);
		

		Scene scene = new Scene(root, WIDTH, HEIGHT);
		primaryStage.setTitle("Company");
		primaryStage.setScene(scene);
		primaryStage.show();

		buttonGetInfo.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				User u = (User) userBox.getSelectionModel().getSelectedItem();
				if (u != null) {
					textInfo.setText("Age is " + u.getAge() + ", " + 
									 "Salary is " + u.getSalary() + ", " + 
									 "Relationship: " + u.getMarried());
				} else {
					textInfo.setText("User not selected");
				}
			}
		}); 
		
		buttonChangeSalary.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				
				User u = (User) userBox.getSelectionModel().getSelectedItem();
				if(u != null) {
					u.changeSalary(Integer.parseInt(howMuchChange.getText()));
					textInfo.setText("Age is " + u.getAge() + ", " + 
							 "Salary is " + u.getSalary() + ", " + 
							 "Relationshp: " + u.getMarried());
					howMuchChange.clear();
				}  
			}
		});
		
		buttonAddUser.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				String m = married.getText();
				boolean mm = (m.equals("married"))? true:false;
				User u = new User(name.getText(), Integer.parseInt(age.getText()), 
										Integer.parseInt(salary.getText()), mm);
				users.add(u);
				userBox.getItems().addAll(u);
				name.clear();
				age.clear();
				salary.clear();
				married.clear();
			}
		});
		
		filter.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent e) {
				int age;
				int index = ageFilterBox.getSelectionModel().getSelectedIndex();
				age = (index == 0)? 0: (index == 1)? 21: (index == 2)? 31: 41;
				
				int salary;
				index = salaryFilterBox.getSelectionModel().getSelectedIndex();
				salary = (index == 0)? 0 : (index == 1)? 151 : (index == 2)? 251:501;
				
				boolean relate;
				index = relationshipFilterBox.getSelectionModel().getSelectedIndex();
				relate = (index == 1)? true: (index == 2)? false: true;
				
				//resultFilter.setText(String.valueOf(age)  + " " + String.valueOf(salary)  + " "+ relate);
				
				List<User> list;
				if(index != 0) {  list = users.stream().
				filter(u -> u.age > age).
				filter(u -> u.salary > salary).
				filter(u -> u.married == relate).
				collect(Collectors.toList()); }
				
				else { list = users.stream().
				filter(u -> u.age > age).
				filter(u -> u.salary > salary).
				collect(Collectors.toList()); }
				
				String res = "";
				for(User u: list) {
					res += u.toString() + ", ";
				}
				
				resultFilter.setText(res);
				
			}
		});

	}

	public static void main(String[] args) {
		launch(args);
	}

	Group root = new Group();
	
	VBox strings = new VBox();
	
	HBox buttonBox = new HBox();
	HBox changeSalaryBox = new HBox();
	HBox addUserBox = new HBox();
	HBox filters = new HBox();
	
	ComboBox<User> userBox = new ComboBox<>();
	ComboBox<String> ageFilterBox = new ComboBox<>();
	ComboBox<String> salaryFilterBox = new ComboBox<>();
	ComboBox<String> relationshipFilterBox = new ComboBox<>();

	final private int WIDTH = 1000;
	final private int HEIGHT = 600;

	private ArrayList<User> users = new ArrayList<>();

	Button buttonGetInfo = new Button("Info");
	Text textInfo = new Text();
	
	Button buttonChangeSalary = new Button("Change salary");
	TextField howMuchChange = new TextField();
	
	Button buttonAddUser = new Button("Add User");
	TextField name = new TextField();
	TextField age = new TextField();
	TextField salary = new TextField();
	TextField married = new TextField();
	
	Button filter = new Button("filter");
	Text resultFilter = new Text();

}

Класс User
package company;

public class User {

	User(String name, int age, int salary, boolean married) {
		this.name = name;
		this.age = age;
		this.salary = salary;
		this.married = married;
	}
	
	public void changeSalary(int x) {
		salary = (salary + x <= 0)? 0: salary + x;
	}
	
	public String toString() {
		return name;
	}
	
	public String getAge() {
		return String.valueOf(age);
	}
	
	public String getSalary() {
		return String.valueOf(salary);
	}
	public String getMarried() {
		return (married)? ("married"):("single");
	}
	
	String name;
	int age;
	int salary;
	boolean married;
}




Что это было


Сама по себе программа не представляет никакой полезности и была написана исключительно для того, чтобы познакомиться с JavaFX и ее инструментами. В некотрых местах, например, при изменении зарплаты, не учитываются варианты, когда не выбран пользователь, или когда введена строка: в эти случаях будет появляться ошибка. То же самое касается полей, куда вводится информация при добавлении новых сотрудников. И, наконец, ошибка будет возникать, если не выбрано какое-то значение в любом из выпадающих списков. При желании, каждый может добавить свой «обход» этих моментов.

При написании фильтров, кстати, я использовал небезызвестные StreamAPI и $\lambda$-выражения, которые сокращают код, добавляют в него легкость понимания и свой шарм.

Источники:

  1. JavaFX 8 — Oracle Help Center
  2. Немного о создании и исторических модификациях JavaFX
  3. Замечательная статья vedenin1980 про StreamAPI и $\lambda$-выражения
Теги:
Хабы:
+5
Комментарии11

Публикации

Истории

Работа

Java разработчик
357 вакансий

Ближайшие события