Scala Swing中的听众和反应
我在
eclipse中做了一些搜索和一些试验和错误,但是当我使用Swing在
Scala中编写GUI时,我对听众和反应的理解似乎存在差距.
每个侦听器是否都有一个反应块,或者我是否在可能生成事件的所有组件上注册侦听器,并在带有case语句的大型反应块中对每个组件做出反应? 听众和反应块究竟属于哪里. 这是我的GUI代码的缩写版本: import scala.swing._ import scala.swing.event.ButtonClicked import scala.swing.event.KeyTyped import scala.swing.event.KeyPressed object HumanGUI extends SimpleGUIApplication { val basicPane = new java.awt.Dimension(800,200) val botPane = new java.awt.Dimension(400,200) val felt = new java.awt.Color(35,125,35) def top = new MainFrame { title = "Blackjack GUI" val ConnectionPanel = new BoxPanel(Orientation.Vertical) { background = felt preferredSize = new java.awt.Dimension(155,90) minimumSize = preferredSize maximumSize = preferredSize val ipAddressLabel = new Label("House IP:") ipAddressLabel.foreground = java.awt.Color.WHITE ipAddressLabel.horizontalTextPosition = scala.swing.Alignment.Left val portLabel = new Label("House port:") portLabel.foreground = java.awt.Color.WHITE portLabel.horizontalTextPosition = scala.swing.Alignment.Left val ipAddressTextField = new TextField val portTextField = new TextField contents += ipAddressLabel contents += ipAddressTextField contents += portLabel contents += portTextField } val DetailPanel = new BoxPanel(Orientation.Vertical) { background = felt preferredSize = new java.awt.Dimension(100,160) minimumSize = preferredSize maximumSize = preferredSize val nameLabel = new Label("Your name:") nameLabel.foreground = java.awt.Color.WHITE nameLabel.horizontalTextPosition = scala.swing.Alignment.Left val bankrollLabel = new Label("Bankroll:") bankrollLabel.foreground = java.awt.Color.WHITE bankrollLabel.horizontalTextPosition = scala.swing.Alignment.Left val betLabel = new Label("Bet:") betLabel.foreground = java.awt.Color.WHITE betLabel.horizontalTextPosition = scala.swing.Alignment.Left val nameTextField = new TextField val bankrollTextField = new TextField val betTextField = new TextField val goButton = new Button("Go!") contents += nameLabel contents += nameTextField contents += bankrollLabel contents += bankrollTextField contents += betLabel contents += betTextField contents += goButton } val PlayPanel = new BoxPanel(Orientation.Vertical) { background = felt val hitButton = new Button("Hit") val stayButton = new Button("Stay") val doubleButton = new Button("Double") val quitButton = new Button("Quit") contents += hitButton contents += stayButton contents += doubleButton contents += quitButton } val playerPanel = new BoxPanel(Orientation.Horizontal) { background = felt border = new javax.swing.border.LineBorder(java.awt.Color.WHITE) preferredSize = basicPane minimumSize = basicPane maximumSize = basicPane opaque = true contents += ConnectionPanel contents += DetailPanel contents += PlayPanel } contents = new BoxPanel(Orientation.Vertical) { contents += playerPanel } } } 所以问题是我在哪里放置我的听众和反应块? 编辑 Odersky的“Scala编程”摘录对我的帮助最大.具体来说,这个页面的例子: http://www.artima.com/pins1ed/gui-programming.html 代码来自文本的第一版,所以我质疑Scala 2.9中是否有更好的方法,但它很简洁,总结了我误解的内容. 从示例中,这是一个简单的华氏温度到摄氏温度转换器,我开始明白监听器和反应块属于MainFrame的内容块之后. 所以我最终得到了: object HumanGUI extends SimpleSwingGUIApplication { def top = new MainFrame { title = "My Blackjack GUI" //The fields I want to work with are instantiated as object object ipAddressTextField extends TextField { columns = 15 } object portNumberTextField extends TextField {columns = 5 } //other panels,objects,etc would go here val OtherPanel = new BoxPanel(Orientation.Horizontal) { label = "Other Panel" } //and here we have the contents += block for the mainframe,other panels,etc from //above would be added to the main frame here contents = new BoxPanel(Orientation.Vertical) { contents += ipAddressTextField contents += portNumberTextField } //here's the listen to,listening on the object created above,and it's enclosed in //in backticks,a good explanation of that is found in the link below listenTo(`ipAddressTextField`) reactions += { case EditDone('ipAddressTextField`) => //do something! } } Need clarification on Scala literal identifiers (backticks) 所以似乎我的问题的答案是listenTo和react块属于MainFrame块,但应该在它的contents = {// contents}块之后出现. eclipse中的其他试验和错误表明,虽然这个解决方案适用于我,但显然还有更多我不理解的内容.例如,虽然我无法让KeyPress事件的监听器工作,但如果我试图在内部听取并对它们做出反应 val OtherPanel = new BoxPanel(Orientation.Horizontal) { val betLabel = new Label("Bet:") val betTextField = new TextField val goButton = new Button("Go!") listenTo(goButton) reactions += { case ButtonClicked(b) => betTextField.text = "Go!" } contents += betLabel contents += betTextField contents += goButton } 为什么这有效但我试图做一些事情 val OtherPanel = new BoxPanel(Orientation.Horizontal) { val betLabel = new Label("Bet:") val betTextField = new TextField val goButton = new Button("Go!") listenTo(betTextField) reactions += { case KeyTyped(betTextField,Enter,_,_) => { println("Caught enter") } contents += betLabel contents += betTextField contents += goButton } 没工作仍然令我困惑.我假设它应该工作,我只是做错了.也许用一个案例EditDone而不是一个案例KeyTyped(,)将这种方法融合起来会起作用,但我现在有点太过刻意跟进了. 我还没有接受答案,因为我希望看到这个的人可以澄清我仍然不理解的观点.如果这种情况没有发生且问题仍未得到解决,我可能会接受@ som-snytt的回答,因为他的代码非常有用. 解决方法
Swing具有教育意义,Scala-Swing具有教育意义.特别是如果课程是“摇摆的历史:兴衰”.
我的第一个Scala程序也使用了Swing.我已经忘记了细节,但我会分享我在源头上看到的内容. 显然,我有一个名为LightBox的主要UI组件,它处理一些UI事件,还有一个协调的中介组件LightBoxMediator. 有趣的部分是,使用蛋糕模式进行合成,并将业务逻辑(或游戏逻辑)交互移动到一个“适当”调整UI的组件中. LightBox也发布了事件. 因此,您的问题的答案将是:利用发布者框架,但将UI事件与应用程序事件区分开来. (这个小游戏也有基于演员的控制器.) 也许这足以说明关注点的分离: /** * Draws the House of Mirrors. * The LightBox is just a list of rays (line segments) and gates (various objects). * The UI emits requests to move and rotate gates. */ class LightBox extends Panel { this.peer.addComponentListener( new ComponentAdapter { override def componentResized(e: ComponentEvent) { if (e.getID == ComponentEvent.COMPONENT_RESIZED && e.getComponent == LightBox.this.peer) { calculateScale() } } } ) listenTo(mouse.clicks,mouse.moves,mouse.wheel,keys) reactions += { case KeyPressed(_,Key.N,_) => highlightNextMoveableGate() case KeyPressed(_,Key.P,_) => highlightPreviousMoveableGate() case e: MousePressed => startDrag(e) case e: MouseDragged => doDrag(e) case e: MouseReleased => endDrag(e) case e: MouseWheelMoved => wheeling(e) case _ => null // println ("Unreacted event") } 和调解员 trait ViewComponents { this: ControllerComponents with ModelComponents => val lightBoxMediator: LightBoxMediator val statusBarMediator: StatusBarMediator val statusIconMediator: StatusIconMediator val applicationMediator: ApplicationMediator /** * Handles update notifications from the application * and user input from the LightBox. */ class LightBoxMediator(val ui: LightBox) extends Reactor with Observing { /** Attempt to track our selection across updates: the point is where the gate should end up. */ private var selectionContinuity: (Option[Gate],Option[Point]) = (None,None) listenTo(ui,ui.keys,ui.mouse.clicks) reactions += { case KeyPressed(_,Key.Q,_) => sys.exit() case KeyPressed(_,Key.Space,_) => rotateSelectedGate() case KeyPressed(_,Key.Enter,_) => rotateOtherwiseSelectedGate() case KeyPressed(_,Key.Up,_) => moveUp() case KeyPressed(_,Key.Down,_) => moveDown() case KeyPressed(_,Key.Left,_) => moveLeft() case KeyPressed(_,Key.Right,_) => moveRight() case KeyPressed(_,Key.PageUp,_) => previousLevel() case KeyPressed(_,Key.PageDown,_) => nextLevel() case DragEvent(from,to) => handleDrag(from,to) case ClickEvent(where,button) => handleClick(where,button) //case x => println("Unreacted event " + x) } observe(controller.modelEvents) { e => e match { case LevelLoaded(v) => onLevelLoaded(v) case TraceResult(s) => onTrace(s) case unknown => println("Lightbox mediator ignored: "+ unknown) } true } 刚刚注意到了其他问题.巧合的是,我正在清理旧代码,实际上是一个小应用程序从sfgate.com获取图像(当然,当他们更改网站时停止工作;但通常你可以右击 – 现在保存),我碰巧请注意以下关于重新订阅的评论.我依旧记得关于UIElement是一个懒惰的发布者的一点,因为我记得头颅.但如果我没有写出微薄的评论,那么这些信息就会在古代历史中丢失. 我认为有人想支持scala-swing并且可能会照顾头部. package com.maqicode.sfg.jfc import java.awt.Color import java.awt.Color.{WHITE => White,RED => Red} import java.net.{URI,URISyntaxException} import javax.swing._ import swing.TextField import swing.event.{EditDone,MouseEntered,ValueChanged} import com.maqicode.sfg.BadGateURLException import com.maqicode.sfg.GateUrlTranslator.translate abstract class URIField extends TextField { reactions += { case e: EditDone => editDone(e) case other: ValueChanged => editing(other) case m: MouseEntered => onMouseEntered() case _ => null } // necessary to resubscribe this so that onFirstSubscribe registers ActionListener listenTo(this,mouse.moves) def onMouseEntered() { val t: Option[String] = ClipboardInput.contents if (t.isDefined && t.get != this.text) { this.text = t.get submitURL(t.get) } } def editing(e: ValueChanged) { clearError() } def editDone(e: EditDone) { submitURL(this.text) } def submitURL(s: String) { val u = s.trim if (!u.isEmpty) try { submitURI(translate(new URI(u))) clearError() } catch { case t: BadGateURLException => flagError() case t: URISyntaxException => flagError() } } def flagError() { colorCode(Red) } def clearError() { colorCode(White) } private def colorCode(c: Color) { if (this.background != c) this.background = c } def submitURI(uri: URI): Unit } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |