Wait one second after click and change JLabel icon [duplicate] - java

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();

Related

GUI freezes using Thread

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.

How do I delay a while loop? [duplicate]

This question already has answers here:
Why does this simple Java Swing program freeze?
(5 answers)
Closed 7 years ago.
I'm trying to make a while loop that increments a double by 0.1 once every second:
public void keyReleased(KeyEvent e)
{
//When a key is released, look for any collision problems
airOrGround(xPos, yPos);
collision(xPos, yPos);
//As long as onGround (which is set to false or true in airOrGround) is false,
//yPos should increment by 1 every second
while(onGround == false)
{
try {
Thread.sleep(1*1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
yPos += 0.1;
yPos = (Math.round(yPos * 10) / 10.0);
start.setText("X = " + xPos + ", Y = " + yPos);
airOrGround(xPos, yPos);
}
}
Once I run it, as soon as the keyReleased() runs, the program freezes. I've also tried putting the while loop inside the try, but that doesn't work either. No errors appear in the console and without the Thread.sleep part it doesn't freeze
You should look at javax.swing.Timer class.
public class Whatever
{
javax.swing.Timer t = new javax.swing.Timer( 1000, new MyListener() );
...
t.start();
}
public class MyListener() implements ActionListener
{
public void actionPerformed( ActionEvent e )
{
if( !onGround )
{
...
}
}
}
For clarity I should explain that this means you don't actually need a while loop. The Timer does the sleeping part for you, effectively.
Also, when I've used the Timer class I've had the ActionListener class (my implementation) be an inner class, so it shares instance variables.
Here is an example of a SwingWorker
I suggest using this if you would like to have a multi-threaded Swing application that needs to update a component. It does it safely on the EDT so your application doesn't freeze up.
SwingWorker<Void, Integer> updater = new SwingWorker<Void, Integer>()
{
#Override
protected Void doInBackground() throws Exception
{
boolean something = false;
int someInt = 3;
while(!something)
{
publish(someInt++);
//publish() adds someInt to the chunks list
//in the process method so you can access it later.
Thread.sleep(1000);
if(someInt == 10)
{
something = true;
}
}
return null;
}
#Override
protected void process(java.util.List<Integer> chunks)
{
for(int num : chunks)
{
label.setText(String.valueOf(num));
}
//This gets each value you added to the chunks list
//So you can update the label with each value
}
#Override
protected void done()
{
//Leave blank or add something to do when the process is finished
}
};
updater.execute();

when add new element on list repaint stops for a moment

Java.problem is when i start addding new element repaint stops every time for a moment while timer is working and elements are moving finaly when it repaints elements just jump like thay have been moving all this time.also there is throwing strange exeption. some code:
public void paintComponent(Graphics g)
{
g = (Graphics2D) g;
g.drawImage(img1, 0, 0,null);
Iterator<zombie> it = zombies.iterator();
while(it.hasNext())
{
if(it.next().heals <= 0)
{
it.remove();
}
else{
g.drawImage(it.next().img ,it.next().x , it.next().y , null);
}
}
}
public void actionPerformed(ActionEvent e)
{
Iterator<zombie> it = zombies.iterator();
while(it.hasNext())
{
it.next().move();
}
repaint();
}
that is new thread that generates new items:
public void run()
{
Random rd = new Random();
while(true)
{
try {
Thread.sleep(1000 + rd.nextInt(2000));
if(rd.nextInt(4) == 1)
{
zombies.add(new ZombieLow(1000,rd.nextInt(500),1,20,300));
}
else
{
zombies.add(new ZombieHard(1000,rd.nextInt(500),1,15,700));
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
what is that problem with? if you need more info just say i will give it.
try to put the repaint() method in the while loop. In your case you repaint your Zombie after moving all.
another thing if you use Thread.sleep() in the move method you should make every Zombie in his own Thread.
Hope that helps, Salam =)

Using Jinput to pop up a JFrame WIndow alarm

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);
}
}
});

Make a main method wait on a smaller method (java)

