views:

116

answers:

2

I've moved on from trying to use OpenGL through Penumbra to trying to draw directly on a JPanel using its Graphics context.

This would be great, except I'm running into some trouble… I compile my code, and ~1 time out of 25, the graphic (it's a rectangle for the example) draws just fine. The other ~24 times, it doesn't.

Here's my code:

(def main
  (let [frame (JFrame. "This is a test.")
        main-panel (JPanel. (GridBagLayout.))
        tpan (proxy [JPanel] [] (getPreferredSize [] (Dimension. 600 400)))]

    (doto frame
      (set-content-pane
       (doto main-panel
         (grid-bag-layout
          :gridx 0 :gridy 0
          tpan
          :gridx 0 :gridy 1
          xy-label)))
      (pack-frame)
      (set-visible))

    (draw-line tpan Color/RED 250 250 50 50)))

The function draw-lineis below:

(defn draw-line [panel color x y w h]
  (let [graphics (.getGraphics panel)]
    (doto graphics
      (.setColor color)
      (.drawRect x y w h))))

I have no idea what is going on. At first I thought it was the refs I was working on, but then I took those out, and still have these problems. I've reset lein and slime/swank and emacs, too. I'm quite puzzled.

As usual, any help would be appreciated. I hope this is a question with an answer! Lately, I seem to be asking the impossible :)

+4  A: 

You should be overriding paintComponent in the panel. (Choice of JPanel probably isn't the best - use JComponent and certain set-opaque on it.)

Also, I guess you should be on the AWT EDT.

Tom Hawtin - tackline
+5  A: 

Ensure that you are always on the EDT. If you see your GUI acting randomly that is generally the cause. Race conditions are critical to swing because it's designed to be entirely single-threaded.

What you might try, just to see, is find any method that interacts with a swing component and have it print out the Thread.getCurrentThread().toString() (or something very close to that).

It should always print out a thread name and you'll see the letters AWT embedded in there somewhere. You could even store off that thread, test against it on every call into Swing and assert if it's not the same.

Actually I don't know why Sun never built a "Debug" version of the JDK that would assert when things like this happened (like when some swing thread was called from a non-awt thread...)

Bill K
Fantastic, thank you! Any suggestions on where to start? (And, for bonus points, any idea where I might be straying off the EDT?)
Isaac Hodes
I'm afraid I don't know enough about the framework you are using--I don't recognize the syntax except to be able to tell that it's declarative. One (annoying) thing you could do is subclass all the controls you use, override the methods you might use and have them output the current thread. Another possibility is at the head of draw-line have it print out that thread name and see if it contains the letters AWT. After that though, I just don't know enough about your code.
Bill K