简体   繁体   中英

creating a loop for ActionListener to iterate through Icon list when Jbutton clicked

I have lists of transparent images that I would like to cycle through on a GUI when a user clicks a JButton and am having trouble with the loop in the actionListener. I have 3 JCheckBoxes so that depending on which is selected, that's the type that changes. Right now I can't get more than one picture to show up at the same time, and I can't get it to change to the next image when the JButton is clicked again. Also, the images in faceImages are solid circles that I would like to change when none of the JCheckBoxes are selected so I'll have to figure out how to put that behind the other Images.. so take your pick on which issue you would like to help me on :)

Here's my code: (the ActionPerfored that I'm working on is at the very bottom, but I'll leave the rest for reference)

public Color myColor;
private JPanel contentPane;
JLabel label;
JCheckBox checkBoxEyes;
JCheckBox checkBoxNose;
JCheckBox checkBoxMouth;
JButton btnSubmit;

Icon plainFace = new ImageIcon(getClass().getResource("plainCircle.png"));
Icon pinkFace = new ImageIcon(getClass().getResource("pinkCircle.png"));
Icon redFace = new ImageIcon(getClass().getResource("redCircle.png"));
Icon greenFace = new ImageIcon(getClass().getResource("greenCircle.png"));

Icon eyes1 = new ImageIcon(getClass().getResource("eyes1.png"));
Icon eyes2 = new ImageIcon(getClass().getResource("eyes2.png"));
Icon eyes3 = new ImageIcon(getClass().getResource("eyes3.png"));

Icon nose1 = new ImageIcon(getClass().getResource("nose1.png"));
Icon nose2 = new ImageIcon(getClass().getResource("nose2.png"));
Icon nose3 = new ImageIcon(getClass().getResource("nose3.png"));

Icon mouth1 = new ImageIcon(getClass().getResource("mouth1.png"));
Icon mouth2 = new ImageIcon(getClass().getResource("mouth2.png"));
Icon mouth3 = new ImageIcon(getClass().getResource("mouth3.png"));

Icon faceImages[] =
{ pinkFace, greenFace, redFace };
Icon eyesImages[] =
{ eyes1, eyes2, eyes3 };
Icon noseImages[] =
{ nose1, nose2, nose3 };
Icon mouthImages[] =
{ mouth1, mouth2, mouth3 };

public ArrayList<Shape> eyeList = new ArrayList<Shape>();
public ArrayList<Shape> noseList = new ArrayList<Shape>();
public ArrayList<Shape> mouthList = new ArrayList<Shape>();
public ArrayList<Shape> backgroundList = new ArrayList<Shape>();

/**
 * Launch the application.
 */
public static void main(String[] args)
{
    // EventQueue
    SwingUtilities.invokeLater(new Runnable()
    {
        @Override
        public void run()
        {
            try
            {
                Face frame = new Face();
                frame.setVisible(true);
            } catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public Face()
{
    setTitle("Face");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 550, 500);
    contentPane = new JPanel();
    contentPane.setBackground(Color.GRAY);
    contentPane.setSize(new Dimension(200, 300));
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    JPanel panel = new JPanel();
    panel.setBounds(0, 31, 97, 218);
    panel.setAlignmentY(Component.TOP_ALIGNMENT);
    contentPane.add(panel);

    checkBoxEyes = new JCheckBox("Eyes");
    checkBoxEyes.getBounds();
    checkBoxEyes.setVerticalAlignment(SwingConstants.TOP);
    checkBoxEyes.setSelected(false);

    panel.setLayout(new MigLayout("", "[83px]", "[45.00px][45.00px][46.00px][50.00px]"));
    panel.add(checkBoxEyes, "cell 0 0,grow");

    checkBoxNose = new JCheckBox("Nose");
    checkBoxNose.setVerticalAlignment(SwingConstants.TOP);
    checkBoxNose.setSelected(false);

    panel.add(checkBoxNose, "cell 0 1,grow");

    checkBoxMouth = new JCheckBox("Mouth");
    checkBoxMouth.setVerticalAlignment(SwingConstants.TOP);
    checkBoxMouth.setSelected(false);

    panel.add(checkBoxMouth, "cell 0 2,grow");

    btnSubmit = new JButton("Submit");
    btnSubmit.getBounds(new Rectangle(10, 10, 50, 50));
    btnSubmit.addActionListener(this);

    panel.add(btnSubmit, "cell 0 3");

    label = new JLabel("");
    label.setLocation(102, 31);
    label.setIcon(plainFace);
    label.setPreferredSize(new Dimension(800, 500));
    label.setSize(new Dimension(421, 381));
    label.setOpaque(true);
    label.setBackground(Color.ORANGE);

    contentPane.add(label);
}

public void createFace(Graphics g)
{
    super.paint(g);
    g.setColor(getColor());
    g.fillOval(20, 20, 100, 100);
}

public Color getColor()
{
    return myColor;
}


public void actionPerformed(ActionEvent e)
{

    if (checkBoxEyes.isSelected() == true)
    {
        for(Icon i : eyesImages)
        {
            label.setIcon(i);
        }
    }

    if (checkBoxNose.isSelected() == true)
    {
        for(Icon i : noseImages)
        {
            label.setIcon(i);
        }

    }

    if (checkBoxMouth.isSelected() == true)
    {
        for(Icon i : mouthImages)
        {
            label.setIcon(i);

        }
    } else
    {
        for(Icon i : faceImages)
        {
            label.setIcon(i);
        }
    }
}

looping on the setIcon() will have the effect of changing the icons so rapidly that you will end up seeing only the last one you set. What you want to do is insert a delay in the loop. However, actionPerformed() is executed by the event dispatching thread, which is also the one responsible for drawing the UI, so while the thread is in it (and changing the icons), the UI is not rendered. so, here is what you should try:

public void actionPerformed(ActionEvent e) {
  final boolean eyes = checkBoxEyes.isSelected();
  /* add booleans for other features here */
  Thread t = new Thread() {
    public void run() {
      if (eyes) {
        for(Icon i : eyesImages) {
            SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                label.setIcon(i)); 
              }
            });
            try {
              Thread.sleep(100);
            }catch(ThreadInterruptedException ex){}
          }
        }
      }
      // add cases for other features
    }        
  }
  t.start();
}

Here is what this does: when actionPerformed() is called by the event dispatch thread, it creates a second thread. This thread goes through the various ifs for the different features, and it loops on the images. For each image, it sets the icon and waits for some time (100ms). In order to set the image, you can't call directly setIcon() from this thread, as in general swing APIs must be called by the event dispatching thread. Hence from the new thread you call SwingUtilities.invokeLater(), which enqueues the runnable for execution by the EDT.

EDIT:

ah, if you want to go to the next image every time a button is pressed:

private int eyeIdx = 0;
public void actionPerformed(ActionEvent e) {
  if (checkBox.Eyes.isSelected()) {
    label.setIcon(eyesImages[eyeIdx]);
    eyeIdx++;
    if (eyeIdx >= eyesImages.length) {
      eyeIdx = 0;
    }
  }
  ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM