Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
332 views
in Technique[技术] by (71.8m points)

swing - Java Button pausing graphical updates

So I have a class where I have to make a program to make Simon. I know the way I'm doing it is not necessarily the best way, However, he had some obscure requirements so that is why I'm doing it this way.

My program is close to finished, but I have one MAJOR issue. When I press the reset button I call a method called reset which in turn sets the computer to play their first move.

During this, there are graphical updates.

When I call the reset method by itself it works as expected When I press the reset button it wates to do all graphical updates until after it is complete. Is there a way to have the method run after the button has ben pressed?

My Main program

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) {
    }
}

The ScoreBoard 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;
    }
}

The 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);
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is the first culprite...

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) {}
    }
}

This is been called from within the content of the Event Dispatching Thread, which is preventing it from processing any new updates or updating the UI.

Have a look at Concurrency in Swing for more details and consider using a Swing Timer instead, see How to use Swing Timers for more details

pane.update(pane.getGraphics()); ranks very, very highly among some of the worst things you could ever do in Swing (Thread.sleep is up there with it).

Take a look at Painting in AWT and Swing and Performing Custom Painting to understand how painting works in Swing

Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify

You might like to have a read through Code Conventions for the Java TM Programming Language, it will make it easier for people to read your code and for you to read others

For example...

So, this example is really basic. It has three buttons...

  • The "wrong way", which is basically what you're doing
  • The "timer way", which uses a Swing Timer
  • The "worker way", which uses a SwingWorker

In your case, I still think a Swing Timer is the best choice, as it's possible for a SwingWorker to get backed up with updates, spitting them all out at once, which defeats the purpose of why you might want to use it.

The Sequence

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();
        }

    }

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...