首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >创建自定义ScalaFX控件

创建自定义ScalaFX控件
EN

Stack Overflow用户
提问于 2014-08-20 09:21:39
回答 1查看 1.4K关注 0票数 4

创建自定义ScalaFX控件的正确方法是什么?我来自Swing和Swing,其中的定制组件只是通过扩展ComponentPanel来创建的。但是,当我试图扩展ScalaFX的Control时,如果没有JavaFX Control委托,就无法扩展它。我应该通过扩展基类而不是ScalaFX类来创建自定义JavFX组件吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-03 19:02:17

一般来说,你会想:

  • 创建自定义JavaFX控件。
  • 然后,可以选择在与默认模型相同的模型上创建自定义ScalaFX包装器。注意,一些ScalaFX特性(如绑定)即使没有特定的ScalaFX包装器也能正常工作--您可以看到这里的一些例子

要创建自定义的JavaFX控件,第一个签出的资源是本Oracle教程,但是这篇博客文章更进一步。像ControlsFXJFXtras这样的开源项目提供了大量的控件示例。

显然,所有这些资源都显示了如何在Java中进行操作。我看不出有什么理由不能在Scala中这样做(只要使用JavaFX类而不是ScalaFX类)--但我无法找到关于它的任何文档,所以我想在Java中创建控件可能更安全。

编辑:,我提供了两个简单的自定义JavaFX控件和ScalaFX包装类的示例。一个版本,YieldingSlider,是一个扩展Slider类的Java类;另一个版本,FxmlYieldingSlider,基本上是一样的,但是它展示了如何用FXML文件和控制器类构造一个控件。请注意,从这个项目构建的JAR文件可以在场景Builder2.0中导入,这样场景生成器就可以在FXML中使用<YieldingSlider><FxmlYieldingSlider>控件。

以下是简单版本的样子。

JavaFX控件:

代码语言:javascript
复制
package customjavafx.scene.control;

import javafx.scene.control.Slider;
import javafx.scene.input.MouseEvent;

public class YieldingSlider extends Slider {

    public YieldingSlider() {
        addEventFilter(MouseEvent.MOUSE_PRESSED, event -> lastTimeMousePressed = System.currentTimeMillis());
    }

    public YieldingSlider(final double min, final double max, final double value) {
        this();
        setMin(min);
        setMax(max);
        setValue(value);
    }

    private long lastTimeMousePressed = 0;

    public boolean mouseWasPressedWithinLast(final long t) {
        return (System.currentTimeMillis() - lastTimeMousePressed) <= t;
    }
}

ScalaFX包装器:

代码语言:javascript
复制
package customscalafx.scene.control

import scala.language.implicitConversions
import customjavafx.scene.{control => jfxsc}
import scalafx.scene.control.Slider

object YieldingSlider {
  implicit def sfxSlider2jfx(v: YieldingSlider) = v.delegate
}

class YieldingSlider(override val delegate: jfxsc.YieldingSlider = new jfxsc.YieldingSlider) extends Slider {

  /** Constructs a Slider control with the specified slider min, max and current value values. */
  def this(min: Double, max: Double, value: Double) {
    this(new jfxsc.YieldingSlider(min, max, value))
  }
}

可用于FXML:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>

<?import customjavafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <YieldingSlider AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
   </children>
</AnchorPane>

或in ScalaFX DSL:

代码语言:javascript
复制
package guilgaly.fxtest.mp3player

import customscalafx.scene.control.YieldingSlider

import scalafx.application.JFXApp
import scalafx.scene.Scene

object TestApp extends JFXApp {
  stage = new JFXApp.PrimaryStage {
    scene = new Scene {
      content = new YieldingSlider
    }
  }
}

最后,请注意,如果将它与ScalaFXML一起使用,则不会在控制器中正确注入它,因为ScalaFXML查找其包以scalafx.*开头的类(并期望在同一个包中包含相应的JavaFX类,但使用javafx.*)。但是,如果使用以javafx.*开头的包,则无法在场景生成器中导入控件。我的解决方案是在ScalaFXML代码中加入一个笨拙的黑客,这样它就可以像处理scalafx.*一样处理customscalafx.*。但这只是在使用ScalaFXML时需要考虑的问题。

编辑2:在我做的时候,这里有相同的JavaFX控件编写的inScala,而不是inScala。它的工作原理是一样的,如果需要的话可以用类似的ScalaFX包装包包装。

代码语言:javascript
复制
package customjavafx.scene.control

import javafx.event.EventHandler
import javafx.scene.control.Slider
import javafx.scene.input.MouseEvent

class ScalaYieldingSlider extends Slider{
  def this(min: Double, max: Double, value: Double) = {
    this()
    setMin(min)
    setMax(max)
    setValue(value)
  }
  // Support for Java 8 SAMs (lambdas) is still experimental in Scala 2.11.
  // I used the old-school anonymous class instead.
  addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler[MouseEvent] {
    def handle(event: MouseEvent): Unit = lastTimeMousePressed = System.currentTimeMillis
  })

  private var lastTimeMousePressed: Long = 0

  def mouseWasPressedWithinLast(t: Long): Boolean =
    (System.currentTimeMillis - lastTimeMousePressed) <= t
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25401094

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档