Search code examples
javaswingjbuttonimageicon

Changing Image by pressing jbutton java


Hello I am having trouble with my code and I have been trying to figure out what is wrong for a few days and looked at somewhat relevant programs for help and can not figure it out. The program is supposed to change the the image of a traffic light based on what button you press: red, yellow, or green. There are 3 classes. I am running the program in eclipse. CLass 1 trafficLight that contains the main method:

import javax.swing.*;
import java.awt.*;
public class trafficLight
{
   //-----------------------------------------------------------------
   //  Creates and displays the main program frame.
   //-----------------------------------------------------------------
   public static void main(String[] args)
   {
      JFrame frame = new JFrame("CHANGE TRAFFIC LIGHT");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      trafficLightPanel lights = new trafficLightPanel();
      trafficLightControls controls = new trafficLightControls(lights);

      JPanel panel = new JPanel();
      panel.setBackground(Color.blue);
      panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));



      panel.add(Box.createRigidArea (new Dimension (0, 20)));
      panel.add(lights);
      panel.add(Box.createRigidArea (new Dimension (0, 10)));
      panel.add(controls);
      panel.add(Box.createRigidArea (new Dimension (0, 10)));

      frame.getContentPane().add(panel);
      frame.pack();
      frame.setVisible(true);
   }
}

The second class trafficLightPanel that contain the imageicons part:

import java.awt.*;
import javax.swing.*;
public class trafficLightPanel extends JPanel
{
    public int count, redCount, yellowCount, greenCount;
    private ImageIcon none, red, yellow, green;
    private JLabel imageLabel;
    //-----------------------------------------------------------------
    // Constructor: Sets up the images and the initial state.
    //-----------------------------------------------------------------
    public trafficLightPanel()
    {

        none = new ImageIcon("nonePic.png");
        red = new ImageIcon("redPic.png");
        yellow = new ImageIcon("yellowPic.png");
        green = new ImageIcon("greenPic.png");
        setBackground(Color.black);
        redCount = 1; yellowCount = 2; greenCount = 3;

        imageLabel = new JLabel(none);

        add(imageLabel);

    }
    //-----------------------------------------------------------------
    // Paints the panel using the appropriate image.
    //-----------------------------------------------------------------
    public void paintComponent(Graphics page)
    {
        super.paintComponent(page);

        if (count == redCount)
        {
            imageLabel.setIcon(red);
        }
        if (count == yellowCount)
        {
            imageLabel.setIcon(yellow);
        }
        if (count == greenCount)
        {
            imageLabel.setIcon(green);
        }
    }
    //-----------------------------------------------------------------
    // Sets the status of the traffic light.
    //-----------------------------------------------------------------
    public void setCount(int newCount)
    {
         count = newCount;
    }
}

The third class trafficLightControls containing the jbuttons:

//********************************************************************
// Represents the control panel for the traffic light program.
//********************************************************************
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class trafficLightControls extends JPanel
{
    private trafficLightPanel lights;
    private JButton red, yellow, green;
    //-----------------------------------------------------------------
    // Sets up the traffic light control panel.
    //-----------------------------------------------------------------
    public trafficLightControls(trafficLightPanel lightPanel)
    {
            lights = lightPanel;
            red = new JButton("RED");
            red.addActionListener(new redListener());
            yellow = new JButton("YELLOW");
            yellow.addActionListener(new yellowListener());
            green = new JButton("GREEN");
            green.addActionListener(new greenListener());

            setBackground(Color.black);
            add(red);
            add(yellow);
            add(green);

    }
    //*****************************************************************
    // Represents the listener for the red button.
    //*****************************************************************
    private class redListener implements ActionListener
    {
        //--------------------------------------------------------------
        // sets count to redCount and repaints the lights panel.
        //--------------------------------------------------------------
        public void actionPerformed(ActionEvent event)
        {
            lights.setCount(lights.redCount);
            lights.repaint();
        }
    }
    //*****************************************************************
    //Represents the listener for the yellow button.
    //*****************************************************************
    private class yellowListener implements ActionListener
    {
        //--------------------------------------------------------------
        //sets count to yellowCount and repaints the lights panel.
        //--------------------------------------------------------------
        public void actionPerformed(ActionEvent event)
        {
            lights.setCount(lights.yellowCount);
            lights.repaint();
        }
    }
    //*****************************************************************
    //Represents the listener for the green button.
    //*****************************************************************
    private class greenListener implements ActionListener
    {
        //--------------------------------------------------------------
        //sets count to green count and repaints the lights panel.
        //--------------------------------------------------------------
        public void actionPerformed(ActionEvent event)
        {
            lights.setCount(lights.greenCount);
            lights.repaint();
        }
    }
}

