Java Swing和线程休眠

时间:2015-06-11 01:54:45

标签: java multithreading swing thread-sleep

我决定在阅读编程书籍时打破一些有趣的事情,我遇到了麻烦。这是我的第一个挥杆计划,我准备把它包起来!

问题:我显然不了解线程如何与Swing一起使用。我正在为黑杰克游戏编写GUI,我首先完成了所有功能,例如当玩家击中时,在屏幕上绘制一张新牌,在玩家决定留下之后显示经销商点击等等。这一切都有效。

当我在逻辑中加入以检查用户在击球时是否破损,或者在用户决定留下时获胜时,游戏会立即进入赢/输屏幕,然后再绘制:用户获得的牌导致了胸围,或;经销商在击中时(如果有的话)的牌。

我尝试在各个地方插入Thread.sleep,但无济于事。程序将在绘制卡片之前休眠,然后如上所述立即结束(即使它在绘制调用之后逻辑上放置,并且在调用计算胜利者之前)。

我也试图在这里遵循MVC范式,只是fyi。

P.S。我的程序在一个线程上运行,我没有明确地实例化另一个线程,但我依旧记得读到Swing产生了它自己的图形内容线程

很抱歉这个长篇介绍!这是一些代码:

模特班'相关方法

    void hit() {
    //run when button is clicked
    player.hand.add(deck.deck.get(0));
    deck.deck.remove(0);
}

boolean isBust() {
    if (player.getScore() > 21)
        return true;

    return false;

}

void dealerHit() {
    while (dealer.getScore() < 17) { //could implement soft 17 rules for more difficulty
        dealer.hand.add(deck.deck.get(0));

        setChanged();
        notifyObservers();
        deck.deck.remove(0);


        //Here was one attempt
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

boolean isWin() {

    //and another
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    if ((player.getScore() > dealer.getScore() && player.getScore() <= 21) || dealer.getScore() > 21)
        return true;

    return false;
}

void stay() {
    dealerHit();
    isWin();
}

查看课程

void addHitListener(ActionListener HitListener) {
    hit.addActionListener(HitListener);
}

void addStartListener(ActionListener StartListener) {
    start.addActionListener(StartListener);
}

void addStayListener(ActionListener StayListener) {
    stay.addActionListener(StayListener);
}

void display() {
    JFrame myFrame = new JFrame("BlackJack");
    myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    myFrame.setContentPane(this);
    myFrame.setPreferredSize(new Dimension(700,550));

    myFrame.pack();
    myFrame.setVisible(true);
}

void addCards(Player p, Dealer d) {
    topPanel.remove(start);

    pcardPanel.add(playerlabel);
    dcardPanel.add(dealerlabel);        

    for (Card c : p.hand) {
        ImageIcon cc = new ImageIcon(c.img);
        JLabel cC = new JLabel(cc);

        //cC.setAlignmentX(alignmentX); use to get X alignment of card 1 & 2 for splits
        //cC.setAlignmentY(alignmentY); same for Y, then increment by .3f

        pcardPanel.add(cC);


    }

    for (Card c : d.hand)
        dcardPanel.add(new JLabel(new ImageIcon(c.img))); 

    topPanel.add(new JLabel("Options: "));
    topPanel.add(hit);                              
    topPanel.add(stay);                             

    validate();
    repaint();
}

void endGame(boolean isWin) {

    //I think I tried here, too

    removeAll();
    setBackground(new Color(0, 122, 0));

    if (isWin == true)
        add(new JLabel("You won!"));
    else
        add(new JLabel("You Lost"));

    validate();
    repaint();
}

public void hitPlayer(Player p) {
    JLabel hits = new JLabel(new ImageIcon(p.hand.get(p.hand.size()-1).img));
    //hits.setAlignmentY(alignmentY);

    pcardPanel.add(hits);

    validate();
    repaint();
}

public void hitDealer(Dealer d) {
    dcardPanel.add(new JLabel(new ImageIcon(d.hand.get(d.hand.size()-1).img)));
    validate();
    repaint();
}

控制器类:

public class Controller implements Observer {

BlackJack game;
Table t;

Controller(BlackJack game, Table t) {
    this.game = game;
    this.t = t;

    this.game.addObserver(this);
    this.t.addHitListener(new HitListener());
    this.t.addStartListener(new StartListener());
    this.t.addStayListener(new StayListener());

}

public void go() {
    t.display();
}

public void update(Observable obj, Object observed) {
    t.hitDealer(game.getDealer());
}

class HitListener implements ActionListener {

    public void actionPerformed(ActionEvent e) {

        game.hit();

        t.hitPlayer(game.getPlayer());

        if (game.isBust() == true)
            t.endGame(false);

    }
}

class StartListener implements ActionListener {

    public void actionPerformed(ActionEvent e) {
        t.addCards(game.getPlayer(), game.getDealer());
    }
}

class StayListener implements ActionListener {

    public void actionPerformed(ActionEvent e) {
        game.stay();
        //doStay();

        if (game.isWin() == true)
            t.endGame(true);
        else
            t.endGame(false);
    }
}

我只是想了一下,因为我在actionPerformed方法中这样做,这可能就是为什么睡眠似乎会影响GUI线程,而不是绘制卡然后睡觉。我打赌就是这样。但是我要去吃晚餐,希望比我聪明的人可以伸出援助之手!提前致谢

P.P.S。如果有任何错别字(我不认为有)只是知道这一切都编译和工作!没有警告,如果有帮助

2 个答案:

答案 0 :(得分:3)

Swing确实是一个单线程库,就像大多数UI一样。还有许多优化可以使其快速运行。一个很好的例子 - 大多数画作都被缓存并一起显示。即使情况并非如此,您仍然依赖于系统的速度,这不是一个好主意。

如果您想要延迟操作,则需要use swing's timer(不要与其他计时器类混淆)。该类有一个动作监听器,在计时器到期时关闭。在您的情况下,您可以检测到胜利/萧条状态,启动计时器(例如在2秒内开火)并像往常一样继续绘图。

答案 1 :(得分:1)

这对我来说有点太长了以便阅读和理解......但我猜您的问题是因为您正在处理Event Dispatching Thread中的所有内容。

当您在GUI上绘制某些内容然后进行更多处理时,只有当整个线程完成处理时,绘制才会实际反映在GUI上。这就是为什么你没有在Thread.sleep方法之前看到你的绘图。

相反,您应该使用SwingWorker将处理和GUI更新拆分为不同的线程。

看看这个https://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html