I wrote my first console app in Scala, and I wrote my first Swing app in Scala -- in case of the latter, the entry point is top method in my object extending SimpleSwingApplication.
However I would like to still go through main method, and from there call top -- or perform other equivalent actions (like creating a window and "running" it).
How to do it?
Just in case if you are curious why, the GUI is optional, so I would like to parse the command line arguments and then decide to show (or not) the app window.
If you have something like:
object MySimpleApp extends SimpleSwingApplication {
// ...
}
You can just call MySimpleApp.main to start it from the console. A main method is added when you mix SimpleSwingApplication trait. Have a look at the scaladoc.
Here is the most basic example:
import swing._
object MainApplication {
def main(args: Array[String]) = {
GUI.main(args)
}
object GUI extends SimpleSwingApplication {
def top = new MainFrame {
title = "Hello, World!"
}
}
}
Execute scala MainApplication.scala from the command line to start the Swing application.
If you override the main method that you inherit from SimpleSwingApplication, you can do whatever you want:
object ApplicationWithOptionalGUI extends SimpleSwingApplication {
override def main(args: Array[String]) =
if (parseCommandLine(args))
super.main(args) // Starts GUI
else
runWithoutGUI(args)
...
}
I needed main.args to be usable in SimpleSwingApplication. I wanted to give a filename to process as an argument in CLI, or then use JFileChooser in case the command line argument list was empty.
I do not know if there is simple method to use command line args in SimpleSwingApplication, but how I got it working was to define, in demoapp.class:
class demoSSA(args: Array[String]) extends SimpleSwingApplication {
....
var filename: String = null
if (args.length > 0) {
filename = args(0)
} else {
// use JFileChooser to select filename to be processed
// https://stackoverflow.com/questions/23627894/scala-class-running-a-file-chooser
}
....
}
object demo {
def main(args: Array[String]): Unit = {
val demo = new demoSSA(args)
demo.startup(args)
}
}
Then start the app by
demo [args], by giving filename as a CLI argument or leaving it empty and program uses JFileChooser to ask it.
Is there a way to get to the args of main() in SimpleSwingApplication singleton object?
Because it doesn't work to parse 'filename' in overridden SimpleSwingApplication.main and to use 'filename' in the singleton object it needs to be declared (val args: Array[String] = null;), not just defined (val args: Array[String];). And singleton objecs inherited from SSA cannot have parameters.
(Edit)
Found one another way:
If whole demoSSA is put inside overridden main() or startup(), then top MainFrame needs to defined outside as top = null and re-declare it from startup() as this.top:
object demo extends SimpleSwingApplication {
var top: MainFrame = null
override def startup(args: Array[String]) {
... // can use args here
this.top = new MainFrame {
... // can use args here also
};
val t = this.top
if (t.size == new Dimension(0,0)) t.pack()
t.visible = true
}
}
But I think I like the former method more, with separated main object.It has at least one level indentation less than the latter method.
Related
I am trying to build a minimal example, of how to generate an AXI4Stream interface using Chisel and diplomacy. I am using the diplomatic interface already available in rocket-chip (freechips.rocketchip.amba.axis). I have some experience with Chisel, but I am still trying to learn diplomacy.
Anyway, I've managed to create a small APB example using the answer provided here: IP block generation/testing when using diplomacy. Possible to give dummy node?
Following that, I tried to create a similar, simple AXI Stream example, but I keep getting errors. Concretely, I get the following error:
[error] (Compile / run) java.lang.Exception: Unable to use BundleMap.cloneType on class freechips.rocketchip.amba.axis.AXISBundleBits, probably because class freechips.rocketchip.amba.axis.AXISBundleBits does not have a constructor accepting BundleFields. Consider overriding cloneType() on class freechips.rocketchip.amba.axis.AXISBundleBits
The code:
package chipyard.example
import chisel3._
import chisel3.internal.sourceinfo.SourceInfo
import chisel3.stage.ChiselStage
import freechips.rocketchip.config.{Config, Parameters}
import freechips.rocketchip.amba.axis._
import freechips.rocketchip.diplomacy.{SimpleNodeImp, ValName, SourceNode, NexusNode,
SinkNode, LazyModule, LazyModuleImp, TransferSizes,
SimpleDevice, AddressSet}
class MyAxisController(implicit p: Parameters) extends LazyModule {
val device = new SimpleDevice("my-device", Seq("tutorial,my-device0"))
val axisParams = AXISSlaveParameters.v1(name = "axisSlave", supportsSizes = TransferSizes(8,8))
val axisPortParams = AXISSlavePortParameters.v1(slaves = Seq(axisParams))
val node = AXISSlaveNode(portParams = Seq(axisPortParams))
lazy val module = new LazyModuleImp(this) {
val ins = node.in.unzip._1
val register = RegInit(UInt(8.W), 0.U)
register := register + ins(0).bits.data
}
}
class AXISMaster()(implicit p: Parameters) extends LazyModule {
val axisMasterParams = AXISMasterParameters.v1(
name = "axisMaster", emitsSizes = TransferSizes(8, 8)
)
val axisMasterPortParams = AXISMasterPortParameters.v1(
masters = Seq(axisMasterParams),
beatBytes = Option(8)
)
val node = AXISMasterNode(
portParams = Seq(axisMasterPortParams)
)
lazy val module = new LazyModuleImp(this) {
//The dontTouch here preserves the interface so logic is generated
dontTouch(node.out.head._1)
}
}
class MyAxisWrapper()(implicit p: Parameters) extends LazyModule {
val master = LazyModule(new AXISMaster)
val slave = LazyModule(new MyAxisController()(Parameters.empty))
slave.node := master.node
lazy val module = new LazyModuleImp(this) {
//nothing???
}
}
and Main.scala:
package chipyard.example
import chisel3._
import freechips.rocketchip.config.Parameters
import freechips.rocketchip.diplomacy._
import java.io.File
import java.io.FileWriter
/**
* An object extending App to generate the Verilog code.
*/
object Main {
def main(args: Array[String]): Unit = {
//(new chisel3.stage.ChiselStage).execute(args, Seq(ChiselGeneratorAnnotation(() => LazyModule(new MyWrapper()(Parameters.empty)).module)))
val verilog = (new chisel3.stage.ChiselStage).emitVerilog(
LazyModule(new MyAxisWrapper()(Parameters.empty)).module
)
//println(s"```verilog\n$verilog```")
val fileWriter = new FileWriter(new File("./gen/gen.v"))
fileWriter.write(verilog)
fileWriter.close()
}
}
The code is also available at https://github.com/jurevreca12/temp_dspblock_example/tree/axistream2/scala/main.
My question is. Why do I get this error? Or am I doing something wrong in the first place, and is there an easier way to create an AXIStream module?
I appreciate any feedback.
This looks to be an issue with Rocket-Chip's changes to bump to Chisel 3.5. During those changes, AXISBundleBits had its cloneType removed even though it extends off BundleMap (and therefore requires cloneType due to extending off Record).
I don't have all the details of cloneType at this time, but essentially:
Records require cloneType
Bundles used to require cloneType, but since the compiler plugin was implemented, as of 3.5 they no longer require cloneType.
BundleMap is a confusing case because it is a custom Bundle type extending directly off Record and isn't of type Bundle. Therefore, it shouldn't have had its cloneType method removed during the 3.5 Chisel bump and that will need to be added back for AXIS in RC's main branch to start working again.
Edit: the cloneType exception issue is now fixed for 3.5 on the main branch :)
I have a problem with my custom subclass of Page. Here is a short example.
def main(args: Array[String]): Unit = {
val pane = new TabbedPane
pane.pages += new LanguagePage("common_yes", new Label)
println(pane.pages(0).isInstanceOf[LanguagePage])
}
class LanguagePage(languageKey: String, com: Component)
extends Page("", com, null) {
def method() {...}
}
When I run the program, false is printed. It would be nice to know why this happens and how I can access my added page again. In my case I need to run the method that the subclass has to adjust the title string based on the language that is set.
If you look at the source
class TabbedPane extends Component with Publisher {
object pages extends BufferWrapper[Page] {
def apply(n: Int) =
new Page(TabbedPane.this, peer.getTitleAt(n),
UIElement.cachedWrapper[Component]
(peer.getComponentAt(n).asInstanceOf[javax.swing.JComponent]),
peer.getToolTipTextAt(n))
you always get a new instance.
Looking at
class TabbedPane extends Component with Publisher {
object pages extends BufferWrapper[Page] {
def +=(t: Page): this.type = {
t.parent = TabbedPane.this
peer.addTab(t.title, null, t.content.peer, t.tip)
this
}
the argument t is not recorded at all.
But you can change the title using
pane.pages(0).title = "Title 2"
so you could define a logical page (a companion in addition to the Swing page) separately. Using a reference to the pane and the tab index this class can change the title.
I'm trying to write automated tests for a gui application written in scala with swing. I'm adapting the code from this article which leverages getName() to find the right ui element in the tree.
This is a self-contained version of my code. It's incomplete, untested, and probably broken and/or non-idiomatic and/or suboptimal in various ways, but my question is regarding the compiler error listed below.
import scala.swing._
import java.awt._
import ListView._
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith
import org.scalatest.FunSpec
import org.scalatest.matchers.ShouldMatchers
object MyGui extends SimpleSwingApplication {
def top = new MainFrame {
title = "MyGui"
val t = new Table(3, 3)
t.peer.setName("my-table")
contents = t
}
}
object TestUtils {
def getChildNamed(parent: UIElement, name: String): UIElement = {
// Debug line
println("Class: " + parent.peer.getClass() +
" Name: " + parent.peer.getName())
if (name == parent.peer.getName()) { return parent }
if (parent.peer.isInstanceOf[java.awt.Container]) {
val children = parent.peer.getComponents()
/// COMPILER ERROR HERE ^^^
for (child <- children) {
val matching_child = getChildNamed(child, name)
if (matching_child != null) { return matching_child }
}
}
return null
}
}
#RunWith(classOf[JUnitRunner])
class MyGuiSpec extends FunSpec {
describe("My gui window") {
it("should have a table") {
TestUtils.getChildNamed(MyGui.top, "my-table")
}
}
}
When I compile this file I get:
29: error: value getComponents is not a member of java.awt.Component
val children = parent.peer.getComponents()
^
one error found
As far as I can tell, getComponents is in fact a member of java.awt.Component. I used the code in this answer to dump the methods on parent.peer, and I can see that getComponents is in the list.
Answers that provide another approach to the problem (automated gui testing in a similar manner) are welcome, but I'd really like to understand why I can't access getComponents.
The issue is that you're looking at two different classes. Your javadoc link points to java.awt.Container, which indeed has getComponents method. On the other hand, the compiler is looking for getComponents on java.awt.Component (the parent class), which is returned by parent.peer, and can't find it.
Instead of if (parent.peer.isInstanceOf[java.awt.Container]) ..., you can verify the type of parent.peer and cast it like this:
parent.peer match {
case container: java.awt.Container =>
// the following works because container isA Container
val children = container.getComponents
// ...
case _ => // ...
}
I've written a Scala program that I'd like to be triggered through a UI (also in Swing). The problem is, when I trigger it, the UI hangs until the background program completes. I got to thinking that the only way to get around this is by having the program run in another thread/actor and have it update the UI as and when required. Updating would include a status bar which would show the file currently being processed and a progressbar.
Since Scala actors are deprecated, I'm having a tough time trying to plough through Akka to get some kind of basic multithreading running. The examples given on the Akka website are also quite complicated.
But more than that, I'm finding it difficult to wrap my head around how to attempt this problem. What I can come up with is:
Background program runs as one actor
UI is the main program
Have another actor that tells the UI to update something
Step 3 is what is confounding me. How do I tell the UI without locking up some variable somewhere?
Also, I'm sure this problem has been solved earlier. Any sample code for the same would be highly appreciated.
For scala 2.10
You can use scala.concurrent.future and then register a callback on completion. The callback will update the GUI on the EDT thread.
Lets do it!
//in your swing gui event listener (e.g. button clicked, combo selected, ...)
import scala.concurrent.future
//needed to execute futures on a default implicit context
import scala.concurrent.ExecutionContext.Implicits._
val backgroundOperation: Future[Result] = future {
//... do that thing, on another thread
theResult
}
//this goes on without blocking
backgroundOperation onSuccess {
case result => Swing.onEDT {
//do your GUI update here
}
}
This is the most simple case:
we're updating only when done, with no progress
we're only handling the successful case
To deal with (1) you could combine different futures, using the map/flatMap methods on the Future instance. As those gets called, you can update the progress in the UI (always making sure you do it in a Swing.onEDT block
//example progress update
val backgroundCombination = backgroundOperation map { partial: Result =>
progress(2)
//process the partial result and obtain
myResult2
} //here you can map again and again
def progress(step: Int) {
Swing.onEDT {
//do your GUI progress update here
}
}
To deal with (2) you can register a callback onFailure or handle both cases with the onComplete.
For relevant examples: scaladocs and the relevant SIP (though the SIP examples seems outdated, they should give you a good idea)
If you want to use Actors, following may work for you.
There are two actors:
WorkerActor which does data processing (here, there is simple loop with Thread.sleep). This actor sends messages about progress of work to another actor:
GUIUpdateActor - receives updates about progress and updates UI by calling handleGuiProgressEvent method
UI update method handleGuiProgressEvent receives update event.
Important point is that this method is called by Actor using one of Akka threads and uses Swing.onEDT to do Swing work in Swing event dispatching thread.
You may add following to various places to see what is current thread.
println("Current thread:" + Thread.currentThread())
Code is runnable Swing/Akka application.
import akka.actor.{Props, ActorRef, Actor, ActorSystem}
import swing._
import event.ButtonClicked
trait GUIProgressEventHandler {
def handleGuiProgressEvent(event: GuiEvent)
}
abstract class GuiEvent
case class GuiProgressEvent(val percentage: Int) extends GuiEvent
object ProcessingFinished extends GuiEvent
object SwingAkkaGUI extends SimpleSwingApplication with GUIProgressEventHandler {
lazy val processItButton = new Button {text = "Process it"}
lazy val progressBar = new ProgressBar() {min = 0; max = 100}
def top = new MainFrame {
title = "Swing GUI with Akka actors"
contents = new BoxPanel(Orientation.Horizontal) {
contents += processItButton
contents += progressBar
contents += new CheckBox(text = "another GUI element")
}
val workerActor = createActorSystemWithWorkerActor()
listenTo(processItButton)
reactions += {
case ButtonClicked(b) => {
processItButton.enabled = false
processItButton.text = "Processing"
workerActor ! "Start"
}
}
}
def handleGuiProgressEvent(event: GuiEvent) {
event match {
case progress: GuiProgressEvent => Swing.onEDT{
progressBar.value = progress.percentage
}
case ProcessingFinished => Swing.onEDT{
processItButton.text = "Process it"
processItButton.enabled = true
}
}
}
def createActorSystemWithWorkerActor():ActorRef = {
def system = ActorSystem("ActorSystem")
val guiUpdateActor = system.actorOf(
Props[GUIUpdateActor].withCreator(new GUIUpdateActor(this)), name = "guiUpdateActor")
val workerActor = system.actorOf(
Props[WorkerActor].withCreator(new WorkerActor(guiUpdateActor)), name = "workerActor")
workerActor
}
class GUIUpdateActor(val gui:GUIProgressEventHandler) extends Actor {
def receive = {
case event: GuiEvent => gui.handleGuiProgressEvent(event)
}
}
class WorkerActor(val guiUpdateActor: ActorRef) extends Actor {
def receive = {
case "Start" => {
for (percentDone <- 0 to 100) {
Thread.sleep(50)
guiUpdateActor ! GuiProgressEvent(percentDone)
}
}
guiUpdateActor ! ProcessingFinished
}
}
}
If you need something simple you can run the long task in a new Thread and just make sure to update it in the EDT:
def swing(task: => Unit) = SwingUtilities.invokeLater(new Runnable {
def run() { task }
})
def thread(task: => Unit) = new Thread(new Runnable {
def run() {task}
}).run()
thread({
val stuff = longRunningTask()
swing(updateGui(stuff))
})
You can define your own ExecutionContext which will execute anything on the Swing Event Dispatch Thread using SwingUtilities.invokeLater and then use this context to schedule a code which needs to be executed by Swing, still retaining the ability to chain Futures the Scala way, including passing results between them.
import javax.swing.SwingUtilities
import scala.concurrent.ExecutionContext
object OnSwing extends ExecutionContext {
def execute(runnable: Runnable) = {
SwingUtilities.invokeLater(runnable)
}
def reportFailure(cause: Throwable) = {
cause.printStackTrace()
}
}
case ButtonClicked(_) =>
Future {
doLongBackgroundProcess("Timestamp")
}.foreach { result =>
txtStatus.text = result
}(OnSwing)
I have found following function calls in several frameworks which appear to me as if the framework extends some base classes. Some examples:
within(500 millis)
or
"Testcase description" in
{ .... }
First example returns a duration object with the duration of 500 milliseconds from akka and second is the definition of a testcase from scalatest.
I would like to know how this behavior is achieved and how it is called.
This is done with the "Pimp my library" technique.
To add non existing methods to a class, you define an implicit method that converts objects of that class to objects of a class that has the method:
class Units(i: Int) {
def millis = i
}
implicit def toUnits(i: Int) = new Units(i)
class Specs(s: String) {
def in(thunk: => Unit) = thunk
}
implicit def toSpecs(s: String) = new Specs(s)
See also "Where does Scala looks for Implicits?"
If I'm not mistaken, those pieces of code can be desugared as
within(500.millis)
and
"Testcase description".in({ ... })
This should make it easier to see what's going on.