I'm creating a silly game, and the first thing I want to make is to tell you "You Lose" if the all that you control with the mouse is not inside the frame. I created a JComponent and every 20 milliseconds it is repainted (A thread does that). Inside it, I detect if the ball is inside the the frame, an if it's not, I just call a method that puts a JOptionPane that says "You Lose", and then exits the program. the problem is, since the JComponent is repainted every 20 milliseconds, loads of JOptionPane messages star to appear. I've tried making the repainting stop, but I was unsuccessful. I tried using the interrupt() method of the thread, telling it to sleep(), removing it from the ScheduledThreadPoolExecutor it was being executed by, shutting down the executor, but nothing worked. How can I make the repainting stop?

Thanks in advance.

Dani AI

Generated

Short answer: move game logic out of your painting code, stop the update timer cleanly, and show the dialog exactly once on the Event Dispatch Thread. That prevents repeated JOptionPanes and lets the last drawn frame persist.

You were on the right track with a boolean (), and is right about separating logic and paint. Do collision checks and state changes in your update/tick loop; let paintComponent only render the current model. Using a Swing Timer makes this simple because its ActionListener runs on the EDT and can stop itself safely:

Timer timer = new Timer(20, e -> {
    updateModel();          // move collision/lose logic here
    panel.repaint();
    if (gameOver) {
        ((Timer)e.getSource()).stop();
        JOptionPane.showMessageDialog(frame, "You Lose"); // runs on EDT
        System.exit(0);
    }
});
timer.start();

If you must use a background ScheduledExecutorService, cancel the ScheduledFuture (or shutdown the executor) and always invoke UI work with SwingUtilities.invokeLater. To make the last image stay, do not clear-and-return early in paintComponent when stopped; either keep painting the model state when gameOver is true or capture the final frame to a BufferedImage and draw that. Also guard the dialog with an AtomicBoolean so it can only be shown once if multiple threads race. Finally, avoid heavy work on the EDT (keep updates cheap or run physics off-EDT and post repaint to EDT).

Recommended Answers

All 6 Replies

don't do that

I created a JComponent and every 20 milliseconds it is repainted

because latency from Native OS are always more than 63ms, yes is possible to paint every 50ms but you have to implements DirtyRegion to avoids GUI's freeze or RepaintManagerError, start with 100ms, better would be 250ms

you have to stop ScheduledThreadPoolExecutor, same as you start ....,

if you want to play with Executor, then look for Monitor

perhaps you can add some boolean variable and an if statement that check for truth value of the variable and call the repaint method only inside the if statement, which means that repaint will be called only while the boolean variable evaluates to true. hope that helps.

perhaps you can add some boolean variable and an if statement that check for truth value of the variable and call the repaint method only inside the if statement, which means that repaint will be called only while the boolean variable evaluates to true. hope that helps.

Thank you, this worked! But the problem is, since it repaints, but nothing happens because the boolean changed, after you lose the screen becomes empty, because nothing is being painted. I wanted a way to stop the thread that repainted so that the last image before you lose remained. But thanks.

I guess if your if statement is the last inside your paintComponent method, the last screen should persist unless you have some other place you invoke the repaint method in... like say if you have an interactive application, like some button or some method linked to some key pressed, and it calls repaint... then you of course are invoking the repaint outside the paintcomponent method too, and in that case your boolean variable may be out of reach and useless. glad you made it work.

I guess if your if statement is the last inside your paintComponent method, the last screen should persist unless you have some other place you invoke the repaint method in... like say if you have an interactive application, like some button or some method linked to some key pressed, and it calls repaint... then you of course are invoking the repaint outside the paintcomponent method too, and in that case your boolean variable may be out of reach and useless. glad you made it work.

The repaint is called in a Thread, what should work is to stop the Thread, but my attempts didn't work.

You really should try to keep your logic and your painting as separate as possible...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.