2009-11-07 17 views
11

मुझे वेब पर Qt के साथ ClojureREPL का उपयोग करने का समाधान नहीं मिला है। असल में समस्या यह है कि यूआई को प्रदर्शित करने के लिए आरईपीएल जैसे ही आप QApplication/exec को कॉल करते हैं। आप सीईपी सी-सी को आरईपीएल में वापस नहीं कर सकते हैं, और सक्रिय क्यूटी विंडो को बंद करना पूरी क्लोजर प्रक्रिया को मारने लगता है।मैं क्यूटी जंबी के साथ क्लोजर आरईपीएल का उपयोग कैसे कर सकता हूं?

अब एजेंट के भीतर से QAplication/processEvents को कॉल करना संभव नहीं है, जब तक कि एजेंट बिल्कुल उसी थ्रेड में नहीं चलता है जिसमें आपने अपना क्यूटी विजेट बनाया है। इसे समझने में मुझे दो दिन लग गए और मैंने देखा है कि दूसरों के पास एक ही समस्या/समस्या है लेकिन समाधान के बिना। तो यहाँ मेरा है, कोड में:

(add-classpath "file:///usr/share/java/qtjambi.jar") 
(ns qt4-demo 
    (:import (com.trolltech.qt.gui QApplication QPushButton QFont QFont$Weight) 
      (com.trolltech.qt.core QCoreApplication) 
      (java.util Timer TimerTask) 
      (java.util.concurrent ScheduledThreadPoolExecutor TimeUnit)) 
    (:require swank.core)) 

(defn init [] 
    (QApplication/initialize (make-array String 0))) 

(def *gui-thread* (new java.util.concurrent.ScheduledThreadPoolExecutor 1)) 
(def *gui-update-task* nil) 
(def *app* (ref nil)) 

(defn update-gui [] 
    (println "Updating GUI") 
    (QApplication/processEvents)) 

(defn exec [] 
    (.remove *gui-thread* update-gui) 
    (def *gui-update-task* (.scheduleAtFixedRate *gui-thread* update-gui 0 150 (. TimeUnit MILLISECONDS)))) 

(defn stop [] 
    (.remove *gui-thread* update-gui) 
    (.cancel *gui-update-task*)) 

(defmacro qt4 [& rest] 
    `(do 
    (try (init) (catch RuntimeException e# (println e#))) 
    [email protected] 
    )) 

(defmacro with-gui-thread [& body] 
    `(.get (.schedule *gui-thread* (fn [] (do [email protected])) (long 0) (. TimeUnit MILLISECONDS)))) 

(defn hello-world [] 
    (with-gui-thread 
    (qt4 
    (let [app (QCoreApplication/instance) 
      button (new QPushButton "Go Clojure Go")] 
     (dosync (ref-set *app* app)) 
     (doto button 
     (.resize 250 100) 
     (.setFont (new QFont "Deja Vu Sans" 18 (.. QFont$Weight Bold value))) 
     (.setWindowTitle "Go Clojure Go") 
     (.show))))) 
    (exec)) 

मूल रूप से यह आदेश सभी क्यूटी-कोड को निष्पादित करने में ScheduledThreadPoolExecutor वर्ग का उपयोग करता है। थ्रेड के भीतर से फ़ंक्शंस कॉल करना आसान बनाने के लिए आप साथ-gui-thread मैक्रो का उपयोग कर सकते हैं। इससे क्यूटी यूआई ऑन-द-फ्लाई को बिना किसी संकल्प के बदलना संभव हो जाता है।

+0

हाँ, मुझे वही करना था। – levand

+0

मुझे क्यूटी के बारे में कुछ भी पता नहीं है। लेकिन आप ऐसा क्यों करना चाहते हैं? क्लोजर के पास स्विंग तक पहुंच है, जो एक बहुत ही शक्तिशाली और बहुमुखी जीयूआई ढांचा है। क्या आप एक क्यूटी जीयूआई से जुड़ रहे हैं जो पहले से ही मौजूद है? –

+0

क्यूटी प्रदर्शन और देशी दिखने और महसूस सहित कई तरीकों से स्विंग से तर्कसंगत रूप से बेहतर है। – levand

उत्तर

5

यदि आप आरईपीएल, QApplication/invokeLater या QApplication/invokeAndWait से क्यूटी विजेट्स के साथ गड़बड़ करना चाहते हैं तो शायद आप जो चाहते हैं। आप एजेंटों के साथ संयोजन के रूप में उनका उपयोग कर सकते हैं। एक आरईपीएल से फिर

