JavaFX入门:简单Demo-学习NetBeans开发平台

JavaFX入门参考,高优质资料:http://www.javafxchina.net/blog/docs/tutorial1/
版权所有,转载注明。

零、 最终目标

通过两种方式(纯代码控制、FXML),实现一个简单的登录界面:

Paste_Image.png

涉及到的控件:
文本(Text,动态显示内容)、标签(Label,显示文本)、文本域(TextField,用户交互输入)、按钮(Button,登录点击)

一、 控件通过Code动态添加实现方法

1、 新建项目

新建JavaFXLoginDemo项目,具体新建方法参见前篇:
JavaFX开发环境:NetBeans开发环境搭建

完成项目新建后,进入开发正题。

入口参数:

public class JavaFXLoginDemo extends Application {
    
    @Override
    public void start(Stage primaryStage) {
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}
2、 布局方式

JavaFX的UI控件均摆放在Scene上,一般通过增加控制布局的Panel,并将实际的UI摆放在布局Panel上,有点类似于Android的布局方式。Panel有多种样式,包括了行、列、栈等等,如BorderPaneGridPaneHboxVBox等等。
本文将使用GridPane进行布局。

GridPane grid = new GridPane();//网格式布局,由行列网格控制
grid.setAlignment(Pos.CENTER);//对齐方式,默认靠左对齐,当前设置居中对齐
grid.setHgap(10);//设置水平间隔
grid.setVgap(10);//设置垂直间隔
grid.setPadding(new Insets(25, 25, 25, 25));//设置Padding,顺序是:上、右、下、左

Scene scene = new Scene(grid, 300, 275);//新建Scene,并将网格式Panel置于其中
primaryStage.setScene(scene);//设置场景
primaryStage.show();
3、 添加控件
        Text scenetitle = new Text("欢迎标题");
        //scenetitle.setFont(Font.font("Times New Roman", FontWeight.NORMAL, 20));
        grid.add(scenetitle, 0, 0, 2, 1);

        //创建Label对象,放到第0列,第1行
        Label userName = new Label("用户名:");
        grid.add(userName, 0, 1);

        //创建文本输入框,放到第1列,第1行
        TextField userTextField = new TextField();
        grid.add(userTextField, 1, 1);

        Label pw = new Label("密 码:");
        grid.add(pw, 0, 2);

        PasswordField pwBox = new PasswordField();
        grid.add(pwBox, 1, 2);

        Button btn = new Button("登录");
        HBox hbBtn = new HBox(10);
        hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
        hbBtn.getChildren().add(btn);//将按钮控件作为子节点
        grid.add(hbBtn, 1, 4);//将HBox pane放到grid中的第1列,第4行

        final Text actiontarget = new Text();//增加用于显示信息的文本
        grid.add(actiontarget, 1, 6);
4、 添加处理事件

只有一个按钮需要事件处理:

        btn.setOnAction(new EventHandler<ActionEvent>() {//注册事件handler
            @Override
            public void handle(ActionEvent e) {
                actiontarget.setFill(Color.FIREBRICK);//将文字颜色变成 firebrick red
                actiontarget.setText("登录中...");
            }
        });
5、 添加样式CSS

步骤一:新建CSS文件:
在包上右击:


Paste_Image.png
Paste_Image.png

输入文件名Login.css,完成样式表文件的创建:

Paste_Image.png

样式表中定义的内容,主要用在控件的样式控制上,需要在UI中应用。样式表需要应用到Root容器中:

scene.getStylesheets().add(JavaFXLoginDemo.class.getResource("Login.css").toExternalForm());

设置后,将会在JavaFXLoginDemo.class相对路径下寻找给出的样式表Login.css,并应用到scene中。
步骤二:添加一张背景图,到当前包路径下:

Paste_Image.png

步骤三:添加CSS样式控制

//根元素样式布局,设置背景图
.root {
   -fx-background-image: url("background.jpg");
}

//标签控件样式
.label {
   -fx-font-size: 12px;
   -fx-font-weight: bold;
   -fx-text-fill: #333333;
   -fx-effect: dropshadow( gaussian , rgba(255,255,255,0.5) , 0,0,0,1 );
}
//给Button增加样式
.button {
   -fx-text-fill: white;
   -fx-font-family: "Arial Narrow";
   -fx-font-weight: bold;
   -fx-background-color: linear-gradient(#61a2b1, #2A5058);
   -fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 5, 0.0 , 0 , 1 );
}
.button:hover {
   -fx-background-color: linear-gradient(#2A5058, #61a2b1);
}
//增加文本效果
#welcome-text {
   -fx-font-size: 32px;
   -fx-fill: #818181;
   -fx-effect: innershadow( three-pass-box , rgba(0,0,0,0.7) , 6, 0.0 , 0 , 2 );
}
//登录点击事件显示效果
#actiontarget {
   -fx-fill: FIREBRICK;
   -fx-font-weight: bold;
   -fx-effect: dropshadow( gaussian , rgba(255,255,255,0.5) , 0,0,0,1 );
}

