Java Swing и Thread спят

Я решил отвлечься от чтения книг по программированию чем-нибудь забавным, и наткнулся на загвоздку. Это моя первая свинг-программа, и я готов ее завершить!

Проблема: я явно не понимаю, как потоки работают с Swing. Я пишу графический интерфейс для игры в блэкджек, и сначала я выполнил все функции, например. рисование новой карты на экране, когда игрок набирает карты, отображение карты дилера после того, как игрок решает остаться, и т. д. Все это работает.

Когда я добавил в логику проверку перебора пользователя при ударе или того, кто выиграет, когда пользователь решит остаться, игра мгновенно переходит к экрану выигрыша/проигрыша перед тем, как вытянуть либо: карту, которую пользователь получил, вызвавшую перебор, либо ; карты, которые дилер вытянул при сдаче (если они есть).

Я пытался вставить Thread.sleep в разные места, но безрезультатно. Программа засыпала перед розыгрышем карты, а затем мгновенно завершалась, как указано выше (даже если она была логически размещена после вызова розыгрыша и перед вызовом вычисления победителя).

также я пытался следовать парадигме MVC здесь, просто к вашему сведению.

P.S. моя программа работает в одном потоке, я явно не создаю экземпляр другого, но я смутно помню, что читал, что 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, может быть поэтому сон влияет на поток графического интерфейса, а не рисует карты, а затем спит. Бьюсь об заклад, это все. Но я собираюсь поужинать, надеюсь, кто-нибудь поумнее меня протянет руку помощи! заранее спасибо

П.П.С. если есть какие-то опечатки (я не думаю, что есть) просто знайте, что все компилируется и работает! И никаких предупреждений, если это поможет


person Trés DuBiel    schedule 11.06.2015    source источник


Ответы (2)


Swing действительно является однопоточной библиотекой, как и большинство пользовательских интерфейсов. Есть также много оптимизаций, чтобы заставить его работать быстрее. Дело в том, что большинство картин кэшируются и отображаются вместе. Даже если бы это было не так, вы бы полагались на скорость системы, что не очень хорошая идея.

Если вам нужно отложенное действие, вам нужно использовать таймер свинга (не путать с другим классом таймера). У этого класса есть прослушиватель действий, который срабатывает по истечении таймера. В вашем случае вы обнаружите условие победы/проигрыша, запустите таймер (например, срабатывает через 2 секунды) и продолжите розыгрыш как обычно.

person Michael Bar-Sinai    schedule 11.06.2015

Это слишком длинно для меня, чтобы прочитать и понять... Но я предполагаю, что ваша проблема в том, что вы обрабатываете все в файле Event Dispatching Thread.

Когда вы рисуете что-то в графическом интерфейсе, а затем выполняете дополнительную обработку, рисование фактически отразится на графическом интерфейсе только тогда, когда весь поток завершит обработку. Вот почему вы не видите свой рисунок перед методом Thread.sleep.

Вместо этого вы должны использовать SwingWorker для разделения обработки и обновления графического интерфейса на разные потоки.

Посмотрите на это https://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html

person Codebender    schedule 11.06.2015
comment
В ответе нет ничего плохого, но, поскольку кажется, что ОП хочет вставить задержку между состояниями хита и конца игры, Swing Timer может быть лучшим решением ... просто говорю;) - person MadProgrammer; 11.06.2015