javaswing

Change the image in a JPanel when a button is pressed, in Java Swing


I am well aware of the several other posts of similar nature. I've been trying to use them to help me, however either I am simply overlooking something or my code is missing something essential to properly work. I have a main JPanel that I am trying to have the image change every time a button is pressed (and I am starting to thing that my plan to change the layout when a different button is pressed will be a lot harder), but when it comes to the @Override section, I find that the icon cannot be changed, or when I try to implement something that I find from Stack Overflow or from suggested in VSCode, it leads to lots of red lines.

What I want is to have an array of images available so that when the button is pressed, it runs through a random number generator and outputs a number that grabs a picture from the array at random. Fret not, I am well educated in the random number generation department, I hope.

And yes, I am aware this is a hot mess. I've tried several times over the past couple of weeks to figure this out (started with only a couple hours a day to stay sane, ending with non-stop 72 hours sessions, waking from sleep with different ideas to try).

Here are some sections of my code, I am including that which I think is necessary as I have written a lot and navigating is a nightmare.

private JPanel topRow, leftPane, mainPane, bottomRow, mPane1;
private JButton btnOne, btnTen, btnHun, btnTho;
private JTextArea mPane2, test;
private String imagePath, name;
private ImageIcon image;

public  WSgui() {
    super("Character Wish Simulator");
    this.setSize(900, 600);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setLayout(new BorderLayout());

    this.mainPane = new JPanel();
    this.mainPane.setBackground(Color.ORANGE);
    this.mainPane.setMinimumSize(new Dimension(650, 400));
    this.mainPane.setBorder(new EmptyBorder(40,40,40,40));
    this.mainPane.setLayout(new BorderLayout());

    //buttons
    this.btnOne = new JButton("x1 wish");
    this.btnOne.setSize(200, 100);

    //setting panes for main
    this.mPane1 = new JPanel();
    int xSize = ((int) mainPane.getSize().getWidth());  
    int ySize = ((int) mainPane.getSize().getHeight());  
    int height = (int)(Math.round(ySize * 0.80));
    int width = (int)(Math.round(xSize * 0.80));
    this.mPane1.setPreferredSize(new Dimension(width, height));
    this.mPane1.setMinimumSize(new Dimension(xSize, ySize));
    this.mPane1.setMaximumSize(new Dimension(1000, 1000));

    this.mPane2 = new JTextArea();
    this.mPane2.setText("This should be below the picture");
    this.mPane2.setFont(new Font("Dialog", Font.PLAIN, 15));
    this.mPane2.setMaximumSize(new Dimension(width, 50));
    this.mPane2.setWrapStyleWord(true);
    this.mPane2.setLineWrap(true);
    this.mPane2.setEditable(false);

    this.btnTen = new JButton("x10 wish");
    this.btnTen.setSize(200, 50);
    this.btnTen.addActionListener(this);
    //This idea (action listener) came from StackOverflow, but sadly is not working

    this.btnHun = new JButton("x100 wish");
    this.btnHun.setSize(200, 50);
    this.btnHun.addActionListener(this);

    this.btnTho = new JButton("x1000 wish");
    this.btnTho.setSize(200, 50);
    this.btnTho.addActionListener(this);

    //Test image for Main Pane
    image = new ImageIcon(bnr);//some more ideas I found
    JLabel image5 = new JLabel(image);
    JLabel image2 = new JLabel(new ImageIcon(lpImage));
    JLabel image3 = new JLabel(new ImageIcon(mImage));
    JLabel image4 = new JLabel(new ImageIcon(xtra));
    this.mPane1.add(image3);
    this.leftPane.add(image2);
    this.topRow.add(image5);
    this.bottomRow.add(image4);
    this.mainPane.add(this.mPane1, BorderLayout.CENTER);
    this.mainPane.add(this.mPane2, BorderLayout.SOUTH);
    this.btnOne.addActionListener(e -> image5.setIcon(images[3]));
    ImageIcon[] images = new ImageIcon[] {//my pathetic attempt at an array
        new ImageIcon("img/t1.png"), new ImageIcon("img/t2.png"), new ImageIcon("img/t3.jpg"),
        new ImageIcon("img/t4.jpg"), new ImageIcon("img/t5.png")
    };

    String[] image8 = new String[] {
        "img/t1.png"//idk how to explain this one
    };  

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == btnOne) {
            String image9 = image8[0];//and this is what I struggle with
            ImageIcon icon9 = new ImageIcon(image9);
            icon9.getImage().flush();
            image.setIcon(icon9);
        }
    }
}

