开发者

Getting JButtons to refresh labels during each cycle of loop

Ok so the goal of this program is to get the red x from one side of the "bridge" (made up of 7 JButtons) to the otherside of the window. I'm trying to get the buttons to refresh the text displayed on them after each cycle of the loop so that it looks like the red x crosses the bridge. Any help on to why it isn't refreshing based on the following code would be incredible.

Thanks for your time

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class GeorgeBridge extends JApplet implements ActionListener{
  // Create a frame to hold the contents of application
  JFrame frame = new JFrame ("George's Big Bridge Crossing");

  // Panel to hold the bridge
  JPanel bridgePanel = new JPanel(new GridLayout(1,7));

  /* The following JLabels are used for spacing of the panels in the frame to make the window look more like a bridge 
   * crossing over a river
   */
  JLabel northLabel = new JLabel(" ");
  JLabel eastLabel = new JLabel("         ");
  JLabel westLabel = new JLabel("         ");
  // Asks the user whether or not they would like George to cross the bridge
  JLabel southLabel = new JLabel("Would you like George to cross the Bridge?"); 

  // George is represented by a red X
  String george = "X";

  // An array of 7 JButtons to act as the bridge
  JButton [] bridge = new JButton [7];

  int spot;





  public void init() { 
    bridge[0] = new JButton ("");
    bridge[1] = new JButton ("");
    bridge[2] = new JButton ("");
    bridge[3] = new JButton ("");
    bridge[4] = new JButton ("");
    bridge[5] = new JButton ("");
    bridge[6] = new JButton ("");



    // Set the program to exit when the JFrame is closed
    frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    //set a border layout manager to the frame
    frame.setLayout(new BorderLayout());

    // Background set to look like water under the bridge
    bridgePanel.setBackground (new Color(0,191,246));

    // Panel to make it look like the bridge is crossing a river
    JPanel northPanel = new JPanel();
    northPanel.setBackground (new Color (0,191,246));

    // Panel to make it look like the bridge is crossing a river
    JPanel eastPanel = new JPanel();
    eastPanel.setBackground (new Color (0,184,48));

    // Panel to make it look like the bridge is crossing a river
    JPanel southPanel = new JPanel();
    southPanel.setBackground (new Color (0,191,246));

    // Panel to make it look like the bridge is crossing a river
    JPanel westPanel = new JPanel();
    westPanel.setBackground (new Color(0,184,48));

    // JButton to let the user choose when George crosses the bridge
    JButton cross = new JButton("Make George cross!");
    cross.setActionCommand("cross");
    cross.addActionListener(this);   

    // Starts George standing on the West Bank
    westLabel.setText(george);
    // Makes George red so he is more visible
    westLabel.setForeground(new Color(255,0,0));
    // Makes George size 24 font so he is more visible
    westLabel.setFont(westPanel.getFont().deriveFont(24.0f));

    // Initiates the first button that represents a foot of the bridge
//    bridge[0] = new JButton ("");
    bridge[0].setBackground(new Color(143,66,19));// Set the background to a brown to make the bridge look like a wooden bridge
    bridge[0].setForeground(new Color(255,0,0));// Set the colour of George to red
    bridge[0].setFont(bridge[0].getFont().deriveFont(24.0f));// Set the font for George to 24

    // Initiates the second button that represents a foot of the bridge
//    bridge[1] = new JButton ("");
    bridge[1].setBackground(new Color(143,66,19));// Set the background to a brown to make the bridge look like a wooden bridge
    bridge[1].setForeground(new Color(255,0,0));// Set the colour of George to red
    bridge[1].setFont(bridge[0].getFont().deriveFont(24.0f));// Set the font for George to 24

    // Initiates the third button that represents a foot of the bridge
//    bridge[2] = new JButton ("");
    bridge[2].setBackground(new Color(143,66,19));// Set the background to a brown to make the bridge look like a wooden bridge
    bridge[2].setForeground(new Color(255,0,0));// Set the colour of George to red
    bridge[2].setFont(bridge[0].getFont().deriveFont(24.0f));// Set the font for George to 24

    // Initiates the fourth button that represents a foot of the bridge
//    bridge[3] = new JButton ("");
    bridge[3].setBackground(new Color(143,66,19));// Set the background to a brown to make the bridge look like a wooden bridge
    bridge[3].setForeground(new Color(255,0,0));// Set the colour of George to red
    bridge[3].setFont(bridge[0].getFont().deriveFont(24.0f));// Set the font for George to 24

    // Initiates the fifth button that represents a foot of the bridge
//    bridge[4] = new JButton ("");
    bridge[4].setBackground(new Color(143,66,19));// Set the background to a brown to make the bridge look like a wooden bridge
    bridge[4].setForeground(new Color(255,0,0));// Set the colour of George to red
    bridge[4].setFont(bridge[0].getFont().deriveFont(24.0f));// Set the font for George to 24

    // Initiates the sixth button that represents a foot of the bridge
//    bridge[5] = new JButton ("");
    bridge[5].setBackground(new Color(143,66,19));// Set the background to a brown to make the bridge look like a wooden bridge
    bridge[5].setForeground(new Color(255,0,0));// Set the colour of George to red
    bridge[5].setFont(bridge[0].getFont().deri开发者_如何转开发veFont(24.0f));// Set the font for George to 24

    // Initiates the seventh button that represents a foot of the bridge
//    bridge[6] = new JButton ("");
    bridge[6].setBackground(new Color(143,66,19));// Set the background to a brown to make the bridge look like a wooden bridge
    bridge[6].setForeground(new Color(255,0,0));// Set the colour of George to red
    bridge[6].setFont(bridge[0].getFont().deriveFont(24.0f));// Set the font for George to 24

    // Add the bridge buttons to the bridge panel
    bridgePanel.add(bridge[0]);
    bridgePanel.add(bridge[1]);
    bridgePanel.add(bridge[2]);
    bridgePanel.add(bridge[3]);
    bridgePanel.add(bridge[4]);
    bridgePanel.add(bridge[5]);
    bridgePanel.add(bridge[6]);

    // Add the labels and buttons to the 4 border panels
    northPanel.add(northLabel);
    eastPanel.add(eastLabel);
    southPanel.add(southLabel);
    southPanel.add(cross);
    westPanel.add(westLabel);

    // Add all the panels to the JFrame
    frame.getContentPane().add(northPanel, BorderLayout.NORTH);
    frame.getContentPane().add(eastPanel, BorderLayout.EAST);
    frame.getContentPane().add(bridgePanel, BorderLayout.CENTER);
    frame.getContentPane().add(southPanel, BorderLayout.SOUTH);
    frame.getContentPane().add(westPanel, BorderLayout.WEST);

    // Set the JFrame size and visibility
    frame.setSize(450,150);
    frame.setVisible(true);
  }

  public void actionPerformed (ActionEvent event) {

    new Thread (new Runnable() {
      public void run() {
        moveGeorge();
      }
    }).start();
  }

  public void moveGeorge() {
    for(int i=0; i<7; i++) {
      spot = i;
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          if (spot > 0) {
            bridge[spot].setText(george);
            bridge[spot-1].setText("");
          }
          else {
            westLabel.setText("");
            bridge[spot].setText(george);
          }

          try
        {
          Thread.sleep(1000); // do nothing for 1000 miliseconds (1 second)
        }
        catch(InterruptedException e)
        {
          e.printStackTrace();
        }

          frame.setVisible(true);
        }
      });
    }
  }
}


