【问题标题】:Java Swing and Thread sleepingJava Swing 和线程休眠
【发布时间】:2015-06-11 01:54:45
【问题描述】:

我决定在阅读编程书籍后做一些有趣的事情,但我遇到了障碍。这是我的第一个摇摆计划,准备结束!

问题:我显然不明白线程如何与 Swing 一起工作。我正在为二十一点游戏编写 GUI,我首先完成了所有功能,例如当玩家击中时在屏幕上绘制一张新牌,在玩家决定留下后显示庄家击中,等等。这一切都有效。

当我在逻辑中添加了检查用户击球时是否失败,或者当用户决定留下时谁获胜时,游戏会在抽奖之前立即进入赢/输屏幕:用户获得的牌导致破产,或;庄家打牌时抽到的牌(如果有的话)。

我尝试在各个地方插入 Thread.sleep,但无济于事。程序会在抽牌之前休眠,然后像上面一样立即结束(即使它在逻辑上被放置在调用抽牌之后,并且在调用计算获胜者之前)。

我也尝试在这里遵循 MVC 范例,仅供参考。

附:我的程序在一个线程上运行,我没有显式地实例化另一个,但我依稀记得读过 Swing 为图形内容生成了它自己的线程

抱歉,介绍太长了!这是一些代码:

Model类的相关方法

    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 线程,而不是绘制卡片然后睡眠。我敢打赌就是这样。但是我要去吃晚饭了,希望比我聪明的人能伸出援手!提前致谢

附言如果有任何错别字(我不认为有),只要知道它都可以编译和工作!并且没有警告,如果有帮助的话

【问题讨论】:

标签: java multithreading swing thread-sleep


【解决方案1】:

Swing 确实是一个单线程库,就像大多数 UI 一样。还有许多优化可以使其快速运行。举个例子——大多数画作都被缓存起来并一起展示。即使不是这种情况,您也会依赖系统的速度,这不是一个好主意。

如果您想要延迟操作,您需要use swing's timer(不要与其他计时器类混淆)。该类有一个动作监听器,当计时器到期时会关闭。在您的情况下,您将检测获胜/失败条件,启动计时器(例如在 2 秒内触发)并照常继续绘图。

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • 每个人的回答都没有问题,但由于 OP 似乎想要在“命中”和“结束游戏”状态之间插入延迟,所以 Swing Timer“可能”是一个更好的解决方案......只是说;)
    猜你喜欢
    • 2011-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-01
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    相关资源
    最近更新 更多