nonePic.png the non lit up traffic light image redPic.png of traffic light lit up with red yellowPic.png greenPic.png

Each time I click a button it is supposed to set the count in the trafficLightPanel object, lights, to the count that corresponds to the color, then based on the count the image is supposed to be replaced by the corresponding image. The components are all put together with a box layout.

For some reason only red will work... It starts out displaying the nonePic, the one without any light, and when I click red it displays redPic. If I click on any before or after clicking RED button, the others do not display. If I click one of the others first then RED button, red can still display for some reason. All images are in the root folder(is this the correct name?), the one containing the src and bin folders.

I thought maybe something was wrong with the count, and I tried doing something like adding a jLabel that would display the count each time into the program with the box layout but it does not display anything(this attempt is not in the code). I also tried putting the jLabel into the trafficLightControls class and adding it along with the add(red) add(yellow).... but it would not display anything. Another thing I tried was to change the text of the buttons each time to displaying the color with the count as an alternative to the jLabel attempt. I tried using .setText("") method like red.setText("") in the listener class for red. I would appreciate it if anyone could explain how to add a jLabel and change the text of the button as I have described in this particular little paragraph, as it is something I would like to know how to do to for future reference, though it is not necessary to solving my problem so its ok to not help out with this little paragraph.

Thank you very much for any help anyone offers!

edit: (I am sorry I left in remnants of my attempts at making jLabels to test the code but I removed them, though they did not affect the code I believe, I attempted to use them because of my problem. I am very sorry if this confused anyone)


Solution

  • There's no need to call repaint() and you shouldn't override paintComponent if all you're doing is swapping ImageIcons. Simply call setIcon(...) on your JLabel is all that is needed. The model will trigger a repainting of the view itself.

    Getting rid of your paintComponent override and changing setCount to something as simple as this could work:

    public void setCount(int newCount) {
        count = newCount;
        Icon icon = null;
        switch (count) {
        case 1:
            icon = red;
            break;
        case 2:
            icon = yellow;
            break;
        case 3: 
            icon = green;
            break;
        default:
            icon = null;
            break;
        }
        imageLabel.setIcon(icon);
    }
    

    For example, my MCVE, one that uses an enum and a Map to simplify the code a bit.

    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.util.EnumMap;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class Traff2 extends JPanel {
        public Traff2() {
            Traff2LightPanel lightPanel = new Traff2LightPanel();
            Traff2LightControlsPanel controlsPanel = new Traff2LightControlsPanel(lightPanel);
    
            setLayout(new BorderLayout());
            add(lightPanel, BorderLayout.CENTER);
            add(controlsPanel, BorderLayout.PAGE_END);
        }
    
        private static void createAndShowGui() {
            Traff2 mainPanel = new Traff2();
    
            JFrame frame = new JFrame("Traffic");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }
    

    enum Light {
        NONE(""), RED("Red"), YELLOW("Yellow"), GREEN("Green");
    
        private String text;
    
        private Light(String text) {
            this.text = text;
        }
    
        public String getText() {
            return text;
        }
    }
    

    @SuppressWarnings("serial")
    class Traff2LightPanel extends JPanel {
        private Map<Light, Icon> lightColorMap = new EnumMap<>(Light.class);
        private JLabel imageLabel = new JLabel();
        private Light light = Light.NONE;
    
        public Traff2LightPanel() {
            // fill the map
            lightColorMap.put(Light.NONE, new ImageIcon("nonePic.png"));
            lightColorMap.put(Light.RED, new ImageIcon("redPic.png"));
            lightColorMap.put(Light.YELLOW, new ImageIcon("yellowPic.png"));
            lightColorMap.put(Light.GREEN, new ImageIcon("greenPic.png"));
    
            imageLabel.setIcon(lightColorMap.get(Light.NONE));
            add(imageLabel);
        }
    
        // when changing the light field, 
        // also set the ImageIcon
        public void setLight(Light light) {
            this.light = light;
            imageLabel.setIcon(lightColorMap.get(light));
        }
    
        public Light getLight() {
            return light;
        }
    }
    

    @SuppressWarnings("serial")
    class Traff2LightControlsPanel extends JPanel {
        private Traff2LightPanel lightPanel;
    
        public Traff2LightControlsPanel(Traff2LightPanel lightPanel) {
            this.lightPanel = lightPanel;
            for (Light light : Light.values()) {
                if (light == Light.NONE) {
                    continue;
                }
                add(new JButton(new LightAction(light)));
            }
        }
    
        // use an AbstractAction... 
        // like an ActionListener on "steroids"
        private class LightAction extends AbstractAction {
            private Light light;
    
            public LightAction(Light light) {
                super(light.getText());
                this.light = light;
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                lightPanel.setLight(light);
            }
        }    
    }