注意,最后两个是采用了CSS中的ID控制样式,而非Label、Button中针对类型设置的样式,因此需要给目标控件增加ID规则:

        scenetitle.setId("welcome-text");
        actiontarget.setId("actiontarget");

☆☆☆ 中文字体库应用

任何事情,涉及到了中文之后,字体库使用有点麻烦。
(1)新建文件夹,在当前包下建立resources/fonts,如图所示:

Paste_Image.png

将字体库粘贴进去,一般是ttf文件,Windows常用,Mac可以用,Linux也是兼容的。我粘贴的是微软雅黑和粗体版,在Windows操作系统的系统盘下Windows/Fonts目录下。
(2)增加fonts.mf文件
使用“文件”选项卡查看工程:


Paste_Image.png

fonts.mf内容:

msyh=/javafxlogindemo/resources/fonts/msyh.ttf
msyhbd=/javafxlogindemo/resources/fonts/msyhbd.ttf
hwxk=/javafxlogindemo/resources/fonts/STXINGKA.TTF
hwcy=/javafxlogindemo/resources/fonts/STCAIYUN.TTF

hwcy:


Paste_Image.png

hwxk:


Paste_Image.png

"="前面,是项目使用时的字体名称,即font-family,后面是字体库文件的路径。
(3)fonts.mf需要在打包时放到jar包的META-INF目录下,因此需要配置NetBeans工程的build.xml文件内容:

NetBeans工程使用Ant管理项目,配置的build.xml文件,根文件在工程根目录下,具体配置文件在nbproject目录下的build-impl.xml文件中。
在build.xml中增加如下内容:

    <target name="-post-compile">
        <mkdir dir="${build.classes.dir}/META-INF"/>
        <copy todir="${build.classes.dir}/META-INF" file="fonts.mf"/>
    </target>

完成之后,运行一下项目,在项目目录的dist目录下,可以看到打包的jar包,用压缩文件查看器打开(WinRAR):

Paste_Image.png
Paste_Image.png

包含了配置文件和字体库文件。
(4)code中使用:

import javafx.scene.text.Font;

Font font = Font.font("hwcy", 32);//字体,尺寸,注意不能使用加粗,即FontWeight

Paste_Image.png

(5)在CSS样式文件中使用:

//增加文本效果
#welcome-text {
   -fx-font-size: 32px;
   -fx-font-family: "hwcy";
   -fx-fill: #818181;
   -fx-effect: innershadow( three-pass-box , rgba(0,0,0,0.7) , 6, 0.0 , 0 , 2 );
}

注意,-fx-font-weight: bold;加粗不能一起使用,会使字体失效。

经过上述的配置,中文字体也能够轻松走起啦。

6、 完成编码,启动项目,运行测试。

二、 FXML实现界面

NetBeans实现方法
1、 新建工程JavaFXLoginFXMLDemo:

与前一种方法新的工程种类稍有区别,这里选择JavaFX FXML应用程序

Paste_Image.png
Paste_Image.png

