Search code examples
swingjframejpaneljlabel

Hangman Game Background Image Not Efficient?


I'm making a Hangman game and it seems that my code doesn't provide me much freedom with using layouts. I added an image to my JFrame then I added a JPanel to my image which I'm using for all the JLabels and JTextFields but it seems to me that its inefficient because in order to change the layout of my JTextFields or JLabels I have to change the layout of my image which messes up the entire looks of the game. How can I make this code more efficient and give myself more freedom to change the layouts of my JLabels and JTextFields without messing everything up? Thanks for the help in advanced.

 /*PACKAGE DECLARATION*/
    package Game;

    import java.awt.Font;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.*;


    /************************
     * GAME MECHANICS CLASS *
     * **********************/
    public class GameStructure {

        /* INSTANCE DECLARATIONS */
        private String []wordList = {"computer","java","activity","alaska","appearance","article",
               "automobile","basket","birthday","canada","central","character","chicken","chosen",
               "cutting","daily","darkness","diagram","disappear","driving","effort","establish","exact",
               "establishment","fifteen","football","foreign","frequently","frighten","function","gradually",
               "hurried","identity","importance","impossible","invented","italian","journey","lincoln",
               "london","massage","minerals","outer","paint","particles","personal","physical","progress",
               "quarter","recognise","replace","rhythm","situation","slightly","steady","stepped",
               "strike","successful","sudden","terrible","traffic","unusual","volume","yesterday"};
        private int []length = new int [64];
        private JTextField tf;//text field instance variable (used)
        private JLabel jl2;//label instance variable (used)
        private JLabel jl3;//label instance (working on)
        private String letter;


        /*****************
         * LENGTH METHOD *
         * ***************/
        public void length(){

            jl3 = new JLabel();

            int j = 0;
            for(j = 0; j<64; j++) {

                length[j] = wordList[j].length();//gets length of words in wordList
            }//end for

            int l = 0;
            String line = "";
            //create line first then put into .setText
            for(int m = 0; m<length[l]; m++) {

                line += "__ ";
                l++;
            }//end for
            jl3.setText(line);

            }//end length method


        /*****************
         * WINDOW METHOD *
         * ***************/
        public void window() {

        LoadImageApp i = new LoadImageApp();//calling image class

        JFrame gameFrame = new JFrame();//declaration
        JPanel jp = new JPanel();
        //JPanel jp2 = new JPanel();//jpanel for blanks
        JLabel jl = new JLabel("Enter a Letter:");//prompt with label

        jl.setFont(new Font("Rockwell", Font.PLAIN, 20));//set font

        tf = new JTextField(1);//length of text field by character
        jl2 = new JLabel("Letters Used:    ");

        tf.setFont(new Font("Rockwell", Font.PLAIN, 20));//set font
        jl2.setFont(new Font("Rockwell", Font.PLAIN, 20));//set font

        jp.add(jl);//add label to panel
        jp.add(tf);//add text field to panel
        jp.add(jl2);//add letters used

        gameFrame.add(i); //adds background image to window
        i.add(jp); // adds panel containing label to background image panel

        gameFrame.setTitle("Hangman");//title of frame window
        gameFrame.setSize(850, 600);//sets size of frame
        gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//exit when 'x' button pressed
        gameFrame.setIconImage(new ImageIcon("Hangman-Game-grey.png").getImage());//set the frame icon to an image loaded from a file
        gameFrame.setLocationRelativeTo(null);//window centered
        gameFrame.setResizable(false);//user can not resize window
        gameFrame.setVisible(true);//display frame

      }//end window method


        /*********************
         * USER INPUT METHOD *
         * *******************/
        public void userInput() {

            tf.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {//when enter key pressed

                JTextField tf = (JTextField)e.getSource();

                letter = tf.getText();
                jl2.setText(jl2.getText() + letter + " ");//sets jlabel text to users entered letter

                }//end actionPerformed method

            });

        }//end userInput method

    }//end GameMechanics class



    /*PACKAGE DECLARATION*/
    package Game;


    /***********************
     * IMPORT DECLARATIONS *
     * *********************/
    import java.awt.BorderLayout;
    import java.awt.Graphics;
    import javax.swing.ImageIcon;
    import javax.swing.JPanel;


    /***************
     * IMAGE CLASS *
     * *************/
    public class LoadImageApp extends JPanel {

        private static final long serialVersionUID = 1L;

            private ImageIcon image;


            /***********************
             * PAINT IMAGE METHOD *
             * *********************/
            public void paintComponent (Graphics g) {

                //setLayout(new BorderLayout());

                super.paintComponent(g);
                image = new ImageIcon("hangman.png");//image name & type
                image.paintIcon(this, g, 270, 20);

            }//end paintComponent method

    }//end LoadImageApp class

    /*PACKAGE DECLARATION*/
    package Game;


    /*******************
     * GAME MAIN CLASS *
     * *****************/
    public class GameMain {


        /***************
         * MAIN METHOD *
         * *************/
        public static void main (String []args) {

            GameStructure game = new GameStructure();//declaration
            game.length();
            game.window();
            game.userInput();

        }//end main method

    }//end GameMain class

Solution

  • Some suggestions:

    • Don't override a JPanel's paint(...) method, but rather its paintComponent(Graphics g) method, not unless you need to change how it renders its child components or its borders (you don't). Also by doing this you gain some Swing graphics advantages including automatic double buffering.
    • Never read in an image into the paint or paintComponent method. These methods are one of the main determinants of how responsive your GUI appears to the user, and so you never want to do file I/O in the method. And also, why have code that inefficiently re-reads the same image in whenever paint or paintComponent is called? Why not simply store the image or ImageIcon in a variable once, and be done with it?
    • Learn and use the layout managers
    • JPanels that go over drawing or image rendering JPanels often should be non-opaque - so be sure to call setOpaque(false) on them, and also on some other overlying Swing components.

    _________________________

    Edit

    For example, here is my SSCCE that shows an example of getting an image (here off of the internet) in a class constructor. Also note that my SSCCE will work on any computer connected to the internet since it does not require image files, unlike yours. Also code not related to displaying the GUI has been cut out making the remaining code more pertinent to the problem. Consider doing this next time you post an SSCCE.

    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    
    import javax.imageio.ImageIO;
    import javax.swing.*;
    
    class GameStructure {
       private JTextField tf;
       private JLabel jl2;
    
       public void window() {
          LoadImageApp loadImageApp = new LoadImageApp();
          JFrame gameFrame = new JFrame();
          JPanel jp = new JPanel();
          jp.setOpaque(false); //!!
          jp.setBorder(BorderFactory.createTitledBorder("jp"));
          JLabel jl = new JLabel("Enter a Letter:");
          jl.setFont(new Font("Rockwell", Font.PLAIN, 20));
          tf = new JTextField(1);
          jl2 = new JLabel("Letters Used:    ");
          tf.setFont(new Font("Rockwell", Font.PLAIN, 20));
          jl2.setFont(new Font("Rockwell", Font.PLAIN, 20));
          jp.add(jl);
          jp.add(tf);
          jp.add(jl2);
          gameFrame.add(loadImageApp);
          loadImageApp.add(jp);
          gameFrame.setTitle("Hangman");
          gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          // gameFrame.setIconImage(
          // new ImageIcon("Hangman-Game-grey.png").getImage());
          gameFrame.setResizable(false);
          gameFrame.pack();
          gameFrame.setLocationRelativeTo(null);
          gameFrame.setVisible(true);
       }
    }
    
    class LoadImageApp extends JPanel {
       private static final long serialVersionUID = 1L;
       private static final int PREF_W = 850;
       private static final int PREF_H = 600;
       private BufferedImage img;
    
       public LoadImageApp() {
          // just used as an example public image
          String spec = "https://duke.kenai.com/"
                + "SunRIP/.Midsize/SunRIP.png.png";    
          URL url;
          try {
             url = new URL(spec);
             img = ImageIO.read(url);
          } catch (MalformedURLException e) {
             e.printStackTrace();
          } catch (IOException e) {
             e.printStackTrace();
          }
       }
    
       @Override
       public Dimension getPreferredSize() {
          return new Dimension(PREF_W, PREF_H);
       }  
    
       public void paintComponent(Graphics g) {
          super.paintComponent(g);
          if (img != null) {
             g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
          }
       }
    }
    
    public class GameMain {
       public static void main(String[] args) {
          GameStructure game = new GameStructure();
          game.window();
       }
    }