如何基于JavaFX開(kāi)發(fā)桌面程序
基于JavaFX開(kāi)發(fā)桌面程序
注:我也是JAVA FX的初學(xué)者之一,自己在學(xué)習(xí)的時(shí)候踩了許多的坑,中文英文的資料查了不少,但是覺(jué)得FX技術(shù)和其他熱門技術(shù)相比,教程還是太少了。這里就盡量做一點(diǎn)微小的貢獻(xiàn)吧
使用環(huán)境
注:寫這個(gè)只是為了說(shuō)明我的環(huán)境,使用和我的不一樣的環(huán)境在理解這篇教程的時(shí)候并沒(méi)有什么問(wèn)題,例如使用Windows平臺(tái)、使用Oracle JDK(這樣就不需要再單獨(dú)安裝FX組件了,可以不用MAVEN)、使用Oracle的SceneBuilder??赡芪ㄒ灰粋€(gè)比較影響體驗(yàn)的就是不使用IDEA而是使用eclipse了
- Ubuntu18.04LTS
- OpenJDK 1.8
- IDEA(with MAVEN):使用MAVEN安裝FX環(huán)境(OpenJDK不附帶FX環(huán)境)
- SceneBuilder(glounhq):這是一個(gè)fxml可視化設(shè)計(jì)環(huán)境,使用上不如C#,但起碼比純命令設(shè)計(jì)強(qiáng)一百倍
搭建JAVA FX環(huán)境
下載IDEA、OpenJDK1.8、SceneBuilder(glounhq).
SceneBuilder下載地址:https://gluonhq.com/products/scene-builder/#download
在IDEA中關(guān)聯(lián)SceneBuilder.關(guān)聯(lián)的目的是為了之后可以從IDEA快速打開(kāi)SceneBuilder來(lái)設(shè)計(jì)頁(yè)面
IDEA->File->Settings->Language->Java FX->輸入SceneBuilder的路徑
如果是Linux環(huán)境,你會(huì)發(fā)現(xiàn)這個(gè)路徑還不好找,我是使用locate SceneBuilder
命令找到的,路徑是: /opt/SceneBuilder/SceneBuilder
因?yàn)镺penJDK沒(méi)有FX環(huán)境,需要我們自己安裝。為了便于管理,我們?cè)谶@里使用MAVEN
在IDEA中創(chuàng)建一個(gè)Java FX項(xiàng)目
在項(xiàng)目名上右鍵,選擇'Add framework support',選擇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>
設(shè)計(jì)流程
這里只寫一些我已經(jīng)探索出來(lái)的設(shè)計(jì)流程,如果有不對(duì)的請(qǐng)指出~
先在Resources中創(chuàng)建fxml文件(之所以放在Resources文件夾下,是為了加載的時(shí)候方便,之后能看到),創(chuàng)建完成后在文件名上右擊,選擇'Open in SceneBuilder',之后就可以在SceneBuilder中進(jìn)行可視化設(shè)計(jì)了。設(shè)計(jì)時(shí)要注意,對(duì)有響應(yīng)的元素要在code欄下的fx:id中設(shè)置id,以便于之后的調(diào)用。設(shè)計(jì)完成后Ctrl+s保存文件
設(shè)計(jì)第一個(gè)加載的界面。這個(gè)可以放在入口的java類的main方法下,舉個(gè)例子:
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(); }
設(shè)計(jì)觸發(fā)器:
對(duì)于每一個(gè)Panel,我們要指定一個(gè)觸發(fā)器類,這個(gè)是放在該fxml文件中的,例如IDEA中默認(rèn)創(chuàng)建的就是AnchorPane對(duì)象,在它那一行就能找到:fx:controller="sample.MainController"
,這個(gè)MainController就是我創(chuàng)建的一個(gè)類
之后,我們可以對(duì)該panel下各個(gè)控件設(shè)計(jì)觸發(fā)事件后的反映,這個(gè)可以在SceneBuilder中填寫,在Code那一欄下面。設(shè)計(jì)了之后,它就會(huì)到我們指定的那個(gè)觸發(fā)器類下尋找這個(gè)方法,如果沒(méi)有的話IDEA會(huì)提示你創(chuàng)建
注意,觸發(fā)器類可以創(chuàng)建多個(gè),這樣更便于管理,降低耦合度
在觸發(fā)器中獲取fxml中的控件對(duì)象
有時(shí)候,我們需要在事件相應(yīng)中獲取對(duì)象的值,例如設(shè)計(jì)登錄頁(yè)面時(shí)點(diǎn)擊'提交'的按鈕,我們需要知道輸入框的字符串。這時(shí)候我們可以在觸發(fā)器中獲取這些元素,前提是我們?yōu)檫@些控件輸入了fx:id,它是全局性的,不允許重復(fù)。例如我們可以通過(guò)聲明:
@FXML private TextField username; @FXML private TextField password;
獲取兩個(gè)TextField對(duì)象下的值:
usernameString=username.getText(); passwordString=password.getText();
頁(yè)面跳轉(zhuǎn)
我們需要為每一個(gè)頁(yè)面設(shè)計(jì)一個(gè)Java類,例如我設(shè)計(jì)了一個(gè)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"));//加載頁(yè)面 Scene anotherScene=new Scene(root); stage.setTitle("Please log in"); stage.setScene(anotherScene); stage.show(); } }
TableView的使用
這個(gè)控件用起來(lái)著實(shí)有點(diǎn)麻煩。折騰了好久。
我們肯定需要在某一個(gè)fxml頁(yè)面中加入了這個(gè)TableView,并且輸入了Table和它每一個(gè)TableColumn的fx:id.
我們需要為有TableView的fxml文件單獨(dú)創(chuàng)建一個(gè)控制器類,之后會(huì)說(shuō)為什么
我們需要?jiǎng)?chuàng)建一個(gè)類來(lái)表示要儲(chǔ)存的數(shù)據(jù),例如我這里創(chuàng)建了一個(gè)Courses.class:(下面的get和set方法是IDEA自動(dòng)生成的)
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); } }
我們需要實(shí)現(xiàn)的效果是,在加載這個(gè)頁(yè)面時(shí),表格中自動(dòng)加載數(shù)據(jù)。填寫我們創(chuàng)建的控制器類如下:
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));//創(chuàng)建ObservableList對(duì)象,將數(shù)據(jù)裝進(jìn)去 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);//加載數(shù)據(jù) } }
這就是為什么要用單獨(dú)的控制器類了,否則initialize方法會(huì)在每次創(chuàng)建頁(yè)面的時(shí)候都加載一次,而只有某一個(gè)頁(yè)面有我們說(shuō)的這些Tabel和Column對(duì)象,會(huì)報(bào)錯(cuò)的。
寫一個(gè)方法來(lái)跳轉(zhuǎn)到這個(gè)頁(yè)面。
如何實(shí)現(xiàn)頁(yè)面之間的傳參呢?
對(duì)于要傳參的頁(yè)面,我們就不能直接獲取parent對(duì)象了,而是先要獲取FXMLLoader對(duì)象:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getClassLoader().getResource("MainPanel.fxml")); Parent root = fxmlLoader.load(); MainController mc=fxmlLoader.getController();
注意這個(gè)MainController是我為這個(gè)頁(yè)面寫的控制器類
獲取了Controller對(duì)象后,我們就可以調(diào)用方法,將參數(shù)傳進(jìn)去了:
mc.setPassword(pass); mc.setUsername(user); mc.handleAllCourses();
我在MainController這個(gè)類中是這樣寫的:
public void setUsername(String username){ usernameString=username; } public void setPassword(String password){ passwordString=password; }
這就是入門的FX教程了,有了這些基本的方法,相信設(shè)計(jì)一個(gè)稍微復(fù)雜一點(diǎn)的桌面應(yīng)用程序已經(jīng)不是問(wèn)題了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解 Java中日期數(shù)據(jù)類型的處理之格式轉(zhuǎn)換的實(shí)例
這篇文章主要介紹了詳解 Java中日期數(shù)據(jù)類型的處理之格式轉(zhuǎn)換的實(shí)例的相關(guān)資料,日期以及時(shí)間格式處理,在Java中時(shí)間格式一般會(huì)涉及到的數(shù)據(jù)類型包括Calendar類和Date類,需要的朋友可以參考下2017-08-08Spring Data JPA結(jié)合Mybatis進(jìn)行分頁(yè)查詢的實(shí)現(xiàn)
本文主要介紹了Spring Data JPA結(jié)合Mybatis進(jìn)行分頁(yè)查詢的實(shí)現(xiàn)2024-03-03maven在settings.xml和pom.xml中指定jdk版本編譯的方法
在開(kāi)發(fā)Java應(yīng)用時(shí),通常需要指定要使用的Java版本,下面這篇文章主要給大家介紹了關(guān)于maven在settings.xm和pom.xml中指定jdk版本編譯的方法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-05-05Spring?Boot項(xiàng)目中使用OpenAI-Java的示例詳解
Spring?Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開(kāi)發(fā)過(guò)程,這篇文章主要介紹了Spring?Boot項(xiàng)目中使用OpenAI-Java的示例詳解,需要的朋友可以參考下2023-04-04springboot yml中profiles的巧妙用法(小白必看多環(huán)境配置)
這篇文章主要介紹了springboot yml中profiles的巧妙用法,非常適合多環(huán)境配置場(chǎng)景,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04springboot項(xiàng)目中引入本地依賴jar包并打包到lib文件夾中
這篇文章主要介紹了springboot項(xiàng)目中引入本地依賴jar包,如何打包到lib文件夾中,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04Java對(duì)象初始化過(guò)程代碼塊和構(gòu)造器的調(diào)用順序
這篇文章主要介紹了Java對(duì)象初始化過(guò)程代碼塊和構(gòu)造器的調(diào)用順序,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08