JavaFX里如何自定义Dialog
王福强
当然,主要的可选项依然是两个:
- 基于javafx.stage.Stage
- 基于javafx.scene.control.Dialog
第一种很简单,就是以写一个JavaFX应用那样的”套路”新开一个窗口而已,所以,不做赘述,毕竟,写JavaFX首先就得先会写一个应用不是?
重点是第二种方式,即基于javafx.scene.control.Dialog进行自定义Dialog的设计和实现。
javafx.scene.control.Dialog是个范型类:Class Dialog<R>
这个R代表Dialog返回结果的类型,也就是对话框关闭之后返回的结果类型,如果我们要把Dialog中各个组件的数据返回给调用程序使用,那么,就要以R类型的形式返回,最简单的就是返回一个String,复杂点儿的就是把多个组件的数据打包成一个类型,比如scala里的case class或者kotlin里的data class, java里当然就是javabeans ;)
那如何打包数据让它们以R类型的形式返回给调用者呢? 这就得用到一个概念,叫resultConverter,在Dialog里有个属性叫resultConverterProperty,保存的就是相应的resultConverter,不过, resultConverter是概念,它对应的类型是Callback<ButtonType,R>
, 其实就是一个函数,接收ButtonType类型数据作为参数,然后返回R类型的数据作为结果,用函数来描述就是ButtonType => R
, 绝大多数情况下(只要我们希望Dialog关闭后给调用者返回数据),resultConverter是必须设置的。
一个常见的resultConverter实现逻辑类似于:
setResultConverter((buttonType) => if (buttonType == ButtonType.OK) Some(passwordF.getText) else None)
这里,我们只处理特定button类型对应的返回结果, 因为我们声明了一个简单的Dialog,返回值类型是Option[String]
,所以,我们在用户点击OK按钮之后,通过Some封装对话框里text field组件的值作为结果返回,其它情况下,都返回None。
这样,当调用者获得对话框返回结果之后,就可以进行类似如下的处理:
val dlg = new CustomDialog[Option[String]]()
.showAndWait().ifPresent(result =>
dlg.foreach(password => {
result.updateAdminPassword(password)
settings})
)
ifPresent是检查用户是点了OK还是Cancel,决定是否有返回结果,如果有返回结果(也就是result),那么,我们再根据返回结果类型对数据进行处理,因为这里我们的结果类型是Option[String]
,所以,我们通过foreach(也可以通过判断或者pattern matching)对结果进行了处理。
以上是数据交换的逻辑,即对话框与调用者之间数据交换的逻辑,下面我们再来看UI逻辑。
Dialog的UI主要通过设置Dialog对应的DialogPane的内容来实现,而DialogPane则通过调用Dialog的getDialogPane()获得引用,之后就可以向其中追加UI布局和组件了。
定制Dialog的UI主要是两种思路:
- 沿用Dialog的布局,做最简单的设置,比如直接setTitle,setContentText等等,然后再通过
getDialogPane.setExpandableContent(myLayout)
添加附加内容; - 直接结果Dialog的布局和内容,通过
getDialogPane.setContent(myLayout)
最大限度接管UI的布局和组件。;
除此之外,最后一个要定制的就是要显示什么按钮以及显示几个按钮,这是通过getDialogPane.getButtonTypes.addAll(ButtonType.OK, ButtonType.CANCEL,...)
来实现的,如果要对具体哪个按钮进行进一步的设置,则需要先取得这个按钮对应的组件,然后再进行设置:
val okButton = getDialogPane.lookupButton(ButtonType.OK)
.disableProperty().bind(Bindings.createBooleanBinding(() => StringUtils.isEmpty(passwordF.textProperty().get()), passwordF.textProperty())) okButton
至此,基本上一个自定义Dialog就完成了。
小结一下就是:
- 通过设置resultConverter对返回数据进行采集、转换和返回;
- 通过getDialogPane()取得Dialog对应的DialogPane做UI定制;
- 按钮按需添加、按需查找、按需设置;
就酱紫。
「福强私学」来一个?
「福强私学」, 一部沉淀了个人成长、技术与架构、组织与管理以及商业上的方法与心法的百科全书。
开天窗,拉认知,订阅「福报」,即刻拥有自己的全模态人工智能。