如何基于JavaFX开发桌面程序
基于JavaFX开发桌面程序
注:我也是JAVAFX的初学者之一,自己在学习的时候踩了许多的坑,中文英文的资料查了不少,但是觉得FX技术和其他热门技术相比,教程还是太少了。这里就尽量做一点微小的贡献吧
使用环境
注:写这个只是为了说明我的环境,使用和我的不一样的环境在理解这篇教程的时候并没有什么问题,例如使用Windows平台、使用OracleJDK(这样就不需要再单独安装FX组件了,可以不用MAVEN)、使用Oracle的SceneBuilder。可能唯一一个比较影响体验的就是不使用IDEA而是使用eclipse了
- Ubuntu18.04LTS
- OpenJDK1.8
- IDEA(withMAVEN):使用MAVEN安装FX环境(OpenJDK不附带FX环境)
- SceneBuilder(glounhq):这是一个fxml可视化设计环境,使用上不如C#,但起码比纯命令设计强一百倍
搭建JAVAFX环境
下载IDEA、OpenJDK1.8、SceneBuilder(glounhq).
SceneBuilder下载地址:https://gluonhq.com/products/scene-builder/#download
在IDEA中关联SceneBuilder.关联的目的是为了之后可以从IDEA快速打开SceneBuilder来设计页面
IDEA->File->Settings->Language->JavaFX->输入SceneBuilder的路径
如果是Linux环境,你会发现这个路径还不好找,我是使用locateSceneBuilder命令找到的,路径是:/opt/SceneBuilder/SceneBuilder
因为OpenJDK没有FX环境,需要我们自己安装。为了便于管理,我们在这里使用MAVEN
在IDEA中创建一个JavaFX项目
在项目名上右键,选择'Addframeworksupport',选择MAVEN
在pom.xml文件中加入以下依赖:
org.openjfx javafx-controls 13 org.openjfx javafx-fxml 13
设计流程
这里只写一些我已经探索出来的设计流程,如果有不对的请指出~
先在Resources中创建fxml文件(之所以放在Resources文件夹下,是为了加载的时候方便,之后能看到),创建完成后在文件名上右击,选择'OpeninSceneBuilder',之后就可以在SceneBuilder中进行可视化设计了。设计时要注意,对有响应的元素要在code栏下的fx:id中设置id,以便于之后的调用。设计完成后Ctrl+s保存文件
设计第一个加载的界面。这个可以放在入口的java类的main方法下,举个例子:
packagesample;
importjavafx.application.Application;
importjavafx.fxml.FXMLLoader;
importjavafx.scene.Parent;
importjavafx.scene.Scene;
importjavafx.stage.Stage;
publicclassMainextendsApplication{
@Override
publicvoidstart(StageprimaryStage)throwsException{
Parentroot=FXMLLoader.load(getClass().getClassLoader().getResource("Entry.fxml"));//从Resources中获取资源
primaryStage.setTitle("CourseRegistrationSystem");
primaryStage.setScene(newScene(root,800,600));
primaryStage.show();
}
设计触发器:
对于每一个Panel,我们要指定一个触发器类,这个是放在该fxml文件中的,例如IDEA中默认创建的就是AnchorPane对象,在它那一行就能找到:fx:controller="sample.MainController",这个MainController就是我创建的一个类
之后,我们可以对该panel下各个控件设计触发事件后的反映,这个可以在SceneBuilder中填写,在Code那一栏下面。设计了之后,它就会到我们指定的那个触发器类下寻找这个方法,如果没有的话IDEA会提示你创建
注意,触发器类可以创建多个,这样更便于管理,降低耦合度
在触发器中获取fxml中的控件对象
有时候,我们需要在事件相应中获取对象的值,例如设计登录页面时点击'提交'的按钮,我们需要知道输入框的字符串。这时候我们可以在触发器中获取这些元素,前提是我们为这些控件输入了fx:id,它是全局性的,不允许重复。例如我们可以通过声明:
@FXML privateTextFieldusername; @FXML privateTextFieldpassword;
获取两个TextField对象下的值:
usernameString=username.getText(); passwordString=password.getText();
页面跳转
我们需要为每一个页面设计一个Java类,例如我设计了一个SignIn_Student.java:
packagesample;
importjavafx.application.Application;
importjavafx.fxml.FXMLLoader;
importjavafx.scene.Parent;
importjavafx.scene.Scene;
importjavafx.stage.Stage;
publicclassSignIn_StudentextendsApplication{
privateStringusernameString;
privateStringpasswordString;
@Override
publicvoidstart(Stagestage)throwsException{
Parentroot=FXMLLoader.load(getClass().getClassLoader().getResource("SignIn_Student.fxml"));//加载页面
SceneanotherScene=newScene(root);
stage.setTitle("Pleaselogin");
stage.setScene(anotherScene);
stage.show();
}
}
TableView的使用
这个控件用起来着实有点麻烦。折腾了好久。
我们肯定需要在某一个fxml页面中加入了这个TableView,并且输入了Table和它每一个TableColumn的fx:id.
我们需要为有TableView的fxml文件单独创建一个控制器类,之后会说为什么
我们需要创建一个类来表示要储存的数据,例如我这里创建了一个Courses.class:(下面的get和set方法是IDEA自动生成的)
packagesample;
importjavafx.beans.property.*;
importjava.time.LocalDate;
importjava.time.LocalTime;
publicclassCourses{
privatefinalStringPropertydepartment;
privatefinalStringPropertylecturer;
privatefinalObjectPropertyTime;
privatefinalStringPropertylocation;
privatefinalIntegerPropertyID;
publicCourses(Stringname,Stringdepartment,Stringlecturer,LocalDatetime,Stringlocation,IntegerID){
this.name=newSimpleStringProperty(name);
this.department=newSimpleStringProperty(department);
this.lecturer=newSimpleStringProperty(lecturer);
this.Time=newSimpleObjectProperty(time);
this.location=newSimpleStringProperty(location);
this.ID=newSimpleIntegerProperty(ID);
}
//String,String,String,Date,String,Integer
privatefinalStringPropertyname;
publicStringgetName(){
returnname.get();
}
publicStringPropertynameProperty(){
returnname;
}
publicvoidsetName(Stringname){
this.name.set(name);
}
publicStringgetDepartment(){
returndepartment.get();
}
publicStringPropertydepartmentProperty(){
returndepartment;
}
publicvoidsetDepartment(Stringdepartment){
this.department.set(department);
}
publicStringgetLecturer(){
returnlecturer.get();
}
publicStringPropertylecturerProperty(){
returnlecturer;
}
publicvoidsetLecturer(Stringlecturer){
this.lecturer.set(lecturer);
}
publicLocalDategetTime(){
returnTime.get();
}
publicObjectPropertytimeProperty(){
returnTime;
}
publicvoidsetTime(LocalDatetime){
this.Time.set(time);
}
publicStringgetLocation(){
returnlocation.get();
}
publicStringPropertylocationProperty(){
returnlocation;
}
publicvoidsetLocation(Stringlocation){
this.location.set(location);
}
publicintgetID(){
returnID.get();
}
publicIntegerPropertyIDProperty(){
returnID;
}
publicvoidsetID(intID){
this.ID.set(ID);
}
}
我们需要实现的效果是,在加载这个页面时,表格中自动加载数据。填写我们创建的控制器类如下:
packagesample;
importjavafx.collections.FXCollections;
importjavafx.collections.ObservableList;
importjavafx.fxml.FXML;
importjavafx.scene.control.TableColumn;
importjavafx.scene.control.TableView;
importjavafx.scene.control.TextField;
importjava.time.LocalDate;
publicclassMainController{
@FXML
privateTextFieldusername;
@FXML
privateTextFieldpassword;
@FXML
privateTableViewallCoursesTable;
@FXML
privateTableColumnCourseNameAttribute;
@FXML
privateTableColumnDepartmentAttribute;
@FXML
privateTableColumnLectureAttribute;
@FXML
privateTableColumnTimeAttribute;
@FXML
privateTableColumnLocationAttribute;
@FXML
privateTableColumnCourseIDAttribute;
@FXML
privatevoidinitialize(){
ObservableListdata=FXCollections.observableArrayList(newCourses("MACHINELEARNING","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对象:
FXMLLoaderfxmlLoader=newFXMLLoader(getClass().getClassLoader().getResource("MainPanel.fxml"));
Parentroot=fxmlLoader.load();
MainControllermc=fxmlLoader.getController();
注意这个MainController是我为这个页面写的控制器类
获取了Controller对象后,我们就可以调用方法,将参数传进去了:
mc.setPassword(pass); mc.setUsername(user); mc.handleAllCourses();
我在MainController这个类中是这样写的:
publicvoidsetUsername(Stringusername){
usernameString=username;
}
publicvoidsetPassword(Stringpassword){
passwordString=password;
}
这就是入门的FX教程了,有了这些基本的方法,相信设计一个稍微复杂一点的桌面应用程序已经不是问题了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。