2011-01-06 6 views
9

मैं स्कैला में एक छोटा सा एप्लीकेशन लिख रहा हूं। एप्लिकेशन सरल लॉग फ़ाइलों को संसाधित करता है। क्योंकि प्रसंस्करण में कुछ समय लगता है, मैंने अपने आवेदन कोर को अभिनेता का विस्तार करने का फैसला किया है।स्कैला स्विंग अनुप्रयोगों में अभिनेताओं के साथ बातचीत

class Application extends Actor { 
    def react() { 
    loop { 
     react { 
     case Process(file) => // do something interesting with file... 
     } 
    } 
    } 
} 

एक लॉग फ़ाइल के प्रसंस्करण जीयूआई में एक बटन क्लिक करके शुरू हो रहा है। गुई स्कैला स्विंग का उपयोग करता है।

object Gui extends SimpleSwingApplication { 
    val application = new Application().start() 

    def top = new MainFrame { 
    val startButton = new Button 

    reactions += { 
     case ButtonClicked(`startButton`) => application ! Process(file) 
    } 
    } 
} 

अब, आवेदन कोर को वर्तमान प्रगति के बारे में गुई को सूचित करने की आवश्यकता है।

sender ! Progress(value) // whenever progress is made 

मैंने इसे गुई के अंदर एक अलग अभिनेता बनाकर हल किया है। अभिनेता को एड थ्रेड के अंदर निष्पादित किया गया है। यह एप्लिकेशन कोर से संदेशों को सुनता है और गुई को अपडेट करता है।

object Gui extends SimpleSwingApplication { 
    val actor = new Actor { 
     override val scheduler = new SchedulerAdapter { 
     def execute(fun: => Unit) { Swing.onEDT(fun) } 
     } 
     start() 

     def act() { 
     loop { 
      react { 
      case ForwardToApplication(message) => application ! message 
      case Progress(value) => progressBar.value = value 
      } 
     } 
     } 
    } 
    } 

के बाद से आवेदन कोर संदेश के प्रेषक के बारे में पता करने की जरूरत है, तो मैं आपको एप्लिकेशन कोर करने के लिए जीयूआई से संदेशों को अग्रेषित करने के लिए इस अभिनेता का उपयोग, मेरे अभिनेता नया इस बना रही है।

reactions += { 
    case ButtonClicked(`startButton`) => actor ! ForwardToApplication(Process(file)) 
    } 

यह कोड ठीक काम करता है। मेरा सवाल: क्या ऐसा करने का कोई आसान तरीका है? यह मेरे आवेदन संदेशों के लिए प्रतिक्रिया तंत्र का सरल उपयोग करने के लिए अच्छा होगा:

reactions += { 
    case Progress(value) => progressBar.value = value 
    } 

कोई विचार यह कैसे प्राप्त करें?

उत्तर

6

मैं अपने आवेदन एक swing.Publisher बनाने का gerferras विचार पर विस्तार किया है। निम्न श्रेणी swing.Reactor और Actor के बीच मध्यस्थ के रूप में कार्य करती है।

import actors.Actor 
import swing.Publisher 
import swing.event.Event 
import swing.Swing.onEDT 

case class Send(event: Any)(implicit intermediator: Intermediator) { 
    intermediator ! this 
} 
case class Receive(event: Any) extends Event 

case class Intermediator(application: Actor) extends Actor with Publisher { 
    start() 

    def act() { 
    loop { 
     react { 
     case Send(evt) => application ! evt 
     case evt => onEDT(publish(Receive(evt))) 
     } 
    } 
    } 
} 

अब मेरी प्रतिक्रियाओं में स्विंग घटनाओं और एप्लिकेशन ईवेंट दोनों शामिल हो सकते हैं।

implicit val intermediator = Intermediator(application) 
listenTo(intermediator, button) 

reactions += { 
    case ButtonClicked(`button`) => Send(Process(file)) 
    case Receive(Progress(value)) => progressBar.value = value 
} 

नोट कैसे case class Send आसानी से घटनाओं बना सकते हैं और बीच का व्यक्ति को पारित करने के लिए कुछ वाक्यात्मक चीनी प्रदान करता है।

+0

मुझे लगता है कि यह एक अच्छा समाधान है। हो सकता है कि मैं बदले में एक उत्थान के लायक हूं;) – gerferra

+0

मुझे लगता है कि आप 'इंटरमीडिएटर' गायब हैं, 'बटन पर क्लिक किया गया' – gerferra

+0

@geferra 'मध्यस्थ!' कॉल 'केस क्लास भेजें' के निर्माता के अंदर है। 'मध्यस्थ' को एक अंतर्निहित पैरामीटर के माध्यम से पारित किया जाता है। मैं आपके उत्तर को उखाड़ फेंक रहा हूं क्योंकि यह मेरे अपने समाधान के लिए प्रेरणा प्रदान करता है। –

4

शायद यह आसान है लेकिन यह नहीं पता कि यह बेहतर है या नहीं। इसके बजाय अपने आवेदन एक अभिनेता बैकेंड बनाने का है, तो आप एक गुमनाम अभिनेता हर बार जब आप फ़ाइल पर कार्रवाई करने की जरूरत है बना सकते हैं:

reactions += { 
    case ButtonClicked(`startButton`) => application.process(file, { v: Int => Swing.onEDT(progressBar.value = v) }) 
} 

प्रगति अद्यतन भाग के लिए, आप इस प्रक्रिया विधि हर निष्पादित करने के लिए करने के लिए एक कॉलबैक पारित कर सकते हैं बार एक नई प्रगति की है:

import scala.actors.Actor.actor 

def process(f: File, progress: Int => Unit) { 
    actor { 
    // process file while notifying the progress using the callback 
    progress(n) 
    } 
} 

वैकल्पिक रूप से (परीक्षण नहीं किया) आप के बजाय कॉलबैक का उपयोग कर के अपने आवेदन एक scala.swing.Publisher कर सकता है और, हर बार प्रकाशित और घटना। तो कोड हो सकता है:

listenTo(startButton, application) //application is a Publisher 

reactions += { 
    case ButtonClicked(`startButton`) => application.process(file) 
    case Progress(v) => progressBar.value = v 
} 

और आवेदन में:

import scala.actors.Actor.actor 

def process(f: File) { 
    actor { 
    // process file while notifying the progress using an scala.swing.event.Event 
    publish(Progess(n)) 
    } 
} 
+0

कॉलबैक के साथ आपका पहला विचार काम करता है, लेकिन मुझे लगता है कि अभिनेता के साथ मेरा दृष्टिकोण अधिक विस्तार योग्य है यदि मुझे अतिरिक्त संदेश पास करने की आवश्यकता है। –

+0

दूसरे दृष्टिकोण के बारे में क्या?आपका आवेदन कुछ हद तक स्विंग फ्रंट एंड से बंधेगा लेकिन मुझे लगता है कि यह बुरा नहीं है और, यदि मैंने आपका प्रश्न सही तरीके से पढ़ा है, तो आप – gerferra

+0

के अंत में पूछ रहे हैं कि मैंने आपके दूसरे दृष्टिकोण की कोशिश की है और कुछ हद तक इसे बढ़ाया है। मेरा स्वयं का जवाब देखें कि यह समाधान कैसा दिखता है। –

संबंधित मुद्दे