Search code examples
javaswingjframejpaneljmenu

Change image in a JPanel when JMenuItem is chosen


I am having trouble with JMenu and I suspect it's bacause I've misunderstood how Jframe works in regards to live updating. Apologies in advance for the sloppily put together code as its my testing grounds for ideas.

currently this code produces a JFrame with a JMenu named High Slot, with 3 sub menus, each with 5 option. only the first 2 options of the rail sub menu have an action listener for now. Under it I have a JPanel with an image that auto scales to the JPanels size.

The issue is that when I click one of the options, it doesnt update the picture like I think it should. And I know the Action listener is working because I make it print out a statement whenever it fires.

What am I doing wrong?

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
import javax.imageio.*;
class Tests {
   JMenu w, Rail, Cann, Miss;
   JMenuItem r1,r3,r5,r7,r9,c1,c3,c5,c7,c9,m1,m3,m5,m7,m9;
   private static BufferedImage h_empty, t1, t2, placeholder;
   private boolean br1 = false, br3 = false, br5 = false, br7 = false, br9 = false, bc1 = false, bc3 = false, bc5 = false, bc7 = false, bc9 = false, 
                   bm1 = false, bm3 = false, bm5 = false, bm7 = false, bm9 = false;
   JFrame f= new JFrame("EveSim");
   JPanel panel=new JPanel();
   Tests(){
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
      JPanel panel=new JPanel();  
      panel.setBounds(0,0,48,48);    
      panel.setBackground(Color.black);
      try { 
         h_empty = ImageIO.read(new File("Icon_fit_high.png"));
      } catch(IOException ex) {
         System.out.println("Error: Image Failed to Load!");
      }
      try { 
         t1 = ImageIO.read(new File("index.png"));
      } catch(IOException ex) {
         System.out.println("Error: Image Failed to Load!");
      }
      try { 
         t2 = ImageIO.read(new File("index1.png"));
      } catch(IOException ex) {
         System.out.println("Error: Image Failed to Load!");
      }
      placeholder = h_empty;
      ImageIcon imageIcon = new ImageIcon(fitimage(placeholder, panel.getWidth(), panel.getHeight()));
      JLabel jl = new JLabel(imageIcon);
      panel.add(jl);
      JMenuBar mb=new JMenuBar();  
      w=new JMenu("High Slot");  
      Rail=new JMenu("Railguns");  
      Cann=new JMenu("Cannons");
      Miss=new JMenu("Missiles");
      r1=new JMenuItem("Tech 1");
      r1.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ev) {
            Reset();
            br1 = !br1;
            System.out.println("rail-tech1");
            placeholder = t1;
            p_add();
         }
      });
      r3=new JMenuItem("Tech 3");
      r3.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ev) {
            Reset();
            br3 = !br3;
            System.out.println("rail-tech3");
            placeholder =t2;
            p_add();
         }
      });  
      r5=new JMenuItem("Tech 5");  
      r7=new JMenuItem("Tech 7");  
      r9=new JMenuItem("Tech 8");
      c1=new JMenuItem("Tech 1");  
      c3=new JMenuItem("Tech 3");  
      c5=new JMenuItem("Tech 5");  
      c7=new JMenuItem("Tech 7");  
      c9=new JMenuItem("Tech 8");
      m1=new JMenuItem("Tech 1");  
      m3=new JMenuItem("Tech 3");  
      m5=new JMenuItem("Tech 5");  
      m7=new JMenuItem("Tech 7");  
      m9=new JMenuItem("Tech 8"); 
           
      Rail.add(r1); Rail.add(r3); Rail.add(r5); Rail.add(r7); Rail.add(r9); 
      Cann.add(c1); Cann.add(c3); Cann.add(c5); Cann.add(c7); Cann.add(c9); 
      Miss.add(m1); Miss.add(m3); Miss.add(m5); Miss.add(m7); Miss.add(m9); 
      w.add(Rail); w.add(Cann); w.add(Miss);
      mb.add(w);  
      f.setJMenuBar(mb);  
      f.add(panel);
      f.setSize(400,400);  
      f.setLayout(null);  
      f.setVisible(true);
   }
   private Image fitimage(Image img , int w , int h) {
      BufferedImage resizedimage = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
      Graphics2D g2 = resizedimage.createGraphics();
      g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
      g2.drawImage(img, 0, 0,w,h,null);
      g2.dispose();
      return resizedimage;
   }
   private void p_add() {
      panel.setBounds(0,0,48,48);    
      panel.setBackground(Color.black);
      ImageIcon imageIcon = new ImageIcon(fitimage(placeholder, panel.getWidth(), panel.getHeight()));
      JLabel jl = new JLabel(imageIcon);
      panel.add(jl);
      f.add(panel);
   }
   private void Reset() {
      br1 = false;
      br3 = false;
      br5 = false; 
      br7 = false; 
      br9 = false; 
      bc1 = false; 
      bc3 = false; 
      bc5 = false; 
      bc7 = false; 
      bc9 = false; 
      bm1 = false; 
      bm3 = false; 
      bm5 = false; 
      bm7 = false;
      bm9 = false;
   }
   public static void main(String args[]){
      new Tests();
   }
}

Solution

  • private void p_add() {
      panel.setBounds(0,0,48,48);    
      panel.setBackground(Color.black);
      ImageIcon imageIcon = new ImageIcon(fitimage(placeholder, panel.getWidth(), panel.getHeight()));
      JLabel jl = new JLabel(imageIcon);
      panel.add(jl);
      f.add(panel);
    }
    

    The problem is that you keep adding components to the frame and because of Swing painting logic you don't see the newly added component.

    1. Don't use setBounds(). Swing was designed to be used with layout managers.
    2. Don't keep creating new components. You should create an add the JLabel to the frame in the constructor of your class. Then in your ActionListener you just create a new ImageIcon and then use the setIcon(...) method of the JLabel to update the image.

    The above suggestions will require a redesign of your application. I suggest you start with the ComboBoxDemo found in the section from the Swing tutorial on How to Use Combo Boxes.

    Yes the example uses a combo box, but the concept is the same. In both cases you use an ActionListener to change the image. In the demo, the ActionListener is added to the combo box. In your case the ActionListener is added to the menu item.