Solution

  • Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section.

    I tried to copy your code into my IDE and run it. I could not. I started over and created this GUI.

    Character

    I used two images from the Internet so anyone could run this code. I read the images once during the GUI initiation.

    I broke up my code into separate classes and methods. This enabled me to test each piece separately.

    I created an ImageCollection class to read the images from the Internet. You can modify this class to read from your resources directory.

    I created a JFrame and two JPanels. I used Swing layout managers to manage the two JPanel layout.

    I created one JLabel to display the images.

    Generally, you create and initialize the Swing components once. You reuse Swing components by changing the text or images.

    Here's the complete runnable code. I made the ImageCollection class an inner class so I could post the code as one block.

    import java.awt.BorderLayout;
    import java.awt.FlowLayout;
    import java.awt.GridLayout;
    import java.awt.Image;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    
    import javax.imageio.ImageIO;
    import javax.swing.BorderFactory;
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class MultipleImageDisplay implements ActionListener, Runnable {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new MultipleImageDisplay());
        }
    
        private int imageIndex;
    
        private final ImageCollection imageCollection;
    
        private JLabel imageLabel;
    
        public MultipleImageDisplay() {
            this.imageCollection = new ImageCollection();
            this.imageIndex = 0;
        }
    
        @Override
        public void run() {
            JFrame frame = new JFrame("Character Wish Simulator");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            frame.add(createMainPanel(), BorderLayout.CENTER);
            frame.add(createButtonPanel(), BorderLayout.EAST);
    
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        private JPanel createMainPanel() {
            JPanel panel = new JPanel(new BorderLayout());
            panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    
            imageLabel = new JLabel();
            imageLabel.setIcon(
                    new ImageIcon(imageCollection.getImages()[imageIndex]));
            panel.add(imageLabel);
    
            return panel;
        }
    
        private JPanel createButtonPanel() {
            JPanel panel = new JPanel(new FlowLayout());
            panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    
            JPanel innerPanel = new JPanel(new GridLayout(0, 1, 5, 5));
    
            JButton btnTen = new JButton("x10 wish");
            btnTen.addActionListener(this);
            innerPanel.add(btnTen);
    
            JButton btnHun = new JButton("x100 wish");
            btnHun.addActionListener(this);
            innerPanel.add(btnHun);
    
            JButton btnTho = new JButton("x1000 wish");
            btnTho.addActionListener(this);
            innerPanel.add(btnTho);
            
            panel.add(innerPanel);
    
            return panel;
        }
        
        @Override
        public void actionPerformed(ActionEvent event) {
            imageIndex = ++imageIndex % imageCollection.getImagesLength();
            imageLabel.setIcon(
                    new ImageIcon(imageCollection.getImages()[imageIndex]));
        }
        
    
        public class ImageCollection {
    
            private Image[] images;
    
            public ImageCollection() {
                this.images = new Image[2];
                this.images[0] = readImage("https://www.goodfreephotos.com/"
                        + "albums/other-landscapes/mountains-and-pond-landscape"
                        + "-with-majestic-scenery.jpg");
                this.images[1] = readImage("https://cdn1.epicgames.com/ue/"
                        + "product/Screenshot/RealisticLandscapes"
                        + "%20125-1920x1080-a125dbb0885e785c4"
                        + "fdafbf130b056b8.png?resize=1&w=1920");
            }
    
            @SuppressWarnings("deprecation")
            private Image readImage(String urlString) {
                URL url;
                try {
                    url = new URL(urlString);
                    Image image = ImageIO.read(url);
                    return image.getScaledInstance(960, 540, Image.SCALE_SMOOTH);
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
                return null;
            }
    
            public Image[] getImages() {
                return images;
            }
    
            public int getImagesLength() {
                return images.length;
            }
    
        }
    
    }