Custom JavaFX Dialogs – A Simple Alternative

github repo

This post is about an alternative approach to building custom dialogs. The official approach is here. My approach is simpler and, I think, more flexible.

Custom dialogs are basically windows or scenes with multiple text entry fields, which are shown modally. Simple dialogs like alerts, messages could still use the JavaFX Dialog<R> approach linked to above.

Here is the single class required – CustomDialog<T> (and a DialogResult<T> to help things along…)

Simple Custom Dialogs. Your code is in white.

CustomDialog<T>

This abstract class has only has one function to override:

 abstract fun result(): DialogResult<T>

Where T is the type of the value returned by the dialog. So your dialog implements this method so the dialog client can get a result, most often from the dialogs controller – which is not required by the Custom Dialog.

It also has a showAndWait method, which will show the dialog and return a DialogResult.

Usage

So if your custom dialog class is a subclass of CustomDialog<T>:

val dialog = YourCustomDialog(stage,"Your Label", "Dialog Title", "default value")
val result = dialog.showAndWait()
if (result.ok){
   // do something with result.data
}

Complete Example – SimpleValueDialog

This is a dialog which returns a single string value. I find it useful for getting user input for things like project names, object names, titles and so on. The code can be found here.

import javafx.fxml.FXMLLoader
import javafx.scene.Scene
import javafx.scene.layout.VBox
import javafx.stage.Stage

/**
 * Dialog for entering a single string value. Title, label and default parameters are all constructor arguments
 */
class SingleValueDialog(ownerStage: Stage, label: String, title: String, defaultValue: String?) : CustomDialog<String>(ownerStage, title) {

   var controller: SingleValueDialogController

   init {
      val loader = FXMLLoader(javaClass.getResource("/app5/singleValueDialog.fxml"))
      controller = SingleValueDialogController(label, defaultValue)
      loader.setController(controller)
      val root = loader.load<VBox>()
      stage.scene = Scene(root)
   }

   override fun result(): DialogResult<String> {
      val v = controller.getValue()
      if (v != null)
         return DialogResult(true, v)
      return DialogResult(false, null)
   }
}

That’s it.

The full code (including the SingleValueDialogController) is in app5 of this repo.