Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Leiningen下的Clojure UI应用程序中跟踪AWT异常_Clojure_Awt_Leiningen - Fatal编程技术网

在Leiningen下的Clojure UI应用程序中跟踪AWT异常

在Leiningen下的Clojure UI应用程序中跟踪AWT异常,clojure,awt,leiningen,Clojure,Awt,Leiningen,因此,我创建了一个新的Leiningenapp项目: lein new app a-ui-app 将源代码复制到leiningen生成的core.clj中,并修改了-main例程来调用它 (defn -main "See https://stackoverflow.com/questions/2792451/improving-my-first-clojure-program?rq=1." [& args] ;; work around dangerous default

因此,我创建了一个新的
Leiningen
app项目:

lein new app a-ui-app
将源代码复制到leiningen生成的
core.clj
中,并修改了
-main
例程来调用它

(defn -main
  "See https://stackoverflow.com/questions/2792451/improving-my-first-clojure-program?rq=1."
  [& args]
  ;; work around dangerous default behaviour in Clojure
  (alter-var-root #'*read-eval* (constantly false))

  (doto panel
        (.setFocusable true)
        (.addKeyListener panel))

  (doto frame
        (.add panel)
        (.pack)
        (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
        (.setVisible true))

  (loop []
        (draw-rectangle panel @x @y)
        (Thread/sleep 10)
        (recur))
  )
然后我通过任何一种方式运行它

lein run

在这两种情况下,应用程序都运行良好,但在我用来启动它的终端中,我在随机延迟几秒钟后出现异常:

线程“AWT-EventQueue-0”中出现异常 java.lang.IllegalArgumentException:无匹配子句:157 at a_ui_app.core$fn_16$fn_21$fn_22.invoke(core.clj:19)位于 clojure.lang.AFn.call(AFn.java:18)位于 clojure.lang.LockingTransaction.run(LockingTransaction.java:263)位于 clojure.lang.LockingTransaction.runInTransaction(LockingTransaction.java:231) 在a_ui_app.core$fn_16$fn_21.invoke(core.clj:17)处 a_ui_app.core.proxy$javax.swing.JPanel$KeyListener$6c415903.keyPressed(未知 位于java.awt.Component.processKeyEvent(Component.java:6340)的 javax.swing.JComponent.processKeyEvent(JComponent.java:2809)位于 a_ui_app.core.proxy$javax.swing.JPanel$KeyListener$6c415903.processKeyEvent(未知 位于java.awt.Component.processEvent(Component.java:6159)的 java.awt.Container.processEvent(Container.java:2083)更多 台词

我没有对
project.clj
做任何更改——只是使用了leiningen生成的一个


我想知道发生了什么事。我对Java线程一无所知。问题是否与leiningen启动应用程序Java线程的方式有关?这是不可避免的吗?如果没有,我如何修复它,无论是对于这个小示例程序还是以后,作为使用UI线程(我认为是
AWT-EventQueue-0
)的未来项目的项目模式。

我不知道为什么会出现这个错误,但我要说的是,您做了一些不正确的事情:Swing是一个复杂的野兽;)

Swing不是线程安全的。关于在EDT(事件调度线程/UI线程)上可以做什么和不能做什么的“规则”随着时间的推移而改变。。。在某个时刻,Sun决定所有修改Swing组件的操作都应该在EDT上完成

因此,从另一个线程(忙于旋转循环)绘制矩形是一个很大的禁忌。同样,您绘制矩形的方式也不正确:您不应该直接从另一个线程获取图形对象并修改它(这是一种超级黑客行为,应该会触发疯狂的闪烁)。一种“正确”的Swing方法是重写
paintComponent(Graphics g)
Java方法并在那里进行绘图:因此每次需要重新绘制组件时,都会正确地重新绘制

下面是使用paintComponent绘制矩形的代码的修改版本(我没有修复嵌套的if语句,它应该是case等):

(import java.awt.Color)
(import java.awt.Dimension)
(import java.awt.event.KeyListener)
(import javax.swing.JFrame)
(import javax.swing.JPanel)

(def x (ref 0))
(def y (ref 0))

(def panel
  (proxy [JPanel KeyListener] []
    (paintComponent [g]
      (proxy-super paintComponent g)
      (doto g
        (.setColor (java.awt.Color/WHITE))
        (.fillRect 0 0 100 100)
        (.setColor (java.awt.Color/BLUE))
        (.fillRect (* 10 @x) (* 10 @y) 10 10)))
    (getPreferredSize [] (Dimension. 100 100))
    (keyPressed [e]
      (let [keyCode (.getKeyCode e)]
        (if (== 37 keyCode) (dosync (alter x dec))
        (if (== 38 keyCode) (dosync (alter y dec))
        (if (== 39 keyCode) (dosync (alter x inc))
        (if (== 40 keyCode) (dosync (alter y inc))))))
        (.repaint this)
        ))
    (keyReleased [e])
    (keyTyped [e])))

(def frame (JFrame. "Test"))

(defn -main [& args]

  (doto panel
        (.setFocusable true)
        (.addKeyListener panel))

  (doto frame
        (.add panel)
        (.pack)
        (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
        (.setVisible true)))
我不太喜欢将x和y分开定义:但是,保证在EDT上同时出现
paintComponent
和键侦听器触发器,因此在您的情况下,读数应该是一致的。如果我是你,我仍然会使用一个
xy
def

我对JPanel也有点困惑,它也是一个KeyListener和-main函数,然后将KeyListener添加到自己中:
(doto面板(.addKeyListener面板))
感觉很奇怪。也许没关系,我不知道:只是感觉很奇怪:)

关于您的异常,我不知道,但是Swing EDT实际上偶尔会抛出异常,因为Swing有很多bug,而且Swing的正确使用非常复杂,程序往往会犯很多诚实的错误。根据平台/JVM,捕获异常并使EDT保持运行,或者自动启动新的EDT。通常情况下,您不应该“崩溃”EDT,因为如果EDT崩溃,它应该自动重新启动。这就是为什么你看到了异常,但你说你的程序仍然“运行良好”

我想说,异常和神秘的堆栈跟踪与Swing不是线程安全的,你做了一些奇怪的事情有关:旋转循环获取面板的底层图形对象并处理它,但我真的不确定

经过上述修改后的代码似乎可以很好地完成您想要完成的任务,而且不会闪烁


希望能有所帮助。

另一方面,有人知道第一行的作用是什么吗(改变变量根等)?它由lein新应用程序生成_
(import java.awt.Color)
(import java.awt.Dimension)
(import java.awt.event.KeyListener)
(import javax.swing.JFrame)
(import javax.swing.JPanel)

(def x (ref 0))
(def y (ref 0))

(def panel
  (proxy [JPanel KeyListener] []
    (paintComponent [g]
      (proxy-super paintComponent g)
      (doto g
        (.setColor (java.awt.Color/WHITE))
        (.fillRect 0 0 100 100)
        (.setColor (java.awt.Color/BLUE))
        (.fillRect (* 10 @x) (* 10 @y) 10 10)))
    (getPreferredSize [] (Dimension. 100 100))
    (keyPressed [e]
      (let [keyCode (.getKeyCode e)]
        (if (== 37 keyCode) (dosync (alter x dec))
        (if (== 38 keyCode) (dosync (alter y dec))
        (if (== 39 keyCode) (dosync (alter x inc))
        (if (== 40 keyCode) (dosync (alter y inc))))))
        (.repaint this)
        ))
    (keyReleased [e])
    (keyTyped [e])))

(def frame (JFrame. "Test"))

(defn -main [& args]

  (doto panel
        (.setFocusable true)
        (.addKeyListener panel))

  (doto frame
        (.add panel)
        (.pack)
        (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
        (.setVisible true)))