Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>It sounds to me (although I can't tell from your code above) that you are trying to add components to a live JFrame (i.e. one that has been shown on screen, or 'realized') from a thread other than the event dispatch thread. That's a violation of the Swing threading model, and will cause you no end of problems.</p> <p>If you want to make changes to a Swing object from a different thread, you package the change up in a Runnable and submit it to the dispatch thread using EventQueue.invokeLater() or invokeAndWait().</p> <p>EDIT: more info</p> <p>Some additional comments (not directly related to your problem, but important nonetheless): Performing activity in a constructor is probably not a good idea. Subclassing JFrame to add components to it is also probably not a good idea. For that matter, doing these operations in a JFrame instead of a JPanel is probably not the best approach either.</p> <p>Taking these in turn:</p> <ol> <li><p>Constructors should be used to perform initial configuration on objects - not invoke behavior. This separation helps to keep your design clean and maintainable. Even though it might seem to be easier to do it this way, I recommend against. At some point in your design, you may decide that it's more efficient to create these objects in advance, and only use them later.</p></li> <li><p>Subclassing a JFrame to add components is usually not a hot idea. Why? What if you decide that you want to use a specialized JFrame that has some other behavior that you want? What if you decide to use an application framework that provides <em>you</em> with the JFrame (this is typical in cases where the framework might want to track window closing events so it can save window size and location). Anyway - tons of reasons. Package your behavior into a non-GUI related class, and use that to inject behavior into the JFrame (or JPanel).</p></li> <li><p>Consider using a JPanel instead of a JFrame. You can always add the JPanel to a JFrame if you want. IF you word directly with JFrame, what happens when you decide that you want to have two of these panels side by side in a single container? </p></li> </ol> <p>So, I would suggest that you do something more along the lines of:</p> <pre><code>BlockAnimator animator = new BlockAnimator(); DispatchThread.invokeLater( new Runnable(){ public void run(){ JPanel blockAnimationPanel = new JPanel(); Block block = new Block(...); blockAnimationPanel.add(block); JFrame mainFrame = new JFrame(); mainFrame.add(blockAnimationPanel); animator.start(); // note that we probably should start the thread *after* the panel is realized - but we don't really have to. } } public class BlockAnimator extends Thread{ private final List&lt;Block&gt; blocks = new CopyOnWriteArray&lt;Block&gt;(); // either this, or synchronize adds to the list public void addBlock(Block block){ blocks.add(block); } public void run(){ while(true){ // either put in a cancel check boolean, or mark the thread as daemon! DispatchThread.invokeAndWait( new Runnable(){ public void run(){ for(Block block: blocks){ block.moveTo(....); // do whatever you have to do to move the block } } } ); // I may have missed the brace/paren count on this, but you get the idea spawnNewBlockObjects(); Thread.sleep(50); } } } </code></pre> <p>Code above hasn't been checked for accuracy, etc...</p> <p>You could, theoretically, have a separate thread for spawning the new blocks, but the above is pretty straightforward. If you do decide to implement with a single background thread like I've shown a above, you can use a simple ArrayList for the blocks list because there will be no race condition on that object.</p> <p>A couple of other thoughts on this:</p> <ol> <li><p>In the above, the block animator can be managed independently from the blocks themselves. You could, for example, add a pause() method that would pause all blocks.</p></li> <li><p>I have the animation update for all blocks occuring in the same dispatch thread call. Depending on the cost of the animation, it may be better to compute the new coordinates on the background thread, and only post the actual position update on the EDT. And you may choose to issue a separate invokeAndWait (or possibly use invokeLater) for each block update. It really depends on the character of what you are doing.</p></li> </ol> <p>If the computation for where to move the block is gnarly, consider separating the computation from the actual move. So you'd have a call that would get the new Point for the object, then another call that would actually do the move.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload