如何停止崩溃JLabels

时间:2015-12-12 08:13:38

标签: java multithreading user-interface jlabel

我正在做一个小的GUI应用程序来模拟游泳比赛。我有一个单独的游泳池和记分牌的图形用户界面,游泳者被5个线程移动,当他们到达触摸板时,我编码在记分板上显示该时间。

问题是每当在记分板中显示标签的那些时间被更新时,游泳者突然移回到起始位置(不是刚刚消失并出现在起点处的连续运动)而不停留在触摸板附近。但如果标签没有更新,这是有效的。

这是GUI的图像。 enter image description here

这不是完整的代码,但这是代码段,负责游泳者的移动以及游泳者完成长度时更新时间标签。

private final Map<Swimmer, JLabel> mapLaneTime = new HashMap<>();

private void startTheGame(final String swimmingStyle) {

    final ArrayList<Swimmer> listSwimmer = 
                               new ArrayList<>  (mapSwimmers.keySet());

    for (int i = 0; i < mapSwimmers.size(); i++) {
        final Swimmer swmr = listSwimmer.get(i);

        // set up the intial position of the JLabel to the swimmer
        swmr.setCurrentPosition(mapSwimmers.get(swmr).getX());               
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    swmr.slowDown();
                    JLabel lblSwmr = mapSwimmers.get(swmr);
                    swmr.doSwimmingStyle(swimmingStyle);

                    int startPosition = swmr.getCurrentPosition();

                    while ((swmr.getCurrentPosition()
                            != swmr.getSwimLane().getLength()
                            + startPosition)) {

                        lblSwmr.setLocation(swmr.doLegMovements(),
                                lblSwmr.getY());

                        swmr.doHandMovements();
                        swmr.speedUp();
                    }
// time takes for the swimmer to touch the touch pad 
                    double time = swmr.touchTheTouchPad(swimmingEvent);


/** problem comes when the below line is present it is the way to set text 
 ** to the label if this is not here swimmers properly end the length
 ** without appearing at the starting position when ever they finish the 
 ** length 
 **/                   
                    mapLaneTime.get(swmr).setText(time + "");

                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                } finally {
                    swmr.giveUp();
                }
            }
        }).start();
    }
}

线程完全没有问题。不要在乎其他方法。其他实现没有任何问题。

对不起,我忘了提及swmr.giveUP()是释放锁的方法(Lock lock = new ReentrantLock())。锁定在Swimmer类中定义。游泳者课程中还有另一个线程来更新使用相同锁定的游泳者的位置

这是Swimmer类的完整代码,ScoreBoard类

Swimmer class(这是一个抽象类,有两个子类MaleSwimmer和FemaleSwimmer)

import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public abstract class Swimmer extends Person {

    private final String gender;            // gender of the Swimmer                               
    private final String costumeColor;       //color of the costume                                                        
    private final int personalBest;
    private volatile int currentPosition;
    private SwimLane swimLane;
    private final Lock lock;                // lock for the thread                                              
    private final Condition condition;

    protected Swimmer(String name, String gender, String costumeColor) {
        super(name);
        this.gender = gender;
        this.costumeColor = costumeColor;

        Random random = new Random();
        this.personalBest = random.nextInt(20) + 8;
        lock = new ReentrantLock();
        condition = lock.newCondition();
    }

    public SwimLane getSwimLane() {
        return this.swimLane;
    }

/**
 * @return the color of the swimming costume
 */
protected String getDressColor() {
    return this.costumeColor;
}

/**
 * perform hand movements
 */
protected void doHandMovements() {
    this.condition.signalAll();
}

/**
 * perform leg movements
 *
 * @return
 */
protected int doLegMovements() {
    return this.currentPosition;
}

/**
 * perform Butterfly stroke
 *
 * @param sleepTime
 */
protected abstract void doButterflyStroke(int sleepTime);

/**
 * perform Backstroke
 *
 * @param sleepTime
 */
protected abstract void doBackStroke(int sleepTime);

/**
 * perform Breaststroke
 *
 * @param sleepTime
 */
protected abstract void doBreastStroke(int sleepTime);

/**
 * perform Freestyle
 *
 * @param sleepTime
 */
protected abstract void doFreeStyle(int sleepTime);

public void doSwimmingStyle(String style) {
    switch (style) {

        case "Freestyle":
            doFreeStyle(personalBest);
            break;

        case "Backstroke":
            doBackStroke(personalBest);
            break;

        case "Butterfly Stroke":
            doButterflyStroke(personalBest);
            break;

        case "Breaststroke":
            doBreastStroke(personalBest);
            break;
    }
    this.swimLane.getTouchPad().startTimer();                               // start the timer when swimmer starts to swim
}

void updatePosition(int sleepTime, double factor) {
    final int swimTime = (int) (sleepTime * factor);

    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                lock.lock();                                                // lock the thread
                int endPosition = currentPosition + swimLane.getLength();   // length of the lane from staring to end

                while (currentPosition <= endPosition) {
                    currentPosition++;
                    Thread.sleep(swimTime);
                    condition.signal();
                    condition.await();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                lock.unlock();                                              // give up the lock from the thread
            }

        }
    }).start();
}

public int getPersonalBest() {
    return this.personalBest;
}

public void setCurrentPosition(int currentPosition) {
    this.currentPosition = currentPosition;
}

public int getCurrentPosition() {
    return this.currentPosition;
}

public void setSwimLane(SwimLane swimLane) {
    this.swimLane = swimLane;
}

/**
 * When swimmer finish the event swimmer should touch the touch pad. This
 * method achieve that task
 *
 * @param swimmingEvent
 * @return swimmer's finishing time
 */
public double touchTheTouchPad(SwimmingEvent swimmingEvent) {
    return this.swimLane.getTouchPad().notifyScoreBoard(this,      
    swimmingEvent);
}

public void slowDown() throws InterruptedException {
    this.lock.lock();
}

public void speedUp() throws InterruptedException {
    this.condition.awaitNanos(500);

}

public void giveUp() {
    this.lock.unlock();
}

}

class ScoreBoard

import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class ScoreBoard implements Serializable {

Queue<Double> time;
Queue<Swimmer> swimmers;
Map<Swimmer, Double> finalResults;

private int numberOfRows;
private final Lock lock;
private final Condition condition;

public ScoreBoard() {
    time = new LinkedList<>();
    swimmers = new LinkedList<>();
    finalResults = new LinkedHashMap<>();
    lock = new ReentrantLock();
    condition = lock.newCondition();
}

/**
 * This method will add swimmer and timeTaken to the list
 *
 * @param swimmer swimmer who completed the event
 * @param timeTaken time took for swimmer to complete the event
 */
public void updateList(Swimmer swimmer, double timeTaken) {

    time.add(timeTaken);
    swimmers.add(swimmer);

}

/**
 * This method will start the process of the Score Board
 */
public void powerUp() {
    new Thread(new Runnable() {
        @Override
        public void run() {

            try {
// swimmer will take more than 4s to complete a game
                Thread.sleep(4000);                                            
                lock.lock();                                                    
                while (swimmers.size() != numberOfRows) {                                      
// wait this thread untill this is awoken
                    Thread.sleep(100);
                }
                comapreTimes();
                condition.signal();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } finally {
                lock.unlock();
            }

        }

    }).start();
}

/**
 * This method will set the number of rows in Score Board
 *
 * @param numberOfRows number of rows that should be in Score Board
 */
public void setNumberOfRows(int numberOfRows) {
    this.numberOfRows = numberOfRows;
}

/**
 * This method will pass the lock to the thread inside the powerUp method
 */
public void lockTheScoreBoard() {
    this.lock.lock();
}

public void unlockTheScoreBoard() {
    this.lock.unlock();
}

public void awaitScoreBoard() throws InterruptedException {
    this.condition.await();
}

void comapreTimes() {
    for (Swimmer s : swimmers) {
        this.finalResults.put(s, time.poll());
        // need to do something more in here
    }
}

public Map<Swimmer, Double> getFinalResults() {
    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                lock.lock();
                condition.await();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }).start();
    return this.finalResults;
}

}

我也尝试使用SwingWorker线程更新JLabel,但是出现了同样的问题。

1 个答案:

答案 0 :(得分:0)

首先,swmr.giveUp();应该从最后移动到为InterruptedExcveption执行的部分。

为什么每个煨者都放弃了?只有宽松者应该。

检查是否会解决问题。也许情况就是这样。

你知道,我认为设置JLabel的文本没有问题,它只是强制重绘窗口,所以这就是为什么你看到所有的游泳者都在startnig,swmr.giveUp();重新开始他们的职位?

如果是这种情况,那就是为什么你在设置JLabel文本后在beginnig上看到所有这些,因为他们已经有了这个位置,但是如果你不重绘,你将看不到他们的新位置。< / p>