(ns qt4-demo 
    (:import (com.trolltech.qt.gui QApplication QPushButton) 
      (com.trolltech.qt.core QCoreApplication))) 

(def *app* (ref nil)) 
(def *button* (ref nil)) 
(def *runner* (agent nil)) 

(defn init [] (QApplication/initialize (make-array String 0))) 
(defn exec [] (QApplication/exec)) 

(defn hello-world [a] 
    (init) 
    (let [app (QCoreApplication/instance) 
     button (doto (QPushButton. "Go Clojure Go") (.show))] 
    (dosync (ref-set *app* app) 
      (ref-set *button* button))) 
    (exec)) 

: यह देखते हुए

qt4-demo=> (send-off *runner* hello-world) 
#<[email protected]: nil> 

;; This fails because we are not in the Qt main thread 
qt4-demo=> (.setText @*button* "foo") 
QObject used from outside its own thread, object=QPushButton(0x8d0f55f0) , objectThread=Thread[pool-2-thread-1,5,main], currentThread=Thread[main,5,main] (NO_SOURCE_FILE:0) 

;; This should work though 
qt4-demo=> (QApplication/invokeLater #(.setText @*button* "foo")) 
nil 
qt4-demo=> (QApplication/invokeAndWait #(.setText @*button* "bar")) 
nil 
+0

बहुत अच्छा। मुझे वह पसंद है। धन्यवाद! – MHOOO

3

मैं कैसे कीचड़ on my blog (जर्मन) के साथ ऐसा करने के साथ-साथ on the Clojure mailing-list के रूप में के बारे में लिखा है। चाल Emacs पक्ष पर उचित कार्यों को परिभाषित करना है और अनुरोध करते समय उन लोगों का उपयोग करने के लिए एसएलआईएमई को बताएं। महत्वपूर्ण बात यह है कि यह आपको Qt कोड का आह्वान करते समय विशेष incantations करने से मुक्त करता है।

अपने आप का हवाला देते हुए: हैक कीचड़:

यह देखते हुए कि हम लिस्प यहां बात कर रहे हैं, वैसे भी, समाधान स्पष्ट लग रहा था! तो मैं यही किया था। नीचे दिए गए कोड, जब को आपके .emacs में गिरा दिया गया था (उस बिंदु पर एसएलईएमई पहले से ही पूरी तरह से लोड हो चुका है), तीन नए Emacs-Lisp इंटरैक्टिव उपयोग के लिए कार्य पंजीकृत करता है। आप , जो कुछ भी आप की तरह कुंजी करने के लिए उन्हें बाध्य कर सकते हैं या आप भी सिर्फ निर्धारित कर सकते हैं कीचड़ से भेजने के माध्यम से-qapplication चर आपके आवेदन प्रारंभ होने के बाद टी के लिए और कम से सभी प्रमुख बाइंडिंग के बारे में चिंता नहीं। या तो अपने आरईपीएल सबमिशन और सी-एम-एक्स-स्टाइल इंटरैक्टिव मूल्यांकन अप्रत्यक्ष QCoreAplication/invokeAndWait के माध्यम से बनाना चाहिए।

मज़े करो!

(defvar slime-send-through-qapplication nil) 
(defvar slime-repl-send-string-fn (symbol-function 'slime-repl-send- 
string)) 
(defvar slime-interactive-eval-fn (symbol-function 'slime-interactive- 
eval)) 

(defun qt-appify-form (form) 
    (concatenate 'string ;' 
       "(let [return-ref (ref nil)] " 
       " (com.trolltech.qt.core.QCoreApplication/invokeAndWait " 
       " (fn [] " 
       "  (let [return-value (do " 
       form 
       "   )] " 
       "  (dosync (ref-set return-ref return-value))))) " 
       " (deref return-ref))")) 

(defun slime-interactive-eval (string) 
    (let ((string (if slime-send-through-qapplication 
        (qt-appify-form string) 
        string))) 
    (funcall slime-interactive-eval-fn string))) 

(defun slime-repl-send-string (string &optional command-string) 
    (let ((string (if slime-send-through-qapplication 
        (qt-appify-form string) 
        string))) 
    (funcall slime-repl-send-string-fn string command-string))) 

(defun slime-eval-defun-for-qt() 
    (interactive) 
    (let ((slime-send-through-qapplication t)) 
    (slime-eval-defun))) 

(defun slime-repl-closing-return-for-qt() 
    (interactive) 
    (let ((slime-send-through-qapplication t)) 
    (slime-repl-closing-return))) 

(defun slime-repl-return-for-qt (&optional end-of-input) 
    (interactive) 
    (let ((slime-send-through-qapplication t)) 
    (slime-repl-return end-of-input)))