Java 按钮暂停图形更新

Java Button pausing graphical updates

所以我有一个class,我必须在其中制作一个程序来制作西蒙。 我知道我这样做的方式不一定是最好的方式,但是,他有一些模糊的要求,所以这就是我这样做的原因。

我的程序即将完成,但我有一个主要问题。 当我按下重置按钮时,我调用了一个名为重置的方法,该方法又将计算机设置为开始他们的第一步。

在此期间,有图形更新。

当我自己调用重置方法时,它按预期工作 当我按下重置按钮时,它会在完成之前执行所有图形更新。 有没有办法在按下按钮后使用 运行 方法?

我的主程序

package game;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import components.*;


@SuppressWarnings("serial")
public class Simonish extends JFrame implements ActionListener, MouseListener {


    private Color[][] ColorSwatch = {{Color.RED,Color.PINK},{Color.GREEN,Color.YELLOW}};
    private int width = 2;
    private int height = 2;
    private int panSize = 200;
    private SPane[][] panBoard;
    private int[] Sequence;
    private int CurrentSequenceLeingth = 0;
    private int SequenceLeingth = 10000;
    private Random r = new Random();
    boolean LastButtonClicked = false;
    private int LastButtonPressed = 0;
    private int sequencePart = 0;
    private boolean turn = false; //f=computer t=player
    Container pane;
    JPanel boardPanel;
    ScoreBoard scorePanel;
    private Simonish(){

        scorePanel = new ScoreBoard(0,width,panSize);
        scorePanel.getResetBtn().addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                    resetGame();
            }
        });
        this.setTitle("Simonish");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        pane = this.getContentPane();
        pane.setLayout(null);
        resetGame();
    }

    private void play(){
        if(!turn)
            ComputerTurn();
        else
            PlayerTurn();
    }

    private void ComputerTurn(){
        CurrentSequenceLeingth++;
        scorePanel.AddScore(1);
        PlaySequenc();
        turn = true;
    }

    private void PlayerTurn(){
            if((LastButtonPressed == Sequence[sequencePart]))
            {
                sequencePart++;
                LastButtonClicked = false;
            }else
            {
                loose();
                return;
            }
            if(sequencePart >= CurrentSequenceLeingth)
            {
                sequencePart = 0;
                turn = false;
                play();
            }
    }

    private void loose(){
        System.out.println("you loose");
        resetGame();
    }

    private void PlaySequenc(){
        for(int i = 0 ; i < CurrentSequenceLeingth ; i++)
        {
            panBoard[Sequence[i]/2][Sequence[i]%2].pressPane();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {}
        }
    }

    private void resetGame() {
        pane.removeAll();
        pane.setPreferredSize(new Dimension(width*panSize, (height) * panSize + 75));
        pane.add(scorePanel);
        initPanes();
        LastButtonClicked = false;
        LastButtonPressed = 0;
        initBtns();
        turn = false;
        CurrentSequenceLeingth = 3;
        Sequence = new int[SequenceLeingth];
        initSeq();
        pane.update(pane.getGraphics());        
        this.pack();
        this.setLocationRelativeTo(null);   
        this.setVisible(true);

        play();

    }
    private void initSeq() {

        for(int i = 0 ; i < SequenceLeingth ; i++)
        {
            Sequence[i] = r.nextInt(4);

        }

    }

    private void initBtns() {
        this.panBoard = new SPane[width][height];

        for(int w = 0; w < width; w++) {
            for(int h = 0; h < height; h++) {
                panBoard[w][h] = new SPane(w, h, panSize,ColorSwatch[w][h]);
                panBoard[w][h].addMouseListener(this);
                pane.add(panBoard[w][h]);
                pane.addMouseListener(this);
            }
        }
    }
    public static void main(String[] args){
        new Simonish();
    }


    private void initPanes() {
        //TODO
    }


    @Override
    public void actionPerformed(ActionEvent e) {
    }

    @Override
    public void mouseClicked(MouseEvent e) {    
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }
}

计分板Class

package components;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.Timer;

@SuppressWarnings({ "serial", "unused" })
public class ScoreBoard extends JPanel {
    private int score;
    private JLabel SimonNumberLabel;
    private JLabel timerLabel;
    private JButton resetBtn;


    public ScoreBoard(int bombsCnt,int w,int w2) {
        score = bombsCnt;
        SimonNumberLabel = new JLabel("Sequence Leingth: " + Integer.toString(bombsCnt), SwingConstants.CENTER);
        resetBtn = new JButton("reset");

        setBounds(0, 0, w*w2, 3*25);

        this.setLayout(new GridLayout(1,3));

        add(SimonNumberLabel);
        add(resetBtn);
    }

    public void AddScore(int update) {
        score += update;
        SimonNumberLabel.setText("Sequence Leingth: " + Integer.toString(score));
    }


    public JButton getResetBtn() {
        return resetBtn;
    }
}

SPane Class

package components;

import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;

@SuppressWarnings("serial")
public class SPane extends JPanel{

    Color C;
    Color DC;
    int x;
    int y;
    public SPane(int x, int y, int size, Color colorSwatch) {
        this();
        this.x = x;
        this.y = y;
        this.setLayout(new GridLayout(x+1,y+1));
        this.setBounds(x*size, y*size+75, size, size);
        C = colorSwatch;
        DC = C;
        DC = DC.darker();
        this.setBackground(DC);
        this.setVisible(true);
    }


    public SPane() {
        this.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
    }

    public void resetSPane() {
        // TODO Auto-generated method stub

    }

    public void pressPane()
    {
        this.setBackground(C);
        System.out.println("dsfdsfsdfsdf");
        try{
            Thread.sleep(1000);
        }catch (Exception e) {} 
        this.setBackground(DC);
    }

