Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.4k views
in Technique[技术] by (71.8m points)

java - Thread.sleep() starts before my JButton text changes (The animation is too long) How to prevent this?

I have a method here that creates 52 JButtons in a loop. When a button is clicked, according text is displayed on it. After two buttons' text has changed, the program sleeps for 1 seconds (to give the user time to look at them). However, the program sleeps before the button text change animation finishes and ends up not showing the text on the second button:

for(int i=0; i<52; i=i+1){
        //button creation
        final int a=i;
        JButton button_one=new JButton();
        buttons[a]=button_one;
        
        mainpanel.add(button_one);
        button_one.addActionListener(new ActionListener(){
            // what happens when the button is clicked
            @Override
            public void actionPerformed(ActionEvent button_picked){
                amount_of_cards_picked=amount_of_cards_picked+1;
                cardamountcheck();
                String selectedcard=null;
                if(twocardspicked==true){
                    userpick2=a;
                    selectedcard=setoutcards[userpick2];
                    System.out.println(selectedcard);
                    // button shows name of card
                    buttons[a].setText(selectedcard);
                    pairdetermination();
                    pairprobability();
                    
                    
                }
                else if(twocardspicked==false){
                    userpick1=a;
                    selectedcard=setoutcards[userpick1];
                    System.out.println(selectedcard);
                    System.out.println(cardspritesmap.get(selectedcard));
                    buttons[a].setText(selectedcard);
                // the two changed text buttons are stored in an array
                }
                if(twocardspicked==true){
                pickedcardbuttons[1]=buttons[a];
                
                }
                else if(twocardspicked==false){
                pickedcardbuttons[0]=buttons[a];
                }
                // sleep method is called
                oncardflipped(selectedcard);
                
            }
        });
    }

This is the method that starts the Thread.sleep():

public void oncardflipped(String card){
    if(twocardspicked==true){
        // if there are two cards picked, the sleep is activated
        try{
            Thread.sleep(1000);
        }
        catch(InterruptedException ex){
            Thread.currentThread().interrupt();
        }
        // once the sleep finishes, the text from the JButtons is removed.
        pickedcardbuttons[0].setText("");
        pickedcardbuttons[1].setText("");
        

    }
}

The program works exactly how I want it to, the only problem is that the program doesn't give enough time to actually display the text.

This is what happens: The buttons before they are clicked

After one button is clicked (ok so far)

After two buttons are clicked (this is what you see during the sleep), as you can see, the animation is cut halfway through

and then the buttons return to not having any text.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

By calling Thread.sleep on the Swing event thread, you are putting the entire GUI to sleep, meaning it cannot do any key actions of updating the GUI or interacting with the user until the sleep time is over. The solution is to never do this. If you need to have a time delay in a Swing GUI, there is a Swing tool created explicitly for this, a Swing Timer: Swing Timer Tutorial

The underlying mechanism is to give the timer a delay time in microseconds as its first constructor parameter, and give it a call back method as an ActionListener as its second parameter. Set it to non-repeating, and call .start() on it. The call-back should do the actions that you desire after the delay time has finished.

For example, something like:

public void oncardflipped(String card) {
    if (twocardspicked) {
        int delay = 1000;
        Timer timer = new Timer(delay, e -> {
            // the actionPerformed call-back code
            pickedcardbuttons[0].setText("");
            pickedcardbuttons[1].setText("");
        });
        timer.setRepeats(false);
        timer.start();
    }
}

Note that you should not use a java.util.Timer, the other main Java Timer class, since while this sort-of works, it is not Swing thread-safe.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...