一、前言
從本章節(jié)開始我們會陸續(xù)實(shí)現(xiàn)各個框體的 UI 開發(fā),內(nèi)容會包括;框體拆解、工程結(jié)構(gòu)、代碼開發(fā),以及最后編寫事件和接口。
在 JavaFx 中,一個框體包含;窗口 (Stage)、場景(Scene)、布局(Pane)、控件(Button 等) 這四方面內(nèi)容。而開發(fā)過程中可以使用 xml 和編碼兩種方式進(jìn)行處理,一般一些預(yù)定好的會使用 xml 結(jié)構(gòu),如果是隨著我們業(yè)務(wù)行為觸達(dá)而產(chǎn)生的會開發(fā)到代碼中來生成。
那么接下來我們的目標(biāo)是開發(fā)一個登陸框體,樣式如下;

二、登陸窗體分析
按照我們的 UI 開發(fā)訴求,將整個頁面進(jìn)行拆解,以方便清楚知道我們的各種類型元素放置位置;

| 序號 | 模塊 | 寬 * 高 | 描述 |
|---|
| 1 | 整體框體 | 540 * 415 | 一個整體的 4px 的圓角面板, 去掉默認(rèn)的標(biāo)題和工具欄 |
| 2 | 背景圖片 | 540 * 158 | 設(shè)置的一個背景圖 |
| 3 | 最小化、退出 | 43 * 32 | 兩個同樣大小的 Button |
| 4 | 用戶 ID 輸入框 | 250 * 45 | 明文輸入框 |
| 5 | 用戶密碼輸入框 | 250 * 45 | 密文輸入框 |
| 6 | 登錄按鈕 | 250 * 45 | 登陸按鈕 Button,鼠標(biāo)進(jìn)入時變換背景色,點(diǎn)擊觸發(fā)登陸 |
| 7 | 版本展示 | 400 * 25 | 透明的無背景可以調(diào)整,一般展示版本編號如;v1.0 |
| 8 | 頭像 | 100 * 100 | 圓角頭像圖片,整個可以使用 Image 等元素開發(fā) |
| 9 | 標(biāo)頭 | 200 * 15 | 展示名稱,例如;憨憨·語約 |
- 以上就是我們整體窗體的一個拆解后的示意圖,接下來開始按照整個示意圖進(jìn)行開發(fā)。
- 如果是個人開發(fā)的新項(xiàng)目,一般 UI 的設(shè)計(jì)可以先在草稿設(shè)計(jì),最后在使用工具進(jìn)行具體設(shè)計(jì)。如果是公司級別會有專門的設(shè)計(jì)來出所有的圖稿。
- 關(guān)于設(shè)計(jì)中使用的元素可以從工程源碼中獲取,可以自己從矢量圖倉庫中尋找自己喜歡的;https://www.
三、工程結(jié)構(gòu)
itstack-naive-chat-ui-02
└── src
├── main
│ ├── java
│ │ └── org.itstack.navice.chat.ui
│ │ ├── view
│ │ │ └── Login.java
│ │ └── Application.java
│ └── resources
│ └── fxml.login
│ ├── css
│ │ └── login.css
│ ├── img
│ │ ├── close_0.png
│ │ ├── close_1.png
│ │ ├── head_default_100.png
│ │ ├── logo.png
│ │ ├── min_0.png
│ │ ├── min_1.png
│ │ └── show.png
│ └── login.fxml
└── test
└── java
└── org.itstack.test
└── ApiTest.java
- 工程結(jié)構(gòu)上我們先從簡單規(guī)劃;啟動層、展示層、資源配置層,三方面。后面在隨著開發(fā)內(nèi)容的增多會不斷的優(yōu)化結(jié)構(gòu)
- fxml 是 JavaFx 開發(fā)的資源文件,可以設(shè)置界面展示,同時 xml 配置里可以引入 css 文件、設(shè)置元素大小等
四、代碼講解
1. login.fxml 配置
在 maven 管理下我們將配置文件放到資源文件夾下;fxml/login/login.fxml
整體外框 xml
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Font?>
<Pane id="login" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
prefWidth="540" prefHeight="415" stylesheets="@css/login.css" xmlns="http:///javafx/8.0.121"
xmlns:fx="http:///fxml/1">
<children>
</children>
</Pane>
- 這是一個整體的面板,初步設(shè)定了面板的寬高、引入的 css 樣式等
- 接下來在 children 孩子元素集合里添加各種窗體元素
操作欄;最小化、關(guān)閉(Pane)
<Pane id="operation" prefWidth="540" prefHeight="158">
<children>
<Label id="login_logo" styleClass="logo" layoutX="10" layoutY="5" prefWidth="200" prefHeight="15" text="憨憨 · 語約" style="-fx-text-fill:#666666;"/>
<Button id="login_min" styleClass="min" layoutX="454" prefWidth="43" prefHeight="32"/>
<Button id="login_close" styleClass="close" layoutX="497" prefWidth="43" prefHeight="32"/>
</children>
</Pane>
- 定義一個 Pane,并設(shè)置寬高,之后在整個面板里中添加 logo、最小化、關(guān)閉操作
- 后面你會看到更多的
<children>,來裝載元素 - 在孩子元素中有三個元素;
- login_logo 定義 logo 和文案,這里默認(rèn)顯示文字“憨憨 · 語約”
- login_min 最小化按鈕處理
- login_close 關(guān)閉操作處理
頭像(Pane)
<Pane id="headImg" layoutX="80" layoutY="200" prefWidth="100" prefHeight="100"/>
- 這個是定義一個頭像區(qū)域,也可以使用其他元素進(jìn)行定義
用戶 ID 輸入框(TextField)
<TextField id="userId" layoutX="200" layoutY="200" prefWidth="250" prefHeight="45" promptText="賬號">
<padding>
<Insets left="10"/>
</padding>
</TextField>
- TextField 是一個單行明文內(nèi)容輸入?yún)^(qū)域,在這里不僅設(shè)置了寬高,還設(shè)置了相對位置;layoutX、layoutY
- padding.Insets,如果你寫過 CSS,可能會知道。這是一個設(shè)置輸入框內(nèi),文字輸入?yún)^(qū)域距離左面的空出位置。一般空出的位置可以設(shè)置一個背景圖片
- 同時我們設(shè)置了提示文字,這個在這里比較簡單直接使用;promptText 即可。例如:
promptText="賬號"
密碼輸入框(PasswordField)
<PasswordField id="userPassword" layoutX="200" layoutY="255" prefWidth="250" prefHeight="45" promptText="密碼">
<padding>
<Insets left="10"/>
</padding>
</PasswordField>
- PasswordField 是一個單行密碼內(nèi)容輸入?yún)^(qū)域,同樣設(shè)置了寬高,以及提示文字
- 基本的使用方式與 TextField 一致,當(dāng)然在你后面后去他里面內(nèi)容的時候,是明文的
登陸按鈕(Button)
<Button id="login_button" styleClass="login_button" layoutX="200" layoutY="345" prefWidth="250" prefHeight="45" text="登 陸"/>
- Button 按鈕類的操作都可以使用,在這里設(shè)置好寬高,以及文字內(nèi)容
text="登 陸" - 同樣在這里我們也設(shè)置了相對的展示位置,這個位置是相對的,相遇對當(dāng)前父元素
版本(Label)
<Label id="slogan" layoutX="5" layoutY="398" prefWidth="400" prefHeight="15"
text="v1.0 小傅哥 | https://">
<font>
<Font size="12"/>
</font>
</Label>
- Label 一般可以設(shè)置文字、圖片等展示內(nèi)容。是一個輕量級元素
- 在這里我們設(shè)置了版本編號,和自己一些內(nèi)容信息
- 同時我們還設(shè)置了字體的大小,關(guān)于字體后面我們還會使用到 css(這里的 css 是 javafx 的 css,除名稱不同外基本一致)
2. login.css 設(shè)計(jì)
#login{
-fx-background-radius: 4px;
-fx-border-width: 1px;
-fx-border-radius: 4px;
-fx-border-color: rgb(180,180,180);
-fx-background-color: white;
}
#operation{-fx-border-color: rgb(180,180,180);
-fx-border-width: 1px 1px 0 1px;
-fx-border-radius: 4px 4px 0 0;
-fx-background-image: url("/fxml/login/img/system/show.png");
}
.close,.close:pressed{
-fx-background-radius: 2px;
-fx-background-position: center center;
-fx-background-repeat: no-repeat;
-fx-background-size: 43px 34px;
-fx-background-color: transparent;
-fx-background-image: url("/fxml/login/img/system/close_0.png");
-fx-cursor: hand;
-fx-border-width: 0;
}
.close:hover{
-fx-background-color: #f45454;
-fx-background-image: url("/fxml/login/img/system/close_1.png");
-fx-border-width: 1px 1px 0 0;
-fx-border-color: rgb(180,180,180);
-fx-border-radius: 2px;
}
...
- 從上面可以看到基本和我們認(rèn)識的 css 代碼一致,在這里我們就不全部展示這部分內(nèi)容了
- 一些基本的 javafx 中的 css 常用語法我們在第一篇中已經(jīng)介紹,可以參考。很常用的包括;背景色、線條色、寬高、圖片、圓角、懸停手勢等。
3. 代碼模塊
Login.java & 登陸頁面初始化
public class Login extends Stage {
private static final String RESOURCE_NAME = "/fxml/login/login.fxml";
private Parent root;
public Login() {
try {root = FXMLLoader.load(getClass().getResource(RESOURCE_NAME));
} catch (IOException e) {e.printStackTrace();
}
Scene scene = new Scene(root);
scene.setFill(Color.TRANSPARENT);
setScene(scene);
initStyle(StageStyle.TRANSPARENT);
setResizable(false);
this.getIcons().add(new Image("/fxml/login/img/system/logo.png"));
}
}
單個窗體的需要繼承 Stage,也就是繼承了窗口類,并需要在里面創(chuàng)建場景,才可以運(yùn)行展示
在這里我們加載配置元素 login.fxml,初始化窗體的基本信息
在布局中我們設(shè)置了填充為透明色,以及初始化樣式 StageStyle.TRANSPARENT
最后我們設(shè)置了狀態(tài)欄的圖標(biāo)樣式,這里我們設(shè)置了模仿微信的樣式,顏色略有差異
this.getIcons().add(new Image("/fxml/login/img/system/logo.png"));
Application.java & 啟動類
public class Application extends javafx.application.Application{
@Override
public void start(Stage primaryStage) throws Exception {Login login = new Login();
login.show();}
public static void main(String[] args) {launch(args);
}
}
這里的 Application 繼承了 JavaFx 的 Application,并實(shí)現(xiàn) start 啟動
在這里我們初始化登陸窗體,并通過 login.show() 調(diào)用窗體的展現(xiàn)
上面這個結(jié)構(gòu)是一個固定的模板代碼,也是配置到 maven 中的啟動類路徑;
<plugin>
<groupId>com.zenjava</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>8.8.3</version>
<configuration>
<mainClass>org.itstack.navice.chat.ui.Application</mainClass>
</configuration>
</plugin>
五、效果演示
在類org.itstack.navice.chat.ui.Application,右鍵運(yùn)行
不出意外效果如下;

六、總結(jié)
- 在這一篇中我們顯示拆解分析了整個窗體需要實(shí)現(xiàn)的功能,之后逐步使用 JavaFx 去把 UI 搭建處理。在這里使用到了代碼、XML、CSS,三個技術(shù)的配合工作。
- 通過上面的工程和代碼可以初步的了解到一個簡單的窗體的搭建和使用,并且設(shè)計(jì)了我們的工程結(jié)構(gòu),一個好的開始就從現(xiàn)在開始了
- 同時如果你細(xì)心可能會發(fā)現(xiàn)我們的工程其實(shí)是在打一個 jar 包,將來共客戶端使用,最后也就達(dá)到了 UI 與業(yè)務(wù)分離,這部分會隨著后續(xù)章節(jié)逐步展現(xiàn)