注:我也是JAVA FX的初学者之一,自己在学习的时候踩了许多的坑,中文英文的资料查了不少,但是觉得FX技术和其他热门技术相比,教程还是太少了。这里就尽量做一点微小的贡献吧
注:写这个只是为了说明我的环境,使用和我的不一样的环境在理解这篇教程的时候并没有什么问题,例如使用Windows平台、使用Oracle JDK(这样就不需要再单独安装FX组件了,可以不用MAVEN)、使用Oracle的SceneBuilder。可能唯一一个比较影响体验的就是不使用IDEA而是使用eclipse了
SceneBuilder下载地址:https://gluonhq.com/products/scene-builder/#download
IDEA->File->Settings->Language->Java FX->输入SceneBuilder的路径
如果是Linux环境,你会发现这个路径还不好找,我是使用locate SceneBuilder
命令找到的,路径是:/opt/SceneBuilder/SceneBuilder
因为OpenJDK没有FX环境,需要我们自己安装。为了便于管理,我们在这里使用MAVEN
在pom.xml文件中加入以下依赖:
<dependencies>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-fxml -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>13</version>
</dependency>
</dependencies>
这里只写一些我已经探索出来的设计流程,如果有不对的请指出~
设计第一个加载的界面。这个可以放在入口的java类的main方法下,举个例子:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("Entry.fxml"));//从Resources中获取资源
primaryStage.setTitle("Course Registration System");
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
}
对于每一个Panel,我们要指定一个触发器类,这个是放在该fxml文件中的,例如IDEA中默认创建的就是AnchorPane对象,在它那一行就能找到:fx:controller="sample.MainController"
,这个MainController就是我创建的一个类
之后,我们可以对该panel下各个控件设计触发事件后的反映,这个可以在SceneBuilder中填写,在Code那一栏下面。设计了之后,它就会到我们指定的那个触发器类下寻找这个方法,如果没有的话IDEA会提示你创建
注意,触发器类可以创建多个,这样更便于管理,降低耦合度
在触发器中获取fxml中的控件对象
有时候,我们需要在事件相应中获取对象的值,例如设计登录页面时点击'提交'的按钮,我们需要知道输入框的字符串。这时候我们可以在触发器中获取这些元素,前提是我们为这些控件输入了fx:id,它是全局性的,不允许重复。例如我们可以通过声明:
@FXML
private TextField username;
@FXML
private TextField password;
获取两个TextField对象下的值:
usernameString=username.getText();
passwordString=password.getText();
页面跳转
我们需要为每一个页面设计一个Java类,例如我设计了一个SignIn_Student.java:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class SignIn_Student extends Application{
private String usernameString;
private String passwordString;
@Override
public void start(Stage stage) throws Exception{
Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("SignIn_Student.fxml"));//加载页面
Scene anotherScene=new Scene(root);
stage.setTitle("Please log in");
stage.setScene(anotherScene);
stage.show();
}
}
TableView的使用
这个控件用起来着实有点麻烦。折腾了好久。
我们需要创建一个类来表示要储存的数据,例如我这里创建了一个Courses.class:(下面的get和set方法是IDEA自动生成的)
package sample;
import javafx.beans.property.*;
import java.time.LocalDate;
import java.time.LocalTime;
public class Courses {
private final StringProperty department;
private final StringProperty lecturer;
private final ObjectProperty<LocalDate> Time;
private final StringProperty location;
private final IntegerProperty ID;
public Courses(String name, String department, String lecturer, LocalDate time, String location, Integer ID) {
this.name = new SimpleStringProperty(name);
this.department = new SimpleStringProperty(department);
this.lecturer = new SimpleStringProperty(lecturer);
this.Time = new SimpleObjectProperty<LocalDate>(time);
this.location = new SimpleStringProperty(location);
this.ID = new SimpleIntegerProperty(ID);
}
//String,String,String, Date,String,Integer
private final StringProperty name;
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public String getDepartment() {
return department.get();
}
public StringProperty departmentProperty() {
return department;
}
public void setDepartment(String department) {
this.department.set(department);
}
public String getLecturer() {
return lecturer.get();
}
public StringProperty lecturerProperty() {
return lecturer;
}
public void setLecturer(String lecturer) {
this.lecturer.set(lecturer);
}
public LocalDate getTime() {
return Time.get();
}
public ObjectProperty<LocalDate> timeProperty() {
return Time;
}
public void setTime(LocalDate time) {
this.Time.set(time);
}
public String getLocation() {
return location.get();
}
public StringProperty locationProperty() {
return location;
}
public void setLocation(String location) {
this.location.set(location);
}
public int getID() {
return ID.get();
}
public IntegerProperty IDProperty() {
return ID;
}
public void setID(int ID) {
this.ID.set(ID);
}
}
我们需要实现的效果是,在加载这个页面时,表格中自动加载数据。填写我们创建的控制器类如下:
package sample;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import java.time.LocalDate;
public class MainController {
@FXML
private TextField username;
@FXML
private TextField password;
@FXML
private TableView<Courses> allCoursesTable;
@FXML
private TableColumn<Courses,String> CourseNameAttribute;
@FXML
private TableColumn<Courses,String> DepartmentAttribute;
@FXML
private TableColumn<Courses,String> LectureAttribute;
@FXML
private TableColumn<Courses, LocalDate> TimeAttribute;
@FXML
private TableColumn<Courses,String> LocationAttribute;
@FXML
private TableColumn<Courses,Number> CourseIDAttribute;
@FXML
private void initialize() {
ObservableList<Courses> data= FXCollections.observableArrayList(new Courses("MACHINE LEARNING","COMPUTER","ZHANGYI",LocalDate.of(2012,01,01),"A101",4011));//创建ObservableList对象,将数据装进去
CourseNameAttribute.setCellValueFactory(cellData->cellData.getValue().nameProperty());
DepartmentAttribute.setCellValueFactory(cellData->cellData.getValue().departmentProperty());
LectureAttribute.setCellValueFactory(cellData->cellData.getValue().lecturerProperty());
TimeAttribute.setCellValueFactory(cellData->cellData.getValue().timeProperty());
LocationAttribute.setCellValueFactory(cellData->cellData.getValue().locationProperty());
CourseIDAttribute.setCellValueFactory(cellData->cellData.getValue().IDProperty());
allCoursesTable.setItems(data);//加载数据
}
}
这就是为什么要用单独的控制器类了,否则initialize方法会在每次创建页面的时候都加载一次,而只有某一个页面有我们说的这些Tabel和Column对象,会报错的。
如何实现页面之间的传参呢?
对于要传参的页面,我们就不能直接获取parent对象了,而是先要获取FXMLLoader对象:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getClassLoader().getResource("MainPanel.fxml"));
Parent root = fxmlLoader.load();
MainController mc=fxmlLoader.getController();
注意这个MainController是我为这个页面写的控制器类
获取了Controller对象后,我们就可以调用方法,将参数传进去了:
mc.setPassword(pass);
mc.setUsername(user);
mc.handleAllCourses();
我在MainController这个类中是这样写的:
```java
public void setUsername(String username){
usernameString=username;
}
public void setPassword(String password){
passwordString=password;
}
```
我画了个流程图来表示传参过程:
java @FXML private void initialize(){ /* 对控制器中注册了的控件进行初始化 */ }
退出当前页面
Stage stage = (Stage)exitButton.getScene().getWindow();
stage.close();
这里是以一个id为exitButton的Button举例的。
意思就是,如果我们通过一个页面的事件进入了一个新页面,如果把在这个页面中得到的参数不借助文件等传递回来呢?当然,既然我们说的是javafx,那么一般就是两个控制器之间的参数传递。一个办法就是,再后一个页面的控制器上定义一个控制器对象和set方法,而前一个页面的控制器对象在创建后一个页面的时候通过set方法将自己传递进去。这样后面的控制器就可以使用前一个控制器的public和protected方法了
创建监听器
界面编辑器中内置了一些监听方法,但是这是不够用的,我们还可以自己创建监听器。例如,如何根据音量条的值控制视频音量?
volumeSD.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
mediaPlayer.setVolume(newValue.doubleValue() / 100);
}
});
注意监听器的注册要在页面创建之后、使用之前
这就是入门的FX教程了,有了这些基本的方法,相信设计一个稍微复杂一点的桌面应用程序已经不是问题了。
原网址: 访问
创建于: 2024-02-20 10:16:02
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论