【发布时间】:2023-12-27 14:22:01
【问题描述】:
我还没有找到在网络上将Clojure REPL 与 Qt 一起使用的解决方案。 基本上问题是,只要您调用 QApplication/exec 以显示 UI,REPL 就会挂起。你不能 C-c C-c 回到 REPL,关闭活动的 Qt 窗口似乎会杀死整个 Clojure 进程。
现在不可能从代理中简单地调用 QApplication/processEvents,除非代理在与您创建 Qt 小部件的线程完全相同的线程中运行。我花了两天时间才弄清楚这一点,我看到其他人有同样的问题/问题,但没有解决方案。 所以这是我的,在代码中:
(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#)))
~@rest
))
(defmacro with-gui-thread [& body]
`(.get (.schedule *gui-thread* (fn [] (do ~@body)) (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 类来执行所有 Qt 代码。您可以使用 with-gui-thread 宏来更轻松地从线程内调用函数。 这使得无需重新编译即可即时更改 Qt UI。
【问题讨论】:
-
是的,我必须做同样的事情。
-
我对QT一无所知。但是你为什么要这样做呢? Clojure 可以访问 Swing,这是一个非常强大且通用的 GUI 框架。您是否连接到已经存在的 QT GUI?
-
QT 在很多方面都可以说比 Swing 更好,包括性能和原生外观。
-
在我看来,Qt 也有一个更干净的 API。 (很难想出比 Swing 更丑的 API。)Qt 应用与 Linux 桌面环境的集成也比 Swing 应用好得多。
标签: qt lisp clojure read-eval-print-loop qt-jambi