Skip to content

Commit 642a084

Browse files
committed
Add helper UI for running batch processing tasks #34
1 parent 7ae35f3 commit 642a084

File tree

8 files changed

+699
-2
lines changed

8 files changed

+699
-2
lines changed

ReadMe.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,9 @@ to parent size.
334334

335335
### Batch Processing and Progress Dialog
336336

337-
Work in progress, see `ProgressStatusDemoApp` for example of use
337+
Work in progress
338+
* Helper UI for running batch processing tasks, see `BatchRunnerProgressHelperDemoApp` for example of use
339+
* Component for display of progress of batch processing tasks, see `ProgressStatusDemoApp` for example of use
338340

339341

340342
Demos

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import scala.xml.{Node => XmlNode, NodeSeq => XmlNodeSeq, _}
99
// JAR_BUILT_BY - Name to be added to Jar metadata field "Built-By" (defaults to System.getProperty("user.name")
1010
//
1111

12-
val projectVersion = "0.9.0.3-SNAPSHOT"
12+
val projectVersion = "0.9.0.5-SNAPSHOT"
1313
val versionTagDir = if (projectVersion.endsWith("SNAPSHOT")) "master" else "v." + projectVersion
1414
val _scalaVersions = Seq("3.3.3", "2.13.14", "2.12.19")
1515
val _scalaVersion = _scalaVersions.head
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2000-2023 Jarek Sacha. All Rights Reserved.
3+
* Author's e-mail: jpsacha at gmail.com
4+
*/
5+
6+
package org.scalafx.extras.batch
7+
8+
import org.scalafx.extras.BusyWorker
9+
import org.scalafx.extras.BusyWorker.SimpleTask
10+
import scalafx.application.JFXApp3
11+
import scalafx.application.JFXApp3.PrimaryStage
12+
import scalafx.geometry.Insets
13+
import scalafx.scene.Scene
14+
import scalafx.scene.control.{Button, Label}
15+
import scalafx.scene.layout.VBox
16+
import scalafx.stage.Window
17+
18+
import scala.util.Random
19+
20+
object BatchRunnerProgressHelperDemoApp extends JFXApp3:
21+
22+
private lazy val busyWorker = new BusyWorker(Title, parentWindow)
23+
private val Title = "Batch Processing / Progress Dialog Demo"
24+
25+
private val nTasks = 100
26+
private val minTime = 500
27+
private val maxTime = 1000
28+
29+
override def start(): Unit =
30+
stage = new PrimaryStage:
31+
title = Title
32+
scene = new Scene:
33+
content = new VBox:
34+
padding = Insets(21)
35+
spacing = 14
36+
children = Seq(
37+
new Label(
38+
s"""Press "Run" to initiate processing.
39+
|Wait till processing finished or press "Abort".
40+
|There will be $nTasks processed.
41+
|Tasks will have randomly generated time between $minTime and $maxTime ms.
42+
|If task's time is divisible by 6, that task will fail.
43+
|""".stripMargin
44+
),
45+
new Button("Run Sequential"):
46+
onAction = (_) => onStart(false)
47+
prefWidth = 120
48+
,
49+
new Button(" Run Parallel "):
50+
onAction = (_) => onStart(false)
51+
prefWidth = 120
52+
)
53+
54+
private def onStart(useParallelProcessing: Boolean): Unit = busyWorker.doTask("Start") {
55+
new SimpleTask[Unit]:
56+
override def call(): Unit =
57+
val helper =
58+
new BatchRunnerProgressHelper[String]("Sample batch processing", parentWindow, useParallelProcessing):
59+
override def createSampleTasks(): Seq[ItemTask[String]] =
60+
val r = new Random()
61+
(1 to nTasks).map { i =>
62+
new ItemTask[String]:
63+
override val name = s"Task #$i"
64+
65+
override def run(): String =
66+
val t = minTime + r.nextInt(maxTime - minTime)
67+
Thread.sleep(t)
68+
if t % 6 == 0 then throw new Exception(s"Do not like ${t}")
69+
s"name t = $t"
70+
}
71+
helper.run()
72+
}
73+
74+
def parentWindow: Option[Window] = Option(stage)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2011-2024, ScalaFX Project
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
* * Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* * Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
* * Neither the name of the ScalaFX Project nor the
13+
* names of its contributors may be used to endorse or promote products
14+
* derived from this software without specific prior written permission.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL THE SCALAFX PROJECT OR ITS CONTRIBUTORS BE LIABLE
20+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*/
27+
28+
package org.scalafx.extras.batch
29+
30+
import scala.util.{Failure, Success}
31+
32+
33+
object ParallelBatchRunnerDemo {
34+
class DemoTaskItem(n: Int) extends ItemTask[Int] {
35+
val name = s"Demo TaskItem $n"
36+
37+
def run(): Int = {
38+
// println(s"Item ${n} - start")
39+
Thread.sleep(300)
40+
if n == 7 then
41+
// println(s"Item ${n} - error")
42+
throw new IllegalArgumentException(s"Don't give me $n")
43+
44+
// println(s"Item ${n} - end")
45+
n
46+
}
47+
}
48+
49+
50+
def main(args: Array[String]): Unit = {
51+
val items: Seq[DemoTaskItem] = Range(0, 10).map { i => new DemoTaskItem(i) }
52+
53+
val batchHelper = new ParallelBatchRunner(items, progressUpdate, useParallelProcessing = true)
54+
55+
val results = batchHelper.execute()
56+
57+
println()
58+
println("Summarize processing")
59+
results.foreach {
60+
case (name, Success(r)) => println(s"$name: SUCCESS: $r")
61+
case (name, Failure(e)) => println(s"$name: ERROR : ${e.getMessage}")
62+
}
63+
}
64+
65+
def progressUpdate(running : Long,
66+
successful: Long,
67+
failed : Long,
68+
canceled : Long,
69+
executed : Long,
70+
total : Long,
71+
isCanceled : Boolean,
72+
perc : Double,
73+
message : String) : Unit = {
74+
val m =
75+
f"R:$running%2d, S:$successful%2d, F:$failed%2d, E:$executed%2d, C:$canceled, T:$total%d, " +
76+
f"C:$isCanceled, perc:${perc.toInt}%3d, $message"
77+
println(m)
78+
}
79+
80+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2011-2024, ScalaFX Project
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
* * Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* * Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
* * Neither the name of the ScalaFX Project nor the
13+
* names of its contributors may be used to endorse or promote products
14+
* derived from this software without specific prior written permission.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL THE SCALAFX PROJECT OR ITS CONTRIBUTORS BE LIABLE
20+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*/
27+
28+
package org.scalafx.extras.batch
29+
30+
object BatchRunner {
31+
32+
@FunctionalInterface
33+
trait ProgressUpdater:
34+
def update(
35+
running: Long,
36+
successful: Long,
37+
failed: Long,
38+
canceled: Long,
39+
executed: Long,
40+
total: Long,
41+
isCanceled: Boolean,
42+
perc: Double,
43+
message: String
44+
): Unit
45+
}
46+
trait BatchRunner[T, I <: ItemTask[T]] {
47+
48+
import BatchRunner.ProgressUpdater
49+
50+
// TODO: Is this trait needed
51+
52+
protected def itemTasks: Seq[I]
53+
54+
protected def progressUpdater: ProgressUpdater
55+
}

0 commit comments

Comments
 (0)