i really need to find better ways to word my questions.
Basically I've created a program that takes information from a webpage and displays it nicely across the screen.
When the user closes the program, they actually hide it.
I also have another method which constantly loops checking for information to see if tis been updated.
unfortunately the problem im having is that it loops to fast, i only want it to check for information every 40 seconds or so.
What i tried was inserting a wait(1000,1000) in the method itself and in the main of the program. but both of these cause IllegalMonitorStateException.
Is this the correct way to make the thread wait properly? or is there a better way?
note: the only thread i have is the main.
MAIN
class Marquee
{
public static void main(String[] args) throws InterruptedException
{
MyFrame frame = new MyFrame();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setBackground(Color.BLACK);
frame.setResizable(true);
while(true)
{
// this doesnt work
frame.wait(1000,1000);
frame.notifyAll();
frame.checkForNewUpdate();
System.out.println(" ____________________________next line _______________________________");
}
}
}
CHECK FOR UPDATES
public String[] checkForNewUpdate()
{
//setVisible(true);
String tempUpdate = getEngineersUpdate();
if (latestUpdate[0] != tempUpdate)
{
// do nothign
setVisible(false);
}
else if(latestUpdate[0]==tempUpdate)
{
latestUpdate[0] = tempUpdate;
//show the page again
setVisible(true);
}
else if(latestUpdate[0]!= "NULL")
{
// do nothing
//latestUpdate[0] = tempUpdate;
}
else
{
latestUpdate[0] = tempUpdate;
}
return latestUpdate;
}
1: WHat am i doing wrong to get this exception
2: Is there any other way to make a gap of time in a method
3: Am i going to have to put all these methods into another thread? Please say no
// my constructor which I failed to mention has a timer in it. only i dont know hwo to use it
class MyFrame extends JFrame implements ActionListener
{
private ActionListener listener;
private Timer t1;
private String [] latestUpdate = new String[1];
public MyFrame()
{
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();// gets the maximum size of the screen
setSize(d.width,(d.height/100)*10);//sets it to max. need to change this
// this shit find the max size of screen and puts it bottom left
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
int x = (int)rect.getMinX();
int y = (int)rect.getMaxY()-getHeight();
setLocation(x,y-30);
setTitle("ALERT::OUTAGE");
MyPanel panel = new MyPanel();
add(panel);
listener = this;
t1 = new Timer(50,listener);
t1.start();
}
by request, here is getEngineersUpdate()
public String getEngineersUpdate() //gets data from page and sets it to string.
{
String update = "blank";
final WebClient webClient = new WebClient();
webClient.setJavaScriptEnabled(false);// javascript causes some serious problems.
webClient.setCssEnabled(false);
String forChecking;
HtmlPage page;
try
{
URL outageURL = new URL("file:\\C:\\Users\\0vertone\\Desktop\\version control\\OUTAGE\\Outages.html"); //local drive at home
page = webClient.getPage(outageURL);
//All this crap can be gone if we just give the table an id
Object[] dates = page.getByXPath("//span[#id='date']/text()").toArray();
Object[] sites = page.getByXPath("//span[#id='site']/text()").toArray();
Object[] issues = page.getByXPath("//span[#id='issue']/text()").toArray();
System.out.println("" + dates[0].toString());
System.out.println("" + sites[0].toString());
System.out.println("" + issues[0].toString());
update = (dates[0].toString() + " " + sites[0].toString() + " " +issues[0].toString());
forChecking = dates[0].toString();
/**some examples of the getCellAt() method*/
//update = table.getCellAt(0,0).asText(); // This returns DATE/Time
//update = table.getCellAt(1,0).asText(); // This return the actual date
//update = table.getCellAt(0,1).asText(); // This returns, SITE/Sector
//update = table.getCellAt(1,1).asText(); // This returns the actual site issue
}
catch (FailingHttpStatusCodeException a)
{
System.out.println("Failing HTTP Status Execution");
a.printStackTrace();
}
catch (MalformedURLException b)
{
System.out.println("Malformed URL");
b.printStackTrace();
}
catch (IOException c)
{
System.out.println("IO PROBLEMS!");
c.printStackTrace();
}
webClient.closeAllWindows();
return update;
}
I've changed your code so it should work as you intended. I'm not clear on what getEngineersUpdate() does, so I can't say for sure if it will work, but I've given you a start. I've included 2 options for how to handle it, with explanation in the comments. You can see how to use a Timer properly in the constructor, also. Finally, I don't have your full code, so I had to rig something together to simulate it.
class Marquee {
public static void main(String[] args) throws InterruptedException {
MyFrame frame = new MyFrame();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setBackground(Color.BLACK);
frame.setResizable(true);
}
}
class MyFrame extends JFrame {
private String [] latestUpdate = new String[1];
private static final int DISPLAY_TIME = 3000;
private Timer displayTimer;
/*
* Option #1:
* Ideally, you'd have the thread that generates the "Engineers Update" messages call this
* method. If you can't make this event based, then you should use option #2
*/
public void newUpdate(String message) {
setVisible(true);
// change this to whatever you need to.
text.setText(message);
displayTimer.restart();
}
// I used this to test it
private JTextField text;
public MyFrame() {
// gets the maximum size of the screen
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
//sets it to max. need to change this
setSize(d.width, (d.height / 100) * 10);
// this shit find the max size of screen and puts it bottom left
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
int x = (int) rect.getMinX();
int y = (int) rect.getMaxY() - getHeight();
setLocation(x, y - 30);
setTitle("ALERT::OUTAGE");
//MyPanel panel = new MyPanel();
//add(panel);
text = new JTextField("Initial Text");
add(text);
// this creates a timer that when it goes off, will hide the frame
displayTimer = new Timer(DISPLAY_TIME, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
// sets the timer not to repeat
displayTimer.setRepeats(false);
//This code is for option #2:
updateTimer = new Timer(UPDATE_INTERVAL, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
checkForNewUpdate();
}
});
updateTimer.start();
}
// This is for option #2
private static final int UPDATE_INTERVAL = 1000;
private Timer updateTimer;
/*
* Option #2:
* Not ideal, but this should work.
*/
public String[] checkForNewUpdate() {
// I don't know how getEngineersUpdate() works
// which would have made it much easier to help you.
String tempUpdate = getEngineersUpdate();
// String comparison doesn't work like this in java.
// you also had a sleeping NullPointerException here
if (!tempUpdate.equals(latestUpdate[0])) {
// this is when you have a new update, correct?
newUpdate(tempUpdate);
latestUpdate[0] = tempUpdate;
} else if (tempUpdate.equals(latestUpdate[0])) {
// it's the same update as last time, so do nothing
} else if (tempUpdate.equals("NULL")) {
// You need to handle this according to what getEngineersUpdate() does
}
return latestUpdate;
}
// This code is rigged to show how it would work
private static int i = 0;
private String getEngineersUpdate() {
// 1 in 6 chance of returning "NULL"
if (Math.random() * 6 - 1 < 0)
return "NULL";
// probability of 1 in 4 of generating a new update
if(Math.random() * 4 - 1 < 0)
return "UPDATE #"+i++;
else
return "UPDATE #"+i;
}
}
I think you can't call wait() on an JFrame, but I am not sure.
You have to call wait() within a snychronized-block. (Example below)
Thread.sleep(1000l) can be used, if it runs in a Thread, but look for the class Timer
It would be much better design, if you create a thread, which checks for updates. You can notify the GUI (JFrame) with some kind of event-listener about the new date to display.
Take a look at the Timer and Callable.
You should create another thread, you should call checkforNewUpdate method from this thread. And also do not forget use SwingUtilities.invokeLater method to update your UI inside checkforNewUpdate method. here is the some part of the code;
public class Marque {
private JFrame frame;
class CheckForUpdate implements Runnable {
public void run() {
while(true) {
checkForNewUpdate();
try {
Thread.sleep(40000);
} catch (InterruptedException e1) {
e1.printStackTrace();
throw new RuntimeException(e1);
} }
}
public String[] checkForNewUpdate() {
//your code
// user interface interaction code
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
}
public Marque() {
frame = new JFrame();
//....frame related code
new Thread(new CheckForUpdate()).start();
}
public static void main(String[] arg) {
Marque marque = new Marque();
}

Categories

Resources