2

I have a main window with some information. I can't start the Alert by timer. I need to show alert every 10 seconds(with working main window) and by the alert's button change the Label's text in the main window. I have this code, but it's not work:

object main extends JFXApp {
 stage = new JFXApp.PrimaryStage() {
   scene = new Scene {
    val MyLabel = new Label("SomeText")
    root = new VBox {
        children = MyLabel
     }
   }
 val ButtonTypeOne = new ButtonType("Change the text")
 val ButtonTypeTwo = new ButtonType("No")

  val alert1 = new Alert(AlertType.Warning) {
        initOwner(stage)
        title = "Warning!!!"
        headerText = "Header"
        contentText = "Do you need to change the text?"
        buttonTypes = Seq(ButtonTypeOne, ButtonTypeTwo, ButtonType.Cancel)
      }
    val result = alert1.showAndWait()
    val timerA = new PauseTransition(Duration(5000))
              timerA.onFinished = { _ =>
                result match {
                  case Some(ButtonTypeOne) => /*Here I need to change text in MyLabel */
                  case Some(ButtonTypeTwo) => None
                  case _ => None
                 }
               timerA.playFromStart()
              }
    timerA.play
 }
}

1 Answers1

1

There are a few different problems in your code:

  1. You display the alert only once, regardless of what's happening with the timer.
  2. The code that reacts to the result of the alert in the timer always looks at the same initial result.
  3. Unfortunately, even if you move the val result = alert1.showAndWait inside of the timer's animation update event, JavaFX makes it illegal to call showAndWait within such a routine.

The solution is to create an onHidden event handler for alert1, which reacts to it being closed. The button type used to close the dialog is then stored in alert1.result, so you can use that to determine what action to take.

I've added a StringProperty to assist with the changing of the label value. The following example should be a good starting point for what you want to achieve...

import scalafx.Includes._
import scalafx.animation.PauseTransition
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.beans.property.StringProperty
import scalafx.scene.Scene
import scalafx.scene.layout.VBox
import scalafx.scene.control.{Alert, ButtonType, Label}
import scalafx.scene.control.Alert.AlertType
import scalafx.util.Duration

object main extends JFXApp {

  // String property for the text in myLabel.
  val strProp = StringProperty("Some Text")

  // Declare this so that it's accessible from timerA.onFinished.
  val myLabel = new Label {

    // Bind the text property to the value of strProp.
    // When strProp's value changes, so does the label's text.
    text <== strProp
  }

  stage = new PrimaryStage() {
    scene = new Scene {
      root = new VBox {
        children = myLabel
      }
    }
  }

  // Custom buttons.
  val ButtonTypeOne = new ButtonType("Change the text")
  val ButtonTypeTwo = new ButtonType("No")

  // Create the timer. This goes off after 5,000ms (5 seconds) - after play is called.
  val timerA = new PauseTransition(Duration(5000))

  // Alert dialog.
  // Note: JavaFX forbids use of showAndWait within animation processing, so we must use
  // an onHidden event instead.
  val alert1 = new Alert(AlertType.Warning) {
    initOwner(stage)
    title = "Warning!!!"
    headerText = "Header"
    contentText = "Do you need to change the text?"
    buttonTypes = Seq(ButtonTypeOne, ButtonTypeTwo, ButtonType.Cancel)
  }

  // React to the dialog being closed.
  alert1.onHidden = {_ =>
    alert1.result.value match {

      // If button type one, change the property value.
      // Note alert1.result.value is a JavaFX ButtonType, so use .delegate for the match.
      case ButtonTypeOne.delegate => strProp.value = "Changed!"

      // Otherwise, do nothing.
      case _ =>
    }

    // Start the timer once more.
    // This is going to be a very annoying app! ;-)
    timerA.playFromStart()
  }

  // When the timer goes off, show the alert.
  timerA.onFinished = {_ =>
    alert1.show()
  }

  // Start the timer for the first time.
  timerA.play
}
Mike Allen
  • 8,139
  • 2
  • 24
  • 46