对比一下工程结构,FXML工程多了一些FXML文件和控制器文件:

Paste_Image.png

新建工程后,立刻运行:

Paste_Image.png

代码也稍有区别,FXML文件中定义了控件和控制器映射关系等等:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxloginfxmldemo.FXMLDocumentController">
    <children>
        <Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
        <Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
    </children>
</AnchorPane>

默认生成的FXML样例界面文件中,根容器是一个AnchorPane:

AnchorPane布局面板可锚定节点于面板的顶、底、左边、右边或中间。当窗口尺寸调整时,相应节点维护它们相对于锚点的位置。节点可被锚定于多个位置,多个节点也可锚定于同一个位置。

在后面,将要修改实际的布局容器。

控制器Controller定义了事件处理方法:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javafxloginfxmldemo;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;

/**
 *
 * @author guorui.he
 */
public class FXMLDocumentController implements Initializable {
    
    @FXML
    private Label label;
    
    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    
    
}

主文件内,与之前的纯代码实现基本类似,但是加载页面的机制稍有不同,这时通过FXML文件加载,搞过Android的人很熟悉:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javafxloginfxmldemo;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

/**
 *
 * @author guorui.he
 */
public class JavaFXLoginFXMLDemo extends Application {
    
    @Override
    public void start(Stage stage) throws Exception {
        //通过fxml的UI布局文件加载实际的界面内容
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
        
        Scene scene = new Scene(root);
        
        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}

由于默认文件名定义的比较弱,我们要自己改一下文件名,这样才能更清晰的展示:

Paste_Image.png

注意不要忘记修改控制器和FXML的映射,以及主类加载的FXML界面名称。

2、在FXML文件中,编写界面内容:
<?xml version="1.0" encoding="UTF-8"?>

//整理引入包
<?import java.net.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>

//编写界面
<GridPane xmlns:fx="http://javafx.com/fxml" 
          fx:controller="javafxloginfxmldemo.FXMLLoginDemoDocumentController" 
          alignment="center" hgap="10" vgap="10">
    <padding>
        <Insets top="25" right="25" bottom="10" left="25"/>
    </padding>
    <Text text="欢迎登录FXML Demo系统"
          GridPane.columnIndex="0" GridPane.rowIndex="0"
          GridPane.columnSpan="2"/>
    <Label text="用户名:"
           GridPane.columnIndex="0" GridPane.rowIndex="1"/>
    <TextField
        GridPane.columnIndex="1" GridPane.rowIndex="1"/>
    <Label text="密  码:"
           GridPane.columnIndex="0" GridPane.rowIndex="2"/>
    <PasswordField fx:id="passwordField"
                   GridPane.columnIndex="1" GridPane.rowIndex="2"/>
    <HBox spacing="10" alignment="bottom_right"
          GridPane.columnIndex="1" GridPane.rowIndex="4">
        <Button text="登录" />
    </HBox>

    <Text fx:id="actiontarget"
          GridPane.columnIndex="0" GridPane.columnSpan="2"
          GridPane.halignment="RIGHT" GridPane.rowIndex="6"/>
</GridPane>

此时,没有添加事件处理,可以试运行:

Paste_Image.png

大致内容都在了,但是没有样式,没有登录按钮点击处理事件。

3、 添加处理事件:

方法一:使用Java处理

//给Button增加一个事件处理
<Button text="登录" onAction="#handleSubmitButtonAction"/>

添加之后,会报错:

Paste_Image.png

需要在控制器中为其添加事件处理:

Paste_Image.png

会自动的在控制器内添加处理程序:

package javafxloginfxmldemo;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.text.Text;

/**
 *
 * @author guorui.he
 */
public class FXMLLoginDemoDocumentController implements Initializable {
    private Label label;
    @FXML
    private PasswordField passwordField;
    @FXML
    private Text actiontarget;
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }
    @FXML
    private void handleSubmitButtonAction(ActionEvent event) {
        actiontarget.setText("登录中...");
    }
}

@FXML注解,可以删除,最好保留,阅读方便。
添加好处理事件后,点击登录按钮,就会有反应了:

