簡體   English   中英

Java, Swing, wait(), notify() 有問題

[英]Problem with Java, Swing, wait(), notify()

我是 Java 的新手,我嘗試制作一個簡單的回合制游戲來獲得一些經驗。 我遇到了一個我自己無法解決的問題,盡管我做了很多谷歌研究......可能我無法解決它是因為我對它的理解不夠深入。

問題是我不知道如何為玩家制作輪流程序。 我的意思是我想讓幾個 Jbutton 處於活動狀態,直到按下其中一個按鈕,然后對另一個玩家執行相同的操作。 由於程序非常復雜,我刪除了 80% 與問題無關的代碼,並將它的 rest 貼在下面。

代碼分為類,由於問題的復雜性(剩余 80% 的代碼),我想保持這種方式。 為了更好地了解程序的作用,我制作了每次激活時都會改變顏色的按鈕。 不幸的是,程序在調用 notify() 方法后立即停止工作。

有人可以幫忙嗎? 先感謝您。

測試員:

package grafika;

import javax.swing.SwingUtilities;


public class OknoTester {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                Okno main = new Okno();
            }
            
            // ctr + spacja - podpowiedzi w Eclipsie
        });

    }

}

主 class

 package grafika;

import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JSplitPane;


public class Okno {
    private JFrame frame;
            
    public Okno()
    {
        initialize();
    }

    
    private void initialize()
    {
        // NEW WINDOW
        frame = new JFrame();
        frame.setTitle("Gra w statki");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(new Dimension(600,100));
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setVisible(true);

        
        // DIVIDE WINDOW
        JSplitPane splitPaneH = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT );
        frame.getContentPane().add(splitPaneH);
        splitPaneH.setDividerSize(0);
        
        
        // INITIALIZATION OF SITES
        Komputer left = new Komputer();
        Komputer right = new Komputer();
        

        // SHOWPANELS
        splitPaneH.setLeftComponent(left.Pokaz());
        splitPaneH.setRightComponent(right.Pokaz());
        splitPaneH.setResizeWeight(0.5);
        splitPaneH.setEnabled(false);
        
        // ALLOW TO USE ONE OF LEFT OR RIGHT SET OF BUTTONS
        while(true)
        {
        left.CzytajRuch();
        right.CzytajRuch();
        }
        
        
    }

}

Class 帶按鍵

package grafika;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;

public class Komputer implements ActionListener{

    private JButton b1 = new JButton("1");
    private JButton b2 = new JButton("2");
    private JPanel panel = new JPanel();
    private Boolean aktywny = false;
    
    
    public void CzytajRuch()
    {
        aktywny = true;
        try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    }

    public JPanel Pokaz()
    {
        return panel;
    }
    

    public Komputer() {
        
        GridLayout gl = new GridLayout(1,2);
        panel.setLayout(gl);
        panel.add(b1);
        b1.addActionListener(this);
        b2.addActionListener(this);
        panel.add(b2);

    }


    public void actionPerformed(ActionEvent ae) {
        if(aktywny == true)
        {
        JButton pb = (JButton) ae.getSource();
        if (pb == b1)
            b1.setBackground(new Color((int)(Math.random() * 0x1000000)));
        if (pb == b2)
            b2.setBackground(new Color((int)(Math.random() * 0x1000000)));
        aktywny = false;
        notify();
        }
    }
    

}
 

感謝您花時間閱讀本文。 我會感謝任何幫助。

Swing 是單線程的。 這意味着您不能在事件調度線程上執行長時間運行或阻塞操作。

如果您嘗試在 EDT 的上下文中使用wait ,它不僅會阻止 EDT 並阻止處理任何進一步的更新或事件,您將永遠無法使用notify (從 EDT 中)喚醒它。

waitnotify旨在從不同的線程上下文中使用(而不是在同一線程上下文中)

有關更多詳細信息,請參閱Swing中的並發。

您需要做的是監視某種“令牌”。 只有持有“令牌”的玩家才能做任何事情。

您可以將其提煉為一個簡單的標志,由某種“控制器”維護。 每次玩家做某事時,controller 都會檢查玩家當前是否處於活動狀態,處理該動作並將活動玩家切換到其他玩家,例如......

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public final class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    enum Player {
        LEFT, RIGHT;
    }

    public class MainPane extends JPanel {

        private Player activePlayer = Player.LEFT;
        private ControlPane leftControlPane;
        private ControlPane rightControlPane;

        private JTextArea logTextArea;

        public MainPane() {
            ControlPane.Observer observer = new ControlPane.Observer() {
                @Override
                public void playerDidPerformAction(ControlPane source, Player player) {
                    if (player != getActivePlayer()) {
                        logTextArea.append((player == Player.LEFT ? "Player 1" : "Player 2") + " tried to perform an illegal action\n");
                    } else {

                        logTextArea.append((player == Player.LEFT ? "Player 1" : "Player 2") + " did perform action\n");
                        switch (player) {
                            case LEFT:
                                activePlayer = Player.RIGHT;
                                break;
                            case RIGHT:
                                activePlayer = Player.LEFT;
                                break;
                        }
                        activePlayerDidChange();
                    }
                }
            };
            leftControlPane = new ControlPane(Player.LEFT, observer);
            rightControlPane = new ControlPane(Player.RIGHT, observer);

            logTextArea = new JTextArea(20, 20);

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();

            gbc.gridheight = GridBagConstraints.REMAINDER;
            gbc.weightx = 1;
            gbc.weighty = 1;
            gbc.fill = gbc.BOTH;
            add(leftControlPane, gbc);

            gbc.weightx = 0;
            gbc.weighty = 0;
            add(new JScrollPane(logTextArea), gbc);

            gbc.weightx = 1;
            gbc.weighty = 1;
            add(rightControlPane, gbc);

            activePlayerDidChange();
        }

        public Player getActivePlayer() {
            return activePlayer;
        }

        protected void activePlayerDidChange() {
            switch (getActivePlayer()) {
                case LEFT:
                    rightControlPane.setActive(false);
                    leftControlPane.setActive(true);
                    break;
                case RIGHT:
                    rightControlPane.setActive(true);
                    leftControlPane.setActive(false);
                    break;
            }
        }

    }

    public class ControlPane extends JPanel {
        public interface Observer {
            public void playerDidPerformAction(ControlPane source, Player player);
        }

        private Player player;
        private JButton actionButton;
        private Observer observer;

        public ControlPane(Player player, Observer observer) {
            this.player = player;
            this.observer = observer;
            actionButton = new JButton("Do stuff!");

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.insets = new Insets(8, 8, 8, 8);

            add(new JLabel(player == Player.LEFT ? "Player 1" : "Player 2"), gbc);

            gbc.weightx = 1;
            gbc.weighty = 1;
            add(actionButton, gbc);

            actionButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    observer.playerDidPerformAction(ControlPane.this, player);
                }
            });
        }

        public void setActive(boolean active) {
            actionButton.setEnabled(active);
        }

    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM