Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
创建自定义ScalaFX控件_Scala_Scalafx - Fatal编程技术网

创建自定义ScalaFX控件

创建自定义ScalaFX控件,scala,scalafx,Scala,Scalafx,创建自定义ScalaFX控件的正确方法是什么?我来自Swing和Scala Swing,在这里,定制组件只需通过扩展组件或面板来创建。但是当我尝试扩展ScalaFX的控件时,如果没有JavaFX控件委托,我就无法扩展它。我是否应该通过扩展基本JavFX类而不是ScalaFX类来创建自定义ScalaFX组件?一般来说,您需要: 创建自定义JavaFX控件 然后,可以选择在与默认模型相同的模型上创建自定义ScalaFX包装器。请注意,即使没有特定的ScalaFX包装器,某些ScalaFX功能(如绑

创建自定义ScalaFX控件的正确方法是什么?我来自Swing和Scala Swing,在这里,定制组件只需通过扩展
组件
面板
来创建。但是当我尝试扩展ScalaFX的
控件时,如果没有JavaFX
控件
委托,我就无法扩展它。我是否应该通过扩展基本JavFX类而不是ScalaFX类来创建自定义ScalaFX组件?

一般来说,您需要:

  • 创建自定义JavaFX控件
  • 然后,可以选择在与默认模型相同的模型上创建自定义ScalaFX包装器。请注意,即使没有特定的ScalaFX包装器,某些ScalaFX功能(如绑定)也可以正常工作-您可以看到
要创建自定义JavaFX控件,首先要签出的资源是,但更进一步。开源项目喜欢并提供了大量控件示例

显然,所有这些资源都展示了如何在Java中实现这一点。我看不出有什么理由不能在Scala中实现这一点(只要使用JavaFX类而不是ScalaFX类),但我找不到任何关于这方面的文档,所以我想用Java创建控件可能更安全

Edit:我提供了两个使用ScalaFX包装类的简单自定义JavaFX控件示例。一个版本,
YieldingSlider
,是扩展
Slider
类的单个Java类;另一个版本,
FxmlYieldingSlider
,基本上是相同的,但它展示了如何使用FXML文件和控制器类构造控件。请注意,可以在Scene Builder 2.0中导入从此项目生成的JAR文件,以便Scene Builder可以使用FXML中的
控件

下面是简单版本的外观

JavaFX控件:

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;
    }
}
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))
  }
}
<?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>
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
    }
  }
}
可用于FXML:

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;
    }
}
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))
  }
}
<?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>
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代码中加入一个笨拙的hack,这样它就可以处理
customscalafx.*
scalafx.*
一样。但这只是使用ScalaFXML时需要考虑的问题

编辑2:当我在编辑时,这里是同样的JavaFX控件,它是在Cala中编写的,而不是Java。它的工作原理相同,如果需要,可以用类似的ScalaFX包装器包装

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
}
package customjavafx.scene.control
导入javafx.event.EventHandler
导入javafx.scene.control.Slider
导入javafx.scene.input.MouseEvent
类scalayieldingsloider扩展滑块{
定义此值(最小值:双精度,最大值:双精度,值:双精度)={
这()
设置最小值(最小值)
setMax(最大值)
设置值(值)
}
//对Java8SAMS(lambdas)的支持在Scala2.11中仍处于试验阶段。
//我改用了老学校的匿名班。
addEventFilter(MouseeEvent.MOUSE_按下,新事件处理程序[MouseeEvent]{
def句柄(事件:MouseeEvent):单位=lastTimeMousePressed=System.currentTimeMillis
})
private var lastTimeMousePressed:Long=0
def mouseWasPressedWithinLast(t:Long):布尔值=

(System.currentTimeMillis-lastTimeMousePressed)仅供参考,我在下面的回答中添加了一个示例。出于好奇,我还尝试在Scala中扩展JavaFX控件,因此我将其添加到示例中。