JavaFx开发资料
按钮自适应
HBox.setHgrow(button2, Priority.ALWAYS);
窗口构成
新建工程,在Main.java中输入下列代码:
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
VBox layout = new VBox();
Label label = new Label("Hello world");
layout.getChildren().add(label);
Scene scene = new Scene(layout, 300, 300);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
JavaFX中的Stage可以看作是窗口,Scene是窗口中的内容,调用Stage的setScene函数来设置窗口内容,窗口可以在运行时切换显示的Scene,实现Tab页面的效果。
VBox是JavaFX中的一种布局,其中的元素纵向排列,向VBox中添加元素需要调用vbox.getChildren().add(control),如上所示。
构造Scene时传入顶层的布局(类似Qt中QMainWindow的CentralWidget)及大小。最后调用show函数将窗口显示出来。
按钮控件
控件(Control)是GUI框架中最重要的部分,也是用户与程序进行交互的媒介。
在JavaFX中使用控件需要导入包,例如
import javafx.scene.control.Label;
import javafx.scene.control.*;
框架中不同控件的使用方法大同小异,这里用最常用的按钮作为示例。
在窗口中添加按钮
构造一个Button对象并添加到VBox中:
Button button = new Button("Click me");
VBox layout = new VBox();
layout.getChildren().add(button);
Scene scene = new Scene(layout, 300, 300);
primaryStage.setScene(scene);
处理按钮点击事件
使用EventHandler接口
创建Handler类实现EventHandler接口
class Handler implements EventHandler<ActionEvent> {
@Override
public void handle(ActionEvent actionEvent) {
if(actionEvent.getSource() instanceof Button)
((Button) actionEvent.getSource()).setText("Click me again");
}
}
为按钮注册点击方法
button.setOnAction(new Handler());
Button还有setOnMouseClicked,setOnTouchPressed等方法,这些是专门为处理鼠标事件及触摸事件,setOnAction函数用来处理按钮触发事件(不管按钮被哪种方式触发,具体参考文档)。
由代码可以得出,setOnAction函数接收一个EventHandler接口,接口的handle方法用来处理事件。
使用匿名内部类
与上一方法同理,我们可以使用匿名内部类创建接口
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
if(actionEvent.getSource() instanceof Button)
((Button) actionEvent.getSource()).setText("Click me again");
}
});
使用Lambda表达
Java中的一些接口可以由lambda表达式代替,因此可以在setOnAction中传入lambda表达式:
button.setOnAction(actionEvent -> {
if(actionEvent.getSource() instanceof Button){
((Button) actionEvent.getSource()).setText("Click me again");
}
});
这样就可以在实现简单的事件处理器时不必再特意实现接口。
其他控件
使用其他控件的方法也都类似按钮,使用时可以查询文档,或者根据IDE的代码提示获知函数签名及使用方法。
多窗口
在一个桌面程序中往往有多个窗口,下面介绍添加窗口的方法。
创建窗口
添加MsgBox类
public class MsgBox {
public static void show(String title) {
Stage window = new Stage();
window.setTitle(title);
Button trueButton = new Button("True");
Button falseButton = new Button("False");
HBox hBox = new HBox(10); //10为元素间空隙
hBox.getChildren().addAll(trueButton, falseButton);
Scene scene = new Scene(hBox, 100, 100);
window.setScene(scene);
window.show();
}
}
与主窗口创建过程相同,新建stage、Scene、布局及控件,最后使用Stage的show方法显示出来。
调用MsgBox类的show方法即可显示窗口,函数的参数为窗口的标题。
设置主窗口中的按钮事件,点击按钮后会显示一个MsgBox窗口。
button.setOnAction(actionEvent -> MsgBox.show("SubWindow"));
窗口模态
Stage对象可以使用initModality方法设置窗口模态类型
window.initModality(Modality.WINDOW_MODAL);
类型包括 Modality.NONE, Modality.WINDOW_MODAL, Modality.APPLICATION_MODAL。
Modality.NONE: 不阻塞任何窗口
Modality.WINDOW_MODAL: 窗口级别的模态,仅仅阻塞与对话框关联的窗口,用户可以正常访问其他窗口,适合用于多窗口的程序。
Modality.APPLICATION_MODAL(默认值): 应用程序级别的模态,窗口将阻塞整个程序,无法访问程序中其他的窗口
返回子窗口的值
有时我们需要得到用户在子窗口中的操作,例如在本文的例子中,获知用户点了哪一个按钮。
接下来实现这样的功能——点击True按钮就在控制台打印true,否则打印’false’。
更改MsgBox中的代码
public static boolean show(String title) {
Stage window = new Stage();
window.setTitle(title);
Button trueButton = new Button("True");
Button falseButton = new Button("False");
trueButton.setOnAction(actionEvent -> {
answer = true;
window.close();
});
falseButton.setOnAction(actionEvent -> {
answer = false;
window.close();
});
HBox hBox = new HBox(10);
hBox.getChildren().addAll(trueButton, falseButton);
Scene scene = new Scene(hBox, 100, 100);
window.setScene(scene);
window.showAndWait();
return answer;
}
show函数返回一个boolean类型的值,这个值是由点击的按钮决定的,按钮点击后会关闭窗口,返回布尔值。
设置主窗口中按钮点击事件
button.setOnAction(actionEvent ->
{
var result = MsgBox.show("SubWindow");
System.out.println(result);
});
showAndWait函数
这个函数会阻塞当前事件,直到窗口被关闭后才会返回,并执行接下类的语句。在上例中,我们显示窗口并等待,直到点击按钮使窗口被关闭,才执行后面的return answer语句。
可以尝试改为调用show方法,观察返回的结果。
窗口的关闭
有时在用户关闭窗口时,需要执行一定的操作,例如保存设置、确认是否退出等。
这时我们可以通过setOnCloseRequest函数设置窗口关闭时触发的事件
window.setOnCloseRequest(windowEvent ->
{
System.out.println("The window will be closed!");
});
JavaFX在关闭窗口时,首先执行这一事件处理函数,再将窗口关闭。但在某些情况下(例如确认是否关闭),我们需要在处理事件时取消窗口的关闭,这种情况下可以调用windowEvent的consume方法,告诉事件系统,此事件已经被处理完毕,不必再执行其他处理动作(如关闭窗口)。
将主窗口的代码改为:
@Override
public void start(Stage primaryStage) throws Exception {
Button button = new Button("Click me");
button.setOnAction(actionEvent ->
{
var result = MsgBox.show("SubWindow");
System.out.println(result);
});
VBox layout = new VBox();
layout.getChildren().add(button);
Scene scene = new Scene(layout, 300, 300);
primaryStage.setScene(scene);
primaryStage.setTitle("Hello World");
primaryStage.setOnCloseRequest(windowEvent -> {
var result = MsgBox.show("Do you want to CLOSE?");
if (result == false) {
windowEvent.consume();
}
});
primaryStage.show();
}
当用户点击关闭按钮时,将会弹窗询问是否关闭,若用户点击False按钮窗口就不会被关闭。