Reputation: 15
I'm trying to get the container to display every color in my array. It compiles, however it will only display, what I'm assuming, Cyan. I thought my for loop would cycle through all of the colors in the array using ActionEvent/Listener. Do you see what I did incorrectly? Thanks.
import java.awt.*;
import javax.swing.*;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Four extends JFrame implements ActionListener {
private final int SIZE = 180;
Color colors[] = {Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE,
Color.CYAN};
int i;
private Container con = getContentPane();
private JButton button = new JButton("Press Me");
public Four()
{
super("Frame");
setSize(SIZE, SIZE);
con.setLayout(new FlowLayout());
con.add(button);
button.addActionListener(this);
}
public void actionPerformed(ActionEvent event) {
for(i=0; i < colors.length; i++) {
con.setBackground(colors[i]);
}
}
public static void main(String[] args) {
Four frame = new Four();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
}
Upvotes: 0
Views: 966
Reputation: 284
You reinitialize i to 0 and then through loop to colors.length every time in actionPerformed, so you get the last item. Use sth like that instead:
public class Four extends JFrame implements ActionListener {
private final int SIZE = 180;
Color colors[] = {Color.RED, Color.ORANGE, Color.YELLOW,
Color.GREEN, Color.BLUE, Color.CYAN};
int i = 0;
private Container con = getContentPane();
private JButton button = new JButton("Press Me");
public Four() {
super("Frame");
setSize(SIZE, SIZE);
con.setLayout(new FlowLayout());
con.add(button);
button.addActionListener(this);
}
public void actionPerformed(ActionEvent event) {
con.setBackground(colors[i++ % colors.length]);
}
public static void main(String[] args) {
Four frame = new Four();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
}
Upvotes: 2
Reputation: 347184
Swing is a single threaded environment, this means that any action that blocks or stops this thread from executing, will prevent it from processing new events from the event queue, including repaint requests.
Swing is also (for the most part), not thread safe, meaning that it is not safe to try and update the state of any UI component from outside of the Event Dispatching Thread.
The problem in you code is here...
public void actionPerformed(ActionEvent event) {
for(i=0; i < colors.length; i++) {
con.setBackground(colors[i]);
}
}
This will mean that only the last color will be displayed.
In this context, I would recommend using a Swing Timer
, which will allow you to schedule a callback at a regular time interval, which will be executed within the context of the Event Dispatching Thread
Take a look at Concurrency in Swing and How to use Swing Timers for more details
Updated with example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Four extends JFrame {
public static void main(String[] args) {
new Four();
}
public Four() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new FourPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class FourPane extends JPanel {
Color colors[] = {Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE,
Color.CYAN};
int i;
private JButton button = new JButton("Press Me");
private Timer timer;
public FourPane() {
add(button);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (!timer.isRunning()) {
timer.start();
}
}
});
timer = new Timer(500, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (i < colors.length) {
setBackground(colors[i]);
} else {
((Timer) e.getSource()).stop();
}
i++;
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(180, 180);
}
}
}
Upvotes: 3