Question

I have been writing and refactoring the code that I started with for Hangman game. I have basically two classes now. One is that launch the hangman (contains main) and other is the getting the panel plugged in with various components. In total, I will have one frame and one Panel, few buttons and a Label and textfield. I have pasted my two bits of code below. I wanted to have all the pushed down to the frame, The label and textfield in the center and I need empty space on the top to put more stuff. I tried BorderLayout.SOUTH, but did not help. The border title is spreading all over, but I would like it to have it surround just the radio buttons. Kindly run the code to see what I mean. Thanks Code1 : with Main method

import javax.swing.*;
import javax.swing.text.MaskFormatter;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.text.ParseException;

public class HangmanGUI {

    DetailsPanel myPanel;

    public HangmanGUI() throws ParseException {

        myPanel = new DetailsPanel();
        JFrame myframe = new JFrame();
        myframe.getContentPane().setLayout(new BorderLayout());
        myframe.getContentPane().add(myPanel, BorderLayout.SOUTH);
        myframe.setTitle("Hangman Game");
        myframe.setVisible(true);
        myframe.setLocationRelativeTo(null);
        myframe.pack();
        myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) throws ParseException {
        new HangmanGUI();
    }
}

code 2: with panel and components

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.text.MaskFormatter;

public class DetailsPanel extends JPanel {

    public DetailsPanel() {

        setPreferredSize(new Dimension(400, 600));

        setBorder(BorderFactory.createTitledBorder(" ciick here "));

        createFormattedPanel();

        for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {
            String buttonText = String.valueOf(alphabet);
            JButton letterButton = new JButton(buttonText);
            letterButton.addActionListener(clickedbutton());
            this.add(letterButton, BorderLayout.CENTER);
        }

    }

    private ActionListener clickedbutton() {
        return new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String actionCommand = e.getActionCommand();
                System.out.println("actionCommand is: " + actionCommand);
            }
        };
    }

    public void createFormattedPanel() {
        MaskFormatter formatter = null;
        try {
            JLabel label = new JLabel("Guesss");
            formatter = new MaskFormatter("? ? ? ? ? ? ?");
            formatter.setPlaceholderCharacter('?');
            JFormattedTextField input = new JFormattedTextField(formatter);
            input.setColumns(20);
            this.add(label);
            this.add(input);
        } catch (java.text.ParseException exc) {
            System.err.println("formatter is bad: " + exc.getMessage());
            System.exit(-1);
        }
    }
}
Was it helpful?

Solution

I would use an image JPanel to hold your hangman drawing, and to act as a placeholder and place it in the JFrame in the BorderLayout.CENTER position. I would also clean up the south JPanel by using layout managers and not relying on default FlowLayout. For instance a BorderLayout for the south Jpanel, put the guess in the page start slot and the buttons in the center slot, and put the buttons into a GridLayout JPanel. For example:

import javax.swing.*;
import javax.swing.text.MaskFormatter;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.text.ParseException;

public class HangmanGUI {
   private DetailsPanel myPanel;
   private ImagePanel imagePanel = new ImagePanel();

   public HangmanGUI() throws ParseException {
      myPanel = new DetailsPanel();
      JFrame myframe = new JFrame();
      // myframe.getContentPane().setLayout(new BorderLayout());
      myframe.getContentPane().add(imagePanel, BorderLayout.CENTER);
      myframe.getContentPane().add(myPanel, BorderLayout.SOUTH);
      myframe.setTitle("Hangman Game");
      // myframe.setVisible(true);
      // myframe.setLocationRelativeTo(null);
      myframe.pack();
      myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      myframe.setLocationRelativeTo(null);
      myframe.setVisible(true);
   }

   public static void main(String[] args) throws ParseException {
      new HangmanGUI();
   }
}

class ImagePanel extends JPanel {
   private static final int PREF_W = 400;
   private static final int PREF_H = PREF_W;
   private static final String TITLE = "Hangman Image";

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   public ImagePanel() {
      setBorder(BorderFactory.createTitledBorder(TITLE));
   }
}

