Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Let's talk about what's wrong...</p> <p>AWT (and Swing) use a single thread, known as the Event Dispatching Thread (AKA EDT) which is responsible for processing user input (like mouse and keyboard events), system events (like changes to the components internally and externally (coming from the OS)) and, most importantly for this issue, paint requests.</p> <p>AWT (and Swing) use, what is known as, a passive painting algorithm. That is, painting is done on a request bases, so only those things that need to be changed are changed.</p> <p>When a paint event is processed by the EDT, the <code>paint</code> method is (eventually) called by the EDT. The expectations is that the <code>paint</code> methods will execute as fast as possible and return. This is important, as any delay in the <code>paint</code> methods will cause delays in how fast program is updated.</p> <p>So, anything the blocks EDT (like long running looks or <code>Thread.sleep</code>) will stop it from been able to process new events and particular in this context, paint requests.</p> <p>For more details, take a look at <a href="http://www.oracle.com/technetwork/java/painting-140037.html" rel="nofollow noreferrer">Painting in AWT and Swing</a> for more details...</p> <p>Now, how to fix it.</p> <p>Basically, what you need some way to run a background task that makes the updates to what you want to paint and then push those updates to the screen. This ensures that the EDT is not blocked and can continue to process incoming events...</p> <p>For example...</p> <pre><code>private int x = 0; private int y = 0; private Thread t; private volatile boolean keepRunning; @Override public void init() { setBackground(Color.BLACK); } @Override public void start() { keepRunning = true; t = new Thread(new Runnable() { private boolean state = false; public void run() { while (keepRunning) { if (state) { setForeground(Color.BLACK); } else { x = (int)(Math.random()*495+1); y = (int)(Math.random()*200+1); setForeground(Color.WHITE); } state = !state; repaint(); try { Thread.sleep(500); } catch(InterruptedException ex) { keepRunning = false; } } } }); } @Override public void stop() { keepRunning = false; } @Override public void paint(Graphics g) { super.paint(g); g.setColor(getForeground()); g.fillOval(x,y,5,5); } </code></pre> <p>So basically, when started, the <code>Applet</code> creates a <code>Thread</code> that is responsible for making the changes to the applet and finally requests that the <code>Applet</code> be repainted.</p> <p>Now, the problems...</p> <p>There are a number of problems with both approaches (yours and mine). The first is the fact the <code>Applet</code>s are not double buffered, this means that it can produce flickering when it is painted.</p> <p>The next is the fact that the values you are painting are being updated by another <code>Thread</code>, this means you could end up with dirty paints as the values are changed while the <code>paint</code> method is updating the UI.</p> <p>Instead, I would take advantage of the Swing API, as it's components are double buffered by default, making it easier to perform fast updates.</p> <p>It will also allow you to take advantage of the <code>javax.swing.Timer</code>, which can be configured to schedule regular updates which are executed within the context of the EDT. This means, when making changes the state of the components, they can't be painted, making it safer. </p> <pre><code>import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JApplet; import javax.swing.JPanel; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class RandomApplet extends JApplet { private RandomPane randomPane; private Timer timer; public RandomApplet() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } } @Override public void init() { EventQueue.invokeLater(new Runnable() { @Override public void run() { setLayout(new BorderLayout()); randomPane = new RandomPane(); add(randomPane); } }); } @Override public void start() { EventQueue.invokeLater(new Runnable() { @Override public void run() { // Just want to make sure that the timer is not started before the // UI is initalised... if (timer != null &amp;&amp; timer.isRunning()) { timer.stop(); } timer = new Timer(500, new ActionListener() { private boolean state = false; @Override public void actionPerformed(ActionEvent e) { if (state) { randomPane.setForeground(Color.BLACK); } else { randomPane.randomise(); randomPane.setForeground(Color.WHITE); } state = !state; repaint(); } }); timer.start(); } }); } @Override public void stop() { timer.stop(); } public class RandomPane extends JPanel { private int xPos; private int yPos; public RandomPane() { setBackground(Color.BLACK); setForeground(Color.BLACK); } @Override public Dimension getPreferredSize() { return new Dimension(495, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.setColor(getForeground()); g2d.fillOval(xPos, yPos, 5, 5); g2d.dispose(); } public void randomise() { xPos = (int) (Math.random() * (getWidth() - 5)); yPos = (int) (Math.random() * (getHeight() - 5)); } } } </code></pre> <p>Take a look at <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html" rel="nofollow noreferrer">Concurrency in Swing</a> for more details...</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

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