在tornadofx中使用javafx并发框架示例

javafx.concurrent中包含:

1个接口Worker<V>,

4个类:

  1. Task,不可重复使用,即一次性任务
  2. Service,可重复使用,
  3. ScheduledService,可间隔一定时间,反复运行
  4. WorkerStateEvent,

1个枚举javafx.concurrent.Worker.State,代表Worker的不同状态READY,SCHEDULED,RUNNING,SUCCEEDED,CANCELLED,FAILED

Task,Service,ScheduledService等3个类均为抽象类,均实现了Worker<V>接口,代表不同的任务类型

import javafx.application.Platform
import javafx.beans.binding.Bindings
import tornadofx.*
import javafx.beans.binding.When
import javafx.collections.ObservableList
import javafx.concurrent.Worker
import kotlin.math.ceil
import kotlin.math.sqrt
import javafx.collections.FXCollections
import javafx.concurrent.ScheduledService
import javafx.concurrent.Service
import javafx.concurrent.Task
import javafx.concurrent.Worker.State.READY
import javafx.concurrent.Worker.State.RUNNING
import javafx.concurrent.Worker.State.SCHEDULED
import javafx.scene.layout.BorderStrokeStyle.SOLID
import javafx.scene.paint.Color
import javafx.util.Duration

class FxConcurrentApp : App(FxConcurrentView::class,Mystyle::class)

class FxConcurrentView : View("A Prime Number Finder Task") {

    // Create the service
    // ScheduledService在任务执行成功或失败后可自动重启
    private var service: ScheduledService<ObservableList<Long>> = object : ScheduledService<ObservableList<Long>>() {
        override fun createTask(): Task<ObservableList<Long>> {
            return PrimeFinderTask()
        }
    }
    var onceStarted = false

    override val root = borderpane {
        paddingAll = 10.0
        top = hbox(5) {
            service.delay = Duration.seconds(2.0)
            service.period = Duration.seconds(3.0)
            service.maximumFailureCount = 5
            button("Start") {
                action {
                    if (onceStarted) {
// restart()方法会依次调用cancel(),reset(),start()等3个方法
                        service.restart()
                    } else {
                        service.start()
                        onceStarted = true
                        text = "Restart"
                    }
                }
            }
            button("Cancel") {
                disableProperty().bind(service.stateProperty().isNotEqualTo(RUNNING))
                action {
                    service.cancel()
                }
            }
            button("Exit") {
                action {
                    Platform.exit()
                }
            }
            button("Reset") {
                disableProperty().bind(Bindings.or(service.stateProperty().isEqualTo(RUNNING),
                        service.stateProperty().isEqualTo(SCHEDULED)))

                action {
                    service.reset()
                }
            }
        }
        center {
            add(WorkerStateGUI(service))
        }
    }
}


class FxConcurrentView2 : View("A Prime Number Finder Task") {
    // Create the service
    // Service<V>类是接口Worker<V>的抽象实现,它包装了抽象类Task<V>,
    // 让Task<V>可以开始start,取消cancell,重置reset和重新开始restart,
//    Service<V>抽象类包含createTask()抽象方法,访方法返回Task<V>实例
    private var service: Service<ObservableList<Long>> = object : Service<ObservableList<Long>>() {
        override fun createTask(): Task<ObservableList<Long>> {
            return PrimeFinderTask()
        }
    }
    var onceStarted = false
    override val root = borderpane {
        paddingAll = 10.0
        top = hbox(5) {
            button("Start") {
                action {
                    if (onceStarted) {
                        service.restart()
                    } else {
                        service.start()
                        onceStarted = true
                        text = "Restart"
                    }
                }
            }
            button("Cancel") {
                disableProperty().bind(service.stateProperty().isNotEqualTo(RUNNING))
                action {
                    service.cancel()
                }
            }
            button("Reset") {
                disableProperty().bind(Bindings.or(service.stateProperty().isEqualTo(RUNNING),
                        service.stateProperty().isEqualTo(SCHEDULED)))
                action {
                    service.reset()
                }
            }
            button("Exit") {
                action {
                    Platform.exit()
                }
            }
        }
        center {
            add(WorkerStateGUI(service))
        }
    }
}

class FxConcurrentView1 : View("A Prime Number Finder Task") {
    var task = PrimeFinderTask()
    override val root = borderpane {
        paddingAll = 10.0
        top = hbox(5) {
            button("Start") {
                disableProperty().bind(task.stateProperty().isNotEqualTo(READY))
                action {
                    startTask()
                }
            }
            button("Cancel") {
                disableProperty().bind(task.stateProperty().isNotEqualTo(RUNNING))
                action {
                    task.cancel()
                }
            }
            button("Exit") {
                action {
                    Platform.exit()
                }
            }
        }
        center {
            add(WorkerStateGUI(task))
        }
    }

    private fun startTask() {
        // Schedule the task on a background thread
        val backgroundThread = Thread(task)
        backgroundThread.isDaemon = true
        backgroundThread.start()
    }
}

class WorkerStateGUI() : Fragment() {

    constructor(worker: Worker<ObservableList<Long>>) : this() {
        bindToWorker(worker)
    }

    private val title0 = stringProperty("")
    private val message = stringProperty("")
    private val running = stringProperty("")
    private val state = stringProperty("")
    private val totalWork = stringProperty("")
    private val workDone = stringProperty("")
    private val value0 = stringProperty("")
    private val progress = stringProperty("")
    private val exception = stringProperty("")
    private val progressbar0 = doubleProperty(0.0)

    override val root = form {
        fieldset {
            field("Title:") {
                label(title0)
            }
            field("Message:") {
                label(message)
            }
            field("Running:") {
                label(running)
            }
            field("State:") {
                label(state)
            }
            field("Total Work:") {
                label(totalWork)
            }
            field("Work Done:") {
                label(workDone)
            }
            field("Progress:") {
                progressbar(progressbar0)
                label(progress)
            }
            field("Value:") {
                textarea(value0) {
                    prefRowCount = 3
                    prefColumnCount = 20
                }
            }
            field("Exception:") {
                textarea(exception) {
                    prefRowCount = 3
                    prefColumnCount = 20
                }
            }
        }
    }

    private fun bindToWorker(worker: Worker<ObservableList<Long>>) {
        // Bind Labels to the properties of the worker
        title0.bind(worker.titleProperty())
        message.bind(worker.messageProperty())
        running.bind(worker.runningProperty().asString())
        state.bind(worker.stateProperty().asString())

        totalWork.bind(
                When(worker.totalWorkProperty().isEqualTo(-1)).then("Unknown")
                        .otherwise(worker.totalWorkProperty().asString()))

        workDone.bind(
                When(worker.workDoneProperty().isEqualTo(-1)).then("Unknown")
                        .otherwise(worker.workDoneProperty().asString()))

        progress.bind(
                When(worker.progressProperty().isEqualTo(-1)).then("Unknown")
                        .otherwise(worker.progressProperty().multiply(100.0).asString("%.2f%%")))

        progressbar0.bind(worker.progressProperty())
        value0.bind(worker.valueProperty().asString())

        worker.exceptionProperty().addListener { _, _, newValue ->
            if (newValue != null) {
                exception.value = newValue.message
            } else {
                exception.value = ""
            }
        }
    }
}

object PrimeUtil {
    fun isPrime(num: Long): Boolean {
        if (num <= 1 || num % 2 == 0L) {
            return false
        }

        val upperDivisor = ceil(sqrt(num.toDouble())).toInt()

        var divisor = 3
        while (divisor <= upperDivisor) {
            if (num % divisor == 0L) {
                return false
            }
            divisor += 2
        }

        return true
    }
}

class PrimeFinderTask : Task<ObservableList<Long>> {
    // Define the Limits
    private var lowerLimit: Long = 1
    private var upperLimit: Long = 10
    private var sleepTimeInMillis: Long = 100

    constructor()

    constructor(lowerLimit: Long, upperLimit: Long) {
        this.lowerLimit = lowerLimit
        this.upperLimit = upperLimit
    }

    constructor(lowerLimit: Long, upperLimit: Long, sleepTimeInMillis: Long) : this(lowerLimit, upperLimit) {
        this.sleepTimeInMillis = sleepTimeInMillis
    }

    // The task implementation
    override fun call(): ObservableList<Long> {
        // An observable list to represent the results
        val results = FXCollections.observableArrayList<Long>()

        // Update the title
        this.updateTitle("Prime Number Finder Task")
        val count = this.upperLimit - this.lowerLimit + 1
        var counter: Long = 0

        // Find the prime numbers
        for (i in lowerLimit..upperLimit) {
            // Check if the task is cancelled
            if (this.isCancelled) {
                break
            }

            // Increment the counter
            counter++

            // Update message
            this.updateMessage("Checking $i for a prime number")

            // Sleep for some time
            try {
                Thread.sleep(this.sleepTimeInMillis)
            } catch (e: InterruptedException) {
                // Check if the task is cancelled
                if (this.isCancelled) {
                    break
                }
            }

            // Check if the number is a prime number
            if (PrimeUtil.isPrime(i)) {
                // Add to the list
                results.add(i)

                // Publish the read-only list to give the GUI
                // access to the partial results
                updateValue(FXCollections.unmodifiableObservableList(results))
            }

            // Update the progress
            updateProgress(counter, count)
        }

        return results
    }

    override fun cancelled() {
        super.cancelled()
        updateMessage("The task was cancelled.")
    }

    override fun failed() {
        super.failed()
        updateMessage("The task failed.")
    }

    override fun succeeded() {
        super.succeeded()
        updateMessage("The task finished successfully.")
    }
}

class Mystyle:Stylesheet(){
    init {
        root{
            padding= box(10.px)
            borderWidth+=box(2.px)
            borderInsets+=box(5.px)
            borderRadius+=box(5.px)
            borderColor+= box(Color.BLUE)
            borderStyle+=SOLID
        }
    }
}

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券