class DetailsPanel extends JPanel {
   public DetailsPanel() {
      setLayout(new BorderLayout());

      setBorder(BorderFactory.createTitledBorder(" ciick here "));
      add(createFormattedPanel(), BorderLayout.PAGE_START);

      JPanel letterPanel = new JPanel(new GridLayout(0, 5));
      for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {
         String buttonText = String.valueOf(alphabet);
         JButton letterButton = new JButton(buttonText);
         letterButton.addActionListener(clickedbutton());
         letterPanel.add(letterButton, BorderLayout.CENTER);
      }
      add(letterPanel, BorderLayout.CENTER);
   }

   private ActionListener clickedbutton() {
      return new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            String actionCommand = e.getActionCommand();
            System.out.println("actionCommand is: " + actionCommand);
         }
      };
   }

   public JPanel createFormattedPanel() {
      JPanel panel = new JPanel();
      MaskFormatter formatter = null;
      try {
         JLabel label = new JLabel("Guesss");
         formatter = new MaskFormatter("? ? ? ? ? ? ?");
         formatter.setPlaceholderCharacter('?');
         JFormattedTextField input = new JFormattedTextField(formatter);
         input.setColumns(20);
//         this.add(label);
//         this.add(input);
         panel.add(label);
         panel.add(input);
      } catch (java.text.ParseException exc) {
         System.err.println("formatter is bad: " + exc.getMessage());
         System.exit(-1);
      }

      return panel;
   }
}

Also, don't set the position of a component or set it visible until after adding all and packing all. Don't set a component's size but rather let the preferred sizes and the layout managers set the sizes for you.


Edit
You ask:

first of all thank you for helping out. This is the solution I wanted. I have some basic questions though. why did you comment out // myframe.getContentPane().setLayout(new BorderLayout());

The JFrame's contentPane already uses BorderLayout by default so it would be unnecessary to explicitly set it to this layout.

also you created three panels, which is nice. for imagepanel, you specified the dimension. but for detailsPanel, you did not specify the dimension. does it mean?

I figure that the image will have a definite size, and so I override its getPreferredSize so that it will be big enough to show the image. All other components, I let them size themselves based on their component's preferred sizes and their layout managers.

if I have many panels and I specify dimension(size) for one panel, all others will get that default on the frame.

Again, all others will have their own preferred sizes based on the preferred sizes of their components and their layout managers.

OTHER TIPS

"IF" I understand correctly, why not just add the buttons to their own panel and set the title border on it instead, for example...

public DetailsPanel() {

    setPreferredSize(new Dimension(400, 600));

    createFormattedPanel();

    JPanel buttons = new JPanel();
    buttons.setBorder(BorderFactory.createTitledBorder(" ciick here "));

    for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {
        String buttonText = String.valueOf(alphabet);
        JButton letterButton = new JButton(buttonText);
        letterButton.addActionListener(clickedbutton());
        buttons.add(letterButton, BorderLayout.CENTER);
    }

    add(buttons);

}

You count create a GridLayout for your buttons like so:

public DetailsPanel() {
    setPreferredSize(new Dimension(400, 600));
    createFormattedPanel();
    JPanel buttons = new JPanel();
    buttons.setBorder(BorderFactory.createTitledBorder(" ciick here "));
    buttons.setLayout(new GridLayout(5,6));

    for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {
        String buttonText = String.valueOf(alphabet);
        JButton letterButton = new JButton(buttonText);
        letterButton.addActionListener(clickedbutton());
        buttons.add(letterButton);
    }
    add(buttons);
}

Then I also added an extra dummy Panel in your main with just a label, change this label to what ever component you want:

    myPanel = new DetailsPanel();
    JFrame myframe = new JFrame();
    JPanel aDummy = new JPanel();
    aDummy.add(new JLabel("Extra text"));
    myframe.getContentPane().setLayout(new BorderLayout());
    myframe.getContentPane().add(aDummy, BorderLayout.CENTER);
    myframe.getContentPane().add(myPanel, BorderLayout.SOUTH);
    //...etc

Comes out like this

enter image description here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top