我正在使用ScalaFX / JavaFX和FXML在Scala中编写应用程序.当您使用FXML在JavaFX中定义视图时,FXML中定义的对象(例如按钮和文本字段)将通过以下方式注入控制器:
>将一个fx:id属性添加到FXML元素
>使用@FXML注释添加(通常是私有的)字段到控制器,并使用与FXML中定义的fx:id属性值匹配的字段名称
>当FXmloader实例化控制器时,它会通过反射自动将fx:id注释元素注入到控制器的匹配@FXML注释字段中
我不是现场注射的忠实粉丝,但这就是FXML的工作方式.但是,由于编译器在某些情况下执行的字段名称修改,我在Scala中遇到了意外的并发症……
这是一个示例应用程序:
test / TestApp.scala(没什么好玩的,只需要运行这个例子)
package test import javafx.application.Application import javafx.fxml.FXMLLoader import javafx.scene.{Scene,Parent} import javafx.stage.Stage object TestApp { def main(args: Array[String]) { Application.launch(classOf[TestApp],args: _*) } } class TestApp extends Application { override def start(primaryStage: Stage): Unit = { val root: Parent = FXMLLoader.load(getClass.getResource("/test.fxml")) val scene: Scene = new Scene(root,200,200) primaryStage.setTitle("Test") primaryStage.setScene(scene) primaryStage.show() } }
test.fxml(视图)
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.*?> <?import java.lang.*?> <?import javafx.scene.layout.*?> <VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefheight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="test.TestController"> <children> <CheckBox fx:id="testCheckBox" mnemonicParsing="false" text="CheckBox"/> <Button fx:id="testButton" mnemonicParsing="false" text="Button"/> </children> </VBox>
test / TestController.scala(test.fxml视图的控制器)
package test import javafx.fxml.FXML import javafx.scene.{control => jfxsc} import scalafx.Includes._ class TestController { @FXML private var testCheckBox: jfxsc.CheckBox = _ @FXML private var testButton: jfxsc.Button = _ def initialize(): Unit = { println(s"testCheckBox=$testCheckBox") println(s"testButton=$testButton") testCheckBox.selected.onChange { testButton.text = "changed" } } }
运行应用程序时,println语句显示testCheckBox正确注入,但testButton为null.如果我单击复选框,则在调用testButton.text_ =时会出现预期的NullPointerException.
查看编译的类时,原因很明显:
>对于在initialize()方法中传递给testCheckBox.selected.onChange()的匿名函数,有一个TestController $$anonfun $initialize $1类
>在TestController类中,有两个私有字段:testCheckBox(如预期的那样)和test $TestController $$testButton(而不仅仅是testButton),以及accessor / mutator方法.其中,只有test $TestController $$testButton的访问器方法是公共的.
很明显,Scala编译器损坏了testButton字段的名称,因为它必须公开其访问器方法(从TestController $$anonfun $initialize $1访问它),因为字段和accesor / mutator方法应保持相同的名称.
现在,最后,我的问题是:有没有合理的解决方案来处理这种情况?现在,我所做的是将字段公开:因为编译器不需要改变它们的可见性,所以它不会破坏它们的名字.但是,这些领域真的没有公开的业务.
注意:另一个解决方案是使用scala-fxml库,它完全隐藏了字段注入,但出于其他原因,我宁愿使用bog标准的FXML加载.
解决方法
@FXML var popoutButton: Button = _
IOW,离开私人,事情很好.如果你来自Java世界,感觉有点脏,但解决方法需要更多的代码.
fx隐含的控制器:include也可以正常工作:
FXML:
<fx:include fx:id="paramTable" source="ParameterTable.fxml" />
斯卡拉:
@FXML var paramTable: TableView[(ModelParameter,ParameterValue)] = _ @FXML var paramTableController: ParameterTableController = _
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。