注:我也是JAVA FX的初学者之一,本身在学习的时候踩了许多的坑,中文英文的资料查了很多,可是以为FX技术和其余热门技术相比,教程仍是太少了。这里就尽可能作一点微小的贡献吧java
注:写这个只是为了说明个人环境,使用和个人不同的环境在理解这篇教程的时候并无什么问题,例如使用Windows平台、使用Oracle JDK(这样就不须要再单独安装FX组件了,能够不用MAVEN)、使用Oracle的SceneBuilder。可能惟一一个比较影响体验的就是不使用IDEA而是使用eclipse了app
下载IDEA、OpenJDK1.八、SceneBuilder(glounhq).eclipse
SceneBuilder下载地址:https://gluonhq.com/products/scene-builder/#downloadide
在IDEA中关联SceneBuilder.关联的目的是为了以后能够从IDEA快速打开SceneBuilder来设计页面学习
IDEA->File->Settings->Language->Java FX->输入SceneBuilder的路径ui
若是是Linux环境,你会发现这个路径还很差找,我是使用locate SceneBuilder
命令找到的,路径是:/opt/SceneBuilder/SceneBuilder
this
由于OpenJDK没有FX环境,须要咱们本身安装。为了便于管理,咱们在这里使用MAVEN设计
在IDEA中建立一个Java FX项目code
在项目名上右键,选择'Add framework support',选择MAVENxml
在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>
这里只写一些我已经探索出来的设计流程,若是有不对的请指出~
先在Resources中建立fxml文件(之因此放在Resources文件夹下,是为了加载的时候方便,以后能看到),建立完成后在文件名上右击,选择'Open in SceneBuilder',以后就能够在SceneBuilder中进行可视化设计了。设计时要注意,对有响应的元素要在code栏下的fx:id中设置id,以便于以后的调用。设计完成后Ctrl+s保存文件
设计第一个加载的界面。这个能够放在入口的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的使用
这个控件用起来着实有点麻烦。折腾了很久。
咱们确定须要在某一个fxml页面中加入了这个TableView,而且输入了Table和它每个TableColumn的fx:id.
咱们须要为有TableView的fxml文件单首创建一个控制器类,以后会说为何
咱们须要建立一个类来表示要储存的数据,例如我这里建立了一个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这个类中是这样写的:
public void setUsername(String username){ usernameString=username; } public void setPassword(String password){ passwordString=password; }
这就是入门的FX教程了,有了这些基本的方法,相信设计一个稍微复杂一点的桌面应用程序已经不是问题了。