Paste_Image.png

方法二.1:使用内置JS脚本处理

<?xml version="1.0" encoding="UTF-8"?>
<?language javascript?>

添加脚本声明。
修改Button的事件处理方法(局部代码)

<GridPane xmlns:fx="http://javafx.com/fxml" 
          fx:controller="javafxloginfxmldemo.FXMLLoginDemoDocumentController" 
          alignment="center" hgap="10" vgap="10">
    <!-- 脚本处理代码 -->
    <fx:script>
        function handleSubmitButtonAction() {
            actiontarget.setText("Calling the JavaScript");
        }
    </fx:script>

    <HBox spacing="10" alignment="bottom_right"
          GridPane.columnIndex="1" GridPane.rowIndex="4">
        <Button text="登录" onAction="handleSubmitButtonAction(event);"/>
    </HBox>

    <Text fx:id="actiontarget"
          GridPane.columnIndex="0" GridPane.columnSpan="2"
          GridPane.halignment="RIGHT" GridPane.rowIndex="6"/>
</GridPane>

点击之后,调用脚本:

Paste_Image.png

脚本语言提供与JSR 223规范兼容的引擎即可。例如JavaScript、Groovy、Jython、Clojure。

方法二.2:使用外置JS脚本处理
脚本可以放在外部,正确引用即可:

Paste_Image.png
Paste_Image.png
Paste_Image.png
function handleSubmitButtonAction() {
    actiontarget.setText("Calling the Outline JavaScript");
}

同时,在FXML中引入脚本:

<GridPane xmlns:fx="http://javafx.com/fxml" 
          fx:controller="javafxloginfxmldemo.FXMLLoginDemoDocumentController" 
          alignment="center" hgap="10" vgap="10">

    <fx:script source="FXMLJSLoginDemo.js"/>

    <HBox spacing="10" alignment="bottom_right"
          GridPane.columnIndex="1" GridPane.rowIndex="4">
        <Button text="登录" onAction="handleSubmitButtonAction(event);"/>
    </HBox>

    <Text fx:id="actiontarget"
          GridPane.columnIndex="0" GridPane.columnSpan="2"
          GridPane.halignment="RIGHT" GridPane.rowIndex="6"/>
</GridPane>

试运行,得到结果:

Paste_Image.png
4、 添加样式控制:

添加样式表文件、字体库文件、背景图片,增加fonts.mf配置文件,修改build.xml等等,与前面纯代码开发基本一致,注意路径名(包名有变化)。
在FXML中引入样式表,并给特定的控件增加id,以便于CSS样式筛选器能够正确筛选适配:

<GridPane xmlns:fx="http://javafx.com/fxml" 
          fx:controller="javafxloginfxmldemo.FXMLLoginDemoDocumentController" 
          alignment="center" hgap="10" vgap="10"
          styleClass="root" >

    <stylesheets>
        <URL value="@Login.css" />
    </stylesheets>
    
    <Text id="welcome-text" text="欢迎登录FXML Demo系统"
          GridPane.columnIndex="0" GridPane.rowIndex="0"
          GridPane.columnSpan="2"/>

    <Text id="actiontarget" fx:id="actiontarget"
          GridPane.columnIndex="0" GridPane.columnSpan="2"
          GridPane.halignment="RIGHT" GridPane.rowIndex="6"/>
</GridPane>
5、 最终运行结果:
Paste_Image.png

FXML方式开发界面完成。

JavaFX Scene Builder 2.0协助开发

JavaFX Scene Builder 2.0下载位置
下载完成,一路安装,开始运行:

Paste_Image.png

非常简单的一个界面,就是做做界面……
配置一下:

Paste_Image.png
Paste_Image.png

选择JavaFX Scene Builder安装主目录,即可。

然后,双击或者右击打开FXML,则会自动使用SB编辑器打开。

NetBeans是JavaFX的一个开发工具,比较好用。
除此之外,e(fx)clipse也是一个不错的JavaFX开发工具,有时间可以适当查下资料,看看如何使用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容