用到了kotlin 协程、带方法的枚举类等知识点
代码语言:txt复制import javafx.beans.property.SimpleObjectProperty
import javafx.geometry.Orientation
import javafx.scene.canvas.Canvas
import javafx.scene.canvas.GraphicsContext
import javafx.scene.control.TextFormatter
import javafx.scene.control.ToggleGroup
import javafx.scene.paint.Color
import kotlinx.coroutines.*
import tornadofx.*
import kotlin.math.PI
import kotlin.math.max
import kotlin.math.sin
class FractalApp : App(FractalView::class)
class FractalController : Controller() {
val v by inject<FractalView>()
val canvas0 = v.canvas0
fun draw(fs: FractalShape1)= GlobalScope.launch {
canvas0.graphicsContext2D.clearRect(0.0, 0.0, canvas0.width, canvas0.height)
fs.drawFractal(canvas0.graphicsContext2D,
v.x.value,
v.y.value,
v.widthh.value.toDouble(),
v.heightt.value.toDouble(),
v.depth.value,
v.maxDepth.value,
v.color.value)
}
}
class FractalView : View("分形图动画演示") {
val c by inject<FractalController>()
val fractal = SimpleObjectProperty(this, "fractal", FractalShape1.Rectangle)
val x = doubleProperty()
val y = doubleProperty()
val widthh = intProperty(700)
val heightt = intProperty(600)
val depth = intProperty(4)
val maxDepth = intProperty(6)
val color = SimpleObjectProperty(this, "color", MyColor1.Indigo)
lateinit var canvas0: Canvas
lateinit var shapeGoup: ToggleGroup
// 过滤输入,只能输入1以上的正整数
val firstTenFilter: (TextFormatter.Change) -> Boolean = { change ->
!change.isAdded || change.controlNewText.let {
it.isInt() && it.toInt() in 1..Int.MAX_VALUE
}
}
override val root = borderpane {
style = "-fx-font-size: 14pt; "
right = vbox(5) {
prefWidth=300.0
form {
fieldset(labelPosition = Orientation.HORIZONTAL) {
vbox(5) {
field("x:") {
textfield(x) {
text = "10"
filterInput(firstTenFilter)
}
}
field("y:") {
textfield(y) {
text = "10"
filterInput(firstTenFilter)
}
}
field("widthh:") {
spinner(100, 1000, 400, 100, false, widthh)
}
field("heightt:") {
spinner(100, 1000, 400, 100, false, heightt)
}
field("depth:") {
spinner(1, 10, 4, 1, false, depth)
}
field("maxDepth:") {
spinner(1, 10, 4, 1, false, maxDepth)
}
}
vbox(5) {
field("color:") {
combobox(property = color, values = MyColor1.all) {
selectionModel.selectedItemProperty().addListener { _, _, _ ->
c.draw(fractal.value)
}
}
}
field("depth:") {
slider(1, 10, 4) {
isShowTickLabels = true
isShowTickMarks = true
valueProperty().bindBidirectional(depth)
}
}
field("maxDepth:") {
slider(1, 10, 6) {
isShowTickLabels = true
isShowTickMarks = true
valueProperty().bindBidirectional(maxDepth)
}
}
shapeGoup = togglegroup {
FractalShape1.values().forEach { fs ->
radiobutton(fs.name) {
action {
// 实现ToggleGroup与combobox联动
fractal.value = fs
c.draw(fs)
}
}
}
}
}
}
}
}
center = stackpane {
canvas0 = canvas(800.0, 700.0)
paddingAll = 10
}
}
}
enum class MyColor1(val color: Color) {
Red(Color.RED), Blue(Color.BLUE), Indigo(Color.INDIGO), Yellow(Color.YELLOW);
companion object {
val all by lazy { values().toList() }
}
}
//分形形状,矩形、圆、椭圆
enum class FractalShape1 {
Rectangle {
override suspend fun drawFractal(g: GraphicsContext, x: Double, y: Double, w: Double, h: Double, depth: Int, maxDepth: Int, color: MyColor1) {
g.fill = color.color
if (depth == maxDepth) {
g.fillRect(x, y, w, h)
return
}
if ((w <= 1).and(h <= 1)) {
g.fillRect(x, y, max(w, 1.0), max(h, 1.0))
return
}
val w_3 = w / 3
val h_3 = h / 3
delay(delay0)
drawFractal(g, x, y, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x 2 * w_3, y, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x w_3, y h_3, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x, y 2 * h_3, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x 2 * w_3, y 2 * h_3, w_3, h_3, depth 1, maxDepth, color)
return
}
},
Circle {
override suspend fun drawFractal(g: GraphicsContext, x: Double, y: Double, w: Double, h: Double, depth: Int, maxDepth: Int, color: MyColor1) {
g.fill = color.color
if (depth == maxDepth) {
g.fillOval(x, y, w, w)
return
}
if (w <= 1) {
g.fillOval(x, y, max(w, 1.0), max(w, 1.0))
return
}
val w_3 = w / 3
val h_3 = h / 3
delay(delay0)
drawFractal(g, x, y, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x 2 * w_3, y, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x w_3, y h_3, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x, y 2 * h_3, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x 2 * w_3, y 2 * h_3, w_3, h_3, depth 1, maxDepth, color)
return
}
},
Triangle {
override suspend fun drawFractal(g: GraphicsContext, x: Double, y: Double, w: Double, h: Double, depth: Int, maxDepth: Int, color: MyColor1) {
var side = w
val y=y-20
if (side <= 1) {
Rectangle.drawFractal(g, x, y, 1.0, 1.0, depth, maxDepth, color)
return
}
val bx = x side
val by = y
val h = sin(60 * PI / 180) * side
val cx = x side / 2
val cy = y - h
if (depth == maxDepth) {
drawTriangle(g, x, y, bx, by, cx, cy, color)
return
}
val ab_centerx = (x bx) / 2
val ab_centery = (y by) / 2
val ac_centerx = (x cx) / 2
val ac_centery = (y cy) / 2
delay(delay0)
// 左下角三角形
drawFractal(g, x, y, w / 2, h, depth 1, maxDepth, color)
delay(delay0)
// 上三角形
drawFractal(g, ac_centerx, ac_centery, w / 2, h, depth 1, maxDepth, color)
delay(delay0)
// 右下角三角形
drawFractal(g, ab_centerx, ab_centery, w / 2, h, depth 1, maxDepth, color)
}
},
Ellipse {
override suspend fun drawFractal(g: GraphicsContext, x: Double, y: Double, w: Double, h: Double, depth: Int, maxDepth: Int, color: MyColor1) {
g.fill = color.color
if (depth == maxDepth) {
g.fillOval(x, y, w, h)
return
}
if ((w <= 1).and(h <= 1)) {
g.fillOval(x, y, max(w, 1.0), max(h, 1.0))
return
}
delay(delay0)
val w_3 = w / 3
val h_3 = h / 3*0.8
drawFractal(g, x, y, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x 2 * w_3, y, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x w_3, y h_3, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x, y 2 * h_3, w_3, h_3, depth 1, maxDepth, color)
delay(delay0)
drawFractal(g, x 2 * w_3, y 2 * h_3, w_3, h_3, depth 1, maxDepth, color)
return
}
};
companion object {
val delay0=100L
val all by lazy { values().toList() }
}
fun drawTriangle(g: GraphicsContext, ax: Double, ay: Double, bx: Double, by: Double, cx: Double, cy: Double, color: MyColor1) {
g.fill = color.color
g.strokePolygon(doubleArrayOf(ax, bx, cx, ax), doubleArrayOf(-ay, -by, -cy, -ay), 3)
}
abstract suspend fun drawFractal(g: GraphicsContext, x: Double, y: Double, w: Double, h: Double, depth: Int, maxDepth: Int, color: MyColor1)
}