Thread.sleep(1000); // do nothing for 1000 miliseconds (1 second)

Never use Thread.sleep() while code is executing on the Event Dispatch Thread. Thats prevents the GUI from responding to events and from repainting itself.

That code needs to be moved outside of the invokeLater() code.

See Concurrency in Swing for more information about the EDT.


Off topic, but it won't fit into a comment:

  • Use a loop, to initialize equal components.
  • Use names like 'brown' instead of comments, mostly repeating the code
  • Use defined values like Color.RED

    Color brown = new Color (143,66,19);
    for (int i = 0; i < 7; ++i) 
    {
        bridge[i] = new JButton ("");
        bridge[i].setBackground (brown);
        bridge[i].setForeground (Color.RED);
        bridge[i].setFont (bridge [0].getFont ().deriveFont (24.0f));
        bridgePanel.add (bridge[i]);
    }
    

This saves you 30 lines of code.


First of all, swing is not thread safe.

Instead of using Thread.sleep() and screwing with the EDT (event dispatch thread) use the Swing Timer

Secondly, try adding a couple ${JComponent}.revalidate() and ${JComponent}.repaint() right after you modify ${JComponent}

For Example

// Starts George standing on the West Bank
westLabel.setText(george);
// Makes George red so he is more visible
westLabel.setForeground(new Color(255,0,0));
// Makes George size 24 font so he is more visible
westLabel.setFont(westPanel.getFont().deriveFont(24.0f));
//VVVV NOW ADD THIS VVVV
westLabel.revalidate();
westLabel.repaint();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