    public void clicked() {
        this.setBackground(Color.GREEN);
    }
}

这是第一个罪魁祸首...

private void PlaySequenc(){
    for(int i = 0 ; i < CurrentSequenceLeingth ; i++)
    {
        panBoard[Sequence[i]/2][Sequence[i]%2].pressPane();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {}
    }
}

这是从事件调度线程的内容中调用的,这会阻止它处理任何新的更新或更新 UI。

查看 Concurrency in Swing for more details and consider using a Swing Timer instead, see How to use Swing Timers 了解更多详情

pane.update(pane.getGraphics()); 在您可能在 Swing 中做过的一些最糟糕的事情中排名非常非常高(Thread.sleep 排名靠前)。

看看 Painting in AWT and Swing and Performing Custom Painting 以了解在 Swing 中绘画是如何工作的

避免使用 null 布局,像素完美布局是现代 ui 设计中的一种错觉。影响组件个体大小的因素太多,none 是您可以控制的。 Swing 旨在与核心的布局管理器一起工作,丢弃这些将导致无穷无尽的问题和问题,您将花费越来越多的时间来尝试纠正

您可能希望通读 Code Conventions for the Java TM Programming Language,这将使人们更容易阅读您的代码,您也可以更轻松地阅读其他人

例如...

所以,这个例子真的很基础。它有三个按钮...

  • "wrong way",这基本上就是您正在做的事情
  • 使用Swing的"timer way"Timer
  • "worker way",它使用了SwingWorker

在你的情况下,我仍然认为 Swing Timer 是最好的选择,因为 SwingWorker 可以通过更新进行备份,一次将它们全部吐出,这会失败您可能想要使用它的目的。

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Sequence {

    public static void main(String[] args) {
        new Sequence();
    }

    public Sequence() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private List<SequencePane> panels = new ArrayList<>(4);

        private Timer timer;
        private int sequenceIndex;

        public TestPane() {
            setLayout(new BorderLayout());
            Color colors[] = new Color[]{Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW};
            for (int index = 0; index < 4; index++) {
                panels.add(new SequencePane(colors[index]));
            }
            JPanel content = new JPanel(new GridLayout(2, 2));
            for (SequencePane pane : panels) {
                content.add(pane);
            }

            add(content);

            JButton wrong = new JButton("The wrong way");
            JButton timerButton = new JButton("The Timer way");
            JButton workerButton = new JButton("The Worker way");

            JPanel actions = new JPanel();
            actions.add(wrong);
            actions.add(timerButton);
            actions.add(workerButton);

            add(actions, BorderLayout.SOUTH);

            wrong.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Collections.shuffle(panels);
                    for (SequencePane pane : panels) {
                        try {
                            pane.setHighlighted(true);
                            Thread.sleep(250);
                            pane.setHighlighted(false);
                        } catch (InterruptedException ex) {
                        }
                    }
                }
            });

            timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (sequenceIndex > 0) {
                        panels.get(sequenceIndex - 1).setHighlighted(false);
                    }

                    if (sequenceIndex < panels.size()) {
                        panels.get(sequenceIndex).setHighlighted(true);
                        sequenceIndex++;
                    } else {
                        timer.stop();
                        // All done, call some "play" method to begin playing
                    }
                }
            });

            timerButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    timer.stop();
                    Collections.shuffle(panels);
                    sequenceIndex = 0;
                    timer.start();
                }
            });

            SwingWorker worker = new SwingWorker<Object, SequenceState>() {
                @Override
                protected Object doInBackground() throws Exception {
                    for (SequencePane pane : panels) {
                        publish(new SequenceState(pane, true));
                        Thread.sleep(100);
                        publish(new SequenceState(pane, false));
                    }
                    return null;
                }

                @Override
                protected void process(List<SequenceState> chunks) {
                    SequenceState state = chunks.get(chunks.size() - 1);
                    state.applyState();
                }

                @Override
                protected void done() {
                    // Back in the EDT, call what ever "play" method you need
                }

            };

            workerButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Collections.shuffle(panels);
                    SequenceWorker worker = new SequenceWorker();
                    worker.execute();
                }
            });

        }

        public class SequenceWorker extends SwingWorker<Object, SequenceState> {
                @Override
                protected Object doInBackground() throws Exception {
                    for (SequencePane pane : panels) {
                        publish(new SequenceState(pane, true));
                        Thread.sleep(250);
                        publish(new SequenceState(pane, false));
                    }
                    return null;
                }

                @Override
                protected void process(List<SequenceState> chunks) {
                    for (SequenceState state : chunks) {
                        state.applyState();
                    }
                }

                @Override
                protected void done() {
                    // Back in the EDT, call what ever "play" method you need
                }

            }

        public class SequenceState {

            private SequencePane sequencePane;
            private boolean highlighted;

            public SequenceState(SequencePane sequencePane, boolean highlighted) {
                this.sequencePane = sequencePane;
                this.highlighted = highlighted;
            }

            public SequencePane getSequencePane() {
                return sequencePane;
            }

            public boolean isHighlighted() {
                return highlighted;
            }

            public void applyState() {
                getSequencePane().setHighlighted(isHighlighted());
            }
        }

    }

    public class SequencePane extends JPanel {

        private boolean highlighted;

        public SequencePane(Color color) {
            setOpaque(false);
            setBackground(color);
        }

        public void setHighlighted(boolean highlighted) {
            this.highlighted = highlighted;
            repaint();
        }

        public boolean isHighlighted() {
            return highlighted;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(50, 50);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (!isHighlighted()) {
                g2d.setComposite(AlphaComposite.SrcOver.derive(0.25f));
            }
            g2d.setColor(getBackground());
            g2d.fillRect(0, 0, getWidth(), getHeight());
            g2d.dispose();
        }

    }

}