I´m new to thread programming and I started a Thread that moves a JPanel inside a Frame. But when I invoke the method the Frame freezes completely and I have to force it to close.
Here´s the simplified method I´ve implemented
public class Thread extends Thread{
public void movePanel(Frame f) {
try {
long t = f.getTime();
while (true) {
f.changeColor();// changes Colour of current JPanel
Thread.sleep(t);
while (true) {
f.setNextPosition(direction);// sets the Position, where the JPanel moves next
p = f.getNextPosition();
f.moveForward();// moves in given direction
Thread.sleep(dauer);
if (p == null)// checks if the next Position is accessible {
f.moveDown();
Thread.sleep(t);
while (true) {
f.moveBackwards();
Thread.sleep(t);
if (p == null) {
f.moveDown();
Thread.sleep(t);
}
}
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
What could cause the problem?
I would appreciate your help very much.
Related
I am using a thread to draw images onto a JFrame.
I added a keyListener to listen for the key P, when it is pressed, the drawing of images stops and when I press P again, the drawing should resume.
I tried using wait/ notify along with synchronized block for implementing this.
However only Pausing works, the resume never works.
Strange...
public static void main(String[] args)
{
static JFrame window1 = new JFrame();
static boolean isPaused=false;
Runnable r = new Runnable()
{
public void run()
{
while(true)
{
window1.paintImage();//fn to redraw an image
}
}
};
final Thread t = new Thread(r);
window1.addKeyListener(new KeyListener()
{
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_P)
{
if(isPaused==false)
{
synchronized(t)
{
try
{
t.wait();
} catch (InterruptedException e1)
{
e1.printStackTrace();
}
}
isPaused=true;
} else
{
t.notifyAll();
isPaused=false;
}
}
}
public void keyReleased(KeyEvent arg0){}
public void keyTyped(KeyEvent arg0){}
});
t.start();
}
}
You should go through the Javadoc of Object.wait.
When t.wait() is executed, the current thread is "paused", not t.
More exactly, you are pausing the SWING Thread that is in charge of handling inputs, not the Thread t that you created to redraw the image.
t.wait() makes the SWING Thread to wait until it receive a notify() which will never come because the t.notifyAll() can only be reached by this same SWING Thread (so it is like you are going to sleep and you are waiting for yourself to wake you up... good luck with that).
Here is one solution to fix it (not the best though, since it does not care about synchronization):
final boolean [] pause = new boolean []{false};
Runnable r = new Runnable()
{
public void run()
{
while(true)
{
if(!pause[0])
window1.paintImage();//fn to redraw an image
}
}
};
...
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_P)
{
if(!pause[0])
{
pause[0] = true;
} else
{
pause[0] = false;
}
}
}
I'm trying to learn Threads in Swing.
I have a Frame with a JProgressBar (progress), five JButtons (Start, Suspend, Resume, Cancel, Close), and a JLabel (label1).
The frame opens. Only Start is enabled. Start calls my class Progressor:
Updated Again Once and For All
Progressor progressor; //declared as class variable, initialized new in constructor and again in overridden done method
Here's the ButtonListener class:
public class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == jbStart) {
progressor.execute();
label1.setText("Progressing ...");
jbCancel.setEnabled(true);
jbResume.setEnabled(true);
jbSuspend.setEnabled(true);
jbClose.setEnabled(true);
}
if(e.getSource() == jbCancel) {
progressor.cancel(true);
label1.setText("Progress Canceled");
}
if (e.getSource() == jbSuspend) {
label1.setText(progressor.suspendProgress());
}
if (e.getSource() == jbResume) {
label1.setText(progressor.resumeProgress());
}
if (e.getSource() == jbClose) {
dispose();
}
}
}//buttonlistener
Here's the SwingWorker class:
public class Progressor extends SwingWorker<Void, Integer> {
private volatile boolean suspend = false;
private Object lock = new Object();
#Override
protected Void doInBackground() {
for (int i = 0; i <= 10; i++) {
checkForSuspend();
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
publish(i);
}
return null;
}
#Override
protected void process(List<Integer> list) {
int value = list.get(list.size() - 1);
progress.setValue(value);
}
public void checkForSuspend() {
synchronized (lock) {
while (suspend) {
try {
lock.wait();
} catch (InterruptedException ie){
}
}
}
}//checkForSuspend
#Override
protected void done() {
label1.setText("All Done. Press close to exit");
progressor = new Progressor();
}
public synchronized String suspendProgress() {
suspend = true;
return "Progress suspended ...";
}
public synchronized String resumeProgress() {
synchronized (lock) {
suspend = false;
lock.notify();
return "Progress resumed ...";
}
}
}//Progressor class
Everything works except the cancel doesn't doesn't actually cancel the thread (the progress bar continues).
Should I suspend it before canceling?
This How to Pause and Resume a Thread in Java from another Thread question looks very similar to yours and has some nice examples in the answers.
As for your own code and why it does not work:
You create a new progressor on every click. You should be using and controlling one, instead of creating new ones every time.
When suspending your progressor finishes work instead of suspending. As the above question states - you should be looking at the flag at some points of your computation and acting on it. Example:
while (!cancel) {
if (!suspended) {
for (int i = 1; i <= 10; i++) {
Thread.sleep(1000);
publish(i);
}
}
}
The above code will suspend when it next reaches 10 (unless you resumed it before that), and finish when you press cancel (Cancel needs to be added as an extra flag in the obvious manner).
Your thread should run inside a while loop that looks for a boolean to change value from another object, then simply change the state with setPause(true/false) when you click the button:
while(true){
if(object_everyone_can_reference.getPause()){
Thread.sleep(1000);
}
}
This question already has an answer here:
SwingWorker, Thread.sleep(), or javax.swing.timer? I need to "insert a pause"
(1 answer)
Closed 9 years ago.
I am working on my first Swing application. It is a memory game using poker cards.
I simulate cards using JLabels and setting icons for front and back sides. Each card has a MouseListener and when the user clicks, I check if two cards are the same. If they aren't the same card, I want to show these two cards for one or two seconds and after this delay, change icon back.
I tried using sleep, wait, invokeLater, invokeAndWait... but nothing works.
This is my main class:
public class Main {
public static void main(String[] args) throws FontFormatException, IOException {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
MyApp window = new MyApp();
} catch ( FontFormatException | IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
MyApp inherits from JFrame. Inside it, I add all my cards to one panel:
while ( cont < cardsInGame.size() ){
this.cardsInGame.get(cont).setBounds(x, y, 100, 140);
panelTablero.add(cardsInGame.get(cont));
cardsInGame.get(cont).addMouseListener(this);
x = x+108+5;
if ( (cont+1)%8 == 0 && cont != 0){
y = y+140+15;
x = 53;
}
cont++;
}
And this is the MouseListener:
public void mouseClicked(MouseEvent e) {
Card selectedCard = (Card)e.getSource();
if (selectedCard != activeCard){
selectedCard.setIcon(new ImageIcon("img/"+selectedCard.getSuit()+selectedCard.getValue()+".png"));
//JOptionPane.showMessageDialog(vp, "Wait");
if ( activeCard != null && !activeCard.getPaired()) {
int result = activeCard.isPair(selectedCard);
pairsTried++;
if ( result != 0 ){
// PAIR
}
else{
// I WANT TO WAIT HERE
// NO PAIR
selectedCard.setIcon(new ImageIcon(CARD_BACK));
activeCard.setIcon(new ImageIcon(CARD_BACK));
}
activeCard = null;
}
else{
activeCard = selectedCard;
}
}
}
If I put a call to JOptionPane.showMessageDialog(vp, "Wait") in my code, all works well. The icon is refreshed and after that wait for dialog OK. If not, the icon never is refreshed (or is ultra fast and is not showing).
How can I add this delay?
Have u tried to put a therad inside this else?
Runnable r = new Runnable() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
Thread asd = new Thread(r);
asd.start();
Using Jinput and Java in Netbeans, I'm working on a very small project that simply Pops up a JFrame alarm window when lets say a user presses down on the 'K' on the keyboard and terminates the JFrame alarm window when the user lets go of 'k'. In my code, I seemed to get stuck in the while loop as the JFrame opened on the first press down and couldn't seem to close. I researched and I found that using javax.swing.Timer was the better way to do it. However, since I'm a newbie at this, all the different ways to use timer just made me even more confused. Could someone please see my code and point me in the right direction?
Here is my code;
public void startPolling() {
while(true) {
ControllerEnvironment.getDefaultEnvironment().getControllers();
ca[index].poll();
EventQueue queue = ca[index].getEventQueue();
Event event = new Event();
while(queue.getNextEvent(event)) {
StringBuffer buffer = new StringBuffer(ca[index].getName());
buffer.append(" at ");
buffer.append(event.getNanos()).append(", ");
Component comp = event.getComponent();
buffer.append(comp.getName()).append(" changed to ");
float value = event.getValue();
if(comp.isAnalog()) {
buffer.append(value);
} else {
if(value==1.0f) {
buffer.append("On");
if ("K".equals(comp.getName())){
alarmBox();
}
} else {
buffer.append("Off");
if ("K".equals(comp.getName())){
alarmBox.setVisible(false);
}
}
}
System.out.println(buffer.toString());
}
}
}
alarmBox() is my JFrame.
I was working on it and here is my updated code:
public void startPolling() {
Timer timer = new Timer(50, new ActionListener() {
public void actionPerformed(ActionEvent e) {
ca[index].poll();
EventQueue queue = ca[index].getEventQueue();
Event event = new Event();
while(queue.getNextEvent(event)) {
StringBuffer buffer = new StringBuffer(ca[index].getName());
buffer.append(" at ");
buffer.append(event.getNanos()).append(", ");
Component comp = event.getComponent();
buffer.append(comp.getName()).append(" changed to ");
float value = event.getValue();
if(comp.isAnalog()) {
buffer.append(value);
} else {
if(value==1.0f) {
buffer.append("On");
if ("K".equals(comp.getName())){
alarmBox();
}
} else {
buffer.append("Off");
if ("K".equals(comp.getName())){
alarmBox.dispose();
}
}
}
System.out.println(buffer.toString());
}
try {
Thread.sleep(20);
} catch (InterruptedException f) {
f.printStackTrace();
}
}
}); timer.start();
if you just want to open and close window,y to use timer?
you have a very complicated code,for a simple task.
you can add a ComponentListener to your JFrame to hide,somthing like this:
frame.addComponentListener(new ComponentAdapter(){
public void componentMoved(ComponentEvent e) {
if (popup.isVisible()){
popup.setVisible(false);
}
}
});
Good day!
I wanted use a standart Swing Timer with Full Screen Exclusive Mode. To this effect I applied a SwingWorker to control the event when graphic mode should be set. All following steps are executed in run method. run() is called from main.
1)First of all, I create my SwingWorker object and override two its methods(doInBackground and done). Init is important method because it should set all needfull graphic setting to current JFrame object and bind my key listener objet(called screen_list) with it:
...
worker = new SwingWorker<Window, Void>()
{
public Window doInBackground()
{
init();
return gdev.getFullScreenWindow();
}
public void done()
{
try {
disp = get();
}
catch (InterruptedException ignore) {}
catch (java.util.concurrent.ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
};
...
2)then I create my screenlistener that implements an ActionListener and a Key Listener, it is bound with disp as KeyListener in init() method:
private void init()
{
...
try
{
disp = gdev.getFullScreenWindow();
if(disp != null)
{
gdev.setDisplayMode(use_dm);
disp.createBufferStrategy(2);
disp.setFocusTraversalKeysEnabled(false);
disp.addKeyListener((KeyListener)screen_list);
}
}
catch(IllegalArgumentException ex)
{
}
...
}
3)I create and initialize my Swing Timer and start it;
4)And finally i call execute method:
public void run(int pause, int delay)
{
...
try
{
screen_list = new ScreenListener();
tm = new Timer(delay, screen_list);
tm.setInitialDelay(pause);
tm.setRepeats(true);
tm.start();
worker.execute();
}
catch(Exception e)
{}
...
}
Class ScreenListener as i have written implements a KeyListener and an ActionListener. In ActionPerfomed method i check out did worker do its job(init method), if yes, i get ref to current display mode and draw something:
class ScreenListener implements ActionListener, KeyListener
{
public void actionPerformed(ActionEvent e)
{
if(!worker.isDone())
{
return;
}
else
{
//gdev - GraphicsDevice type
disp = gdev.getFullScreenWindow();
if (disp != null)
{
...
draw(gr);
...
}
}
}
...
}
Why aren't events from keyboard processed?
I don't make all of those Swing calls from init. Init should set all needfull graphic setting to current JFrame object and bind key listener with it.
OK, I see you've changed your code some:
private void init()
{
...
try
{
disp = gdev.getFullScreenWindow();
if(disp != null)
{
gdev.setDisplayMode(use_dm);
disp.createBufferStrategy(2);
disp.setFocusTraversalKeysEnabled(false);
disp.addKeyListener((KeyListener)screen_list);
}
}
catch(IllegalArgumentException ex)
{
}
...
}
but you're still making Swing calls in init when you get the JFrame, set its display mode and buffer strategy, it's focus traversal business, and add a key listener. Why are these calls being made in a background thread as they wouldn't be expected to interfere with Swing processing (so no need to be done on the background), and are actually "Swing calls" since you're changing the state of Swing objects with them. doInBackground is for running long-running or cpu-intensive processes that if run on the EDT would freeze the GUI and make it unresponsive. The code you've shown does not do this. The danger of doing Swing calls in a background thread is that while it will work 95% of the time, it will fail at unexpected times causing your app to crash and burn, usually at the most inopportune time.
Also, why the empty catch block? I'd at least put in an ex.printStackTrace() in there so as not to fly blind.
2)then I create my screenlistener that implements an ActionListener and a Key Listener, it is bound with disp as KeyListener in init() method:
So am I right in stating that you're adding a KeyListener to a JFrame? I doubt that this will work since KeyListeners only respond if the bound component has the focus, something a JFrame would rarely do or want to do. Perhaps you wish to use the more versatile key bindings as this will allow greater flexibility with regards to focus and responsiveness.
3)then I create and initialize my Swing Timer and start it;
OK
4)And finally i call execute method. –
public void run(int pause, int delay)
{
...
try
{
screen_list = new ScreenListener();
tm = new Timer(delay, screen_list);
tm.setInitialDelay(pause);
tm.setRepeats(true);
tm.start();
worker.execute();
}
catch(Exception e)
{}
...
}
Again you've got an empty catch block.
And can you tell us more about your specific problems? We see bits and pieces of unrelated code with a vague description of sort of what it does, but don't really have a full idea of anything yet. Can you give us a more detailed description of your program and its problems? Are you trying to create the SSCCE as recommended by Andrew? If you could create and post this, we'd be much better able to test and modify your program and help you to a solution. Best of luck
I used a SwingWorker capabilities because full screen mode as yet had not set by the time timer already started.
Ок. I passed up using a SwingWorker. Instead of this I added a simple condition:
class ScreenListener implements ActionListener, KeyListener
{
public void actionPerformed(ActionEvent e)
{
System.out.println("ScreenListener: actionPerformed");
disp = gdev.getFullScreenWindow();
if(disp == null)
{
return;
}
else
{
//draw something
...
}
}
}
So now my run method looks like this
public void run(int pause, int delay)
{
screen_list = new ScreenListener();
init();
try
{
tm = new Timer(delay, (ActionListener)screen_list);
tm.setInitialDelay(pause);
tm.setRepeats(true);
tm.start();
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
if(!tm.isRunning())
{
...
}
}
}
And I make a focusable my disp:
private void init()
{
JFrame frame = new JFrame();
...
disp = new Window(frame);
DisplayMode[] dms = gdev.getDisplayModes();
DisplayMode use_dm = null;
if(gdev.isFullScreenSupported())
{
disp.setBackground(Color.CYAN);
disp.setForeground(Color.WHITE);
gdev.setFullScreenWindow(disp);
}
use_dm = getMatchMode(dms, def_dm);
try
{
disp = gdev.getFullScreenWindow();
if(disp != null)
{
...
disp.setFocusable(true);
disp.addKeyListener((KeyListener)screen_list);
...
}
}
catch(IllegalArgumentException ex)
{
ex.printStackTrace();
}
}
but I can't still catch my keyboard events. KeyTyped, KeyPressed, KeyReleased aren't still called so it is my problem in that programm.
My first aim was make a simple animation with full screen mode. At first i used a simple thread method - sleep - as for main thread. Then I added a swing timer for the same purpose but as you look I got a problem: I can't make to work my KeyListener.
I decided my problem:
1)Now FullScreen class extends from JFrame:
public class SimpleFullScreen extends JFrame
{
...
private synchronized void init()
{
Window disp = null;
//customize my display
setFocusable(true);
setResizable(false);
setIgnoreRepaint(true);
setUndecorated(true);
setBackground(Color.CYAN);
setForeground(Color.WHITE);
addKeyListener((KeyListener)screen_list);
DisplayMode[] dms = gdev.getDisplayModes();
DisplayMode use_dm = null;
if(gdev.isFullScreenSupported())
gdev.setFullScreenWindow(this);
use_dm = getMatchMode(dms, def_dm);
try
{
disp = gdev.getFullScreenWindow();
if(disp != null)
{
gdev.setDisplayMode(use_dm);
createBufferStrategy(2);
}
}
catch(IllegalArgumentException ex)
{
ex.printStackTrace();
}
}
...
}
2)Add loop in the run method, it checks out is timer running:
public void run(int pause, int delay)
{
Window disp = null;
screen_list = new ScreenListener();
init();
try
{
//Initialize and start timer
...
while(tm.isRunning())
{
System.out.println("Run: timer running");
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
try
{
if(!tm.isRunning())
{
disp = gdev.getFullScreenWindow();
disp.setVisible(false);
disp.dispose();
gdev.setFullScreenWindow(null);
System.exit(0);
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}
3) init, actionPerfomed and KeyPressed became the synchronized methods.
So ActionListener and KeyListener works good.
Thanks for responses!