0

I am looking to develop a word guessing game for JAVA but I am having a bit of difficulty developing the GUI. I am not trying to develop a simple GUI that just using one text field, I would like to develop one that is more mobile-like so to say. Thus I would like to white-boxes show up as place holders for the characters in the word. It would something like the image below.enter image description here

Essentially players will be able to drag and drop characters from below (I'll probably have them be buttons or something) into the place holder boxes to be compared to the character of the word at that location. I have tried making an array list of text fields but that failed horribly. Anyone have any suggestions on how to proceed?


Updated as per answer provided by MadProgrammer

After using some of MadProgrammer's code I came up with the following package structure for my views package.

> Views
>> GameBoard.java
>> HighScorePanel.java
>> MainPanel.java
>> ScorePanel.java
>> StatisticPanel.java
>> TimerPanel.java
>> ViewConfig.java
>> WordPanel.java

Essentially just a bunch of panels that are put together in the GameBoard.java class. The main issues that I am having is with the MainPanel.java class, and keeping the aspect ratios. So below is an image of the view so far, it looks half decent but the word hint & category are right up against the text fields, and the text fields not wide enough.

enter image description here

If I were to enlarge this frame, the spacing between the components would stay exactly the same and would not scale up. So essentially I looking for a way to dynamically set the spacing between components. I have placed the code for GameBoard.java, MainPanel.java and StatisticPanel.java below. GameBoard is composed of MainPanel and StatisticsPanel. StatisticsPanel is composed of ScorePanel, TimerPanel and HighScorePanel. Finally MainPanel is composed of the bits that MadProgrammer suggested earlier.

GameBoard.java

package views;

import java.awt.BorderLayout;

import javax.swing.JFrame;

public class GameBoard extends JFrame{

    private StatisticsPanel sp = new StatisticsPanel();
    private MainPanel mp = new MainPanel();

    public GameBoard() {
        // set the title for the game board
        setTitle(ViewConfig.DEFAULT_GAME_TITLE);

        // add panel components to board
        add(sp, BorderLayout.PAGE_START);
        add(mp, BorderLayout.CENTER);

        // set the board size
        setSize(ViewConfig.DEFAULT_FRAME_WIDTH, ViewConfig.DEFAULT_FRAME_HEIGHT);

        // set the default close operation
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        GameBoard gb = new GameBoard();

        // set visible
        gb.setVisible(true);
    }
}

StatisticsPanel.java

package views;

import java.awt.FlowLayout;

import javax.swing.JPanel;

public class StatisticsPanel extends JPanel {

    private ScorePanel sp = new ScorePanel();
    private TimerPanel tp = new TimerPanel();
    private HighScorePanel hsp = new HighScorePanel();

    protected StatisticsPanel() {
        // Create a layout for the panel, flow layout in this case as each component should line up
        // horizontally
        FlowLayout panelLayout = new FlowLayout(FlowLayout.CENTER, (ViewConfig.DEFAULT_FRAME_WIDTH/6), 4);

        // Set the panel's layout to the newly created layout
        setLayout(panelLayout);

        // add components
        add(sp);
        add(tp);
        add(hsp);
    }

}

MainPanel.java

package views;

import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class MainPanel extends JPanel {

    private JButton submitAns, clearAns;
    private JLabel wordHint, wordCategory;
    private WordPanel wp = new WordPanel(ViewConfig.DEFAULT_GUESS_WORD.length());

    protected MainPanel() {
        // create the buttons to submit and clear answer
        submitAns = new JButton(ViewConfig.DEFAULT_SUBMIT);
        clearAns = new JButton(ViewConfig.DEFAULT_CLEAR);

        // Create new default labels for the word hint and category
        wordHint = new JLabel(ViewConfig.DEFAULT_WORD_HINT);
        wordCategory = new JLabel(ViewConfig.DEFAULT_WORD_CATEGORY);

        // Set layout manger to GridBagLayout
        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.insets = new Insets(4, 4, 4, 4);

        // add all components to panel with following format:
        // Word Hint > Input Fields > Word Category > Buttons
        add(wordHint, gbc);
        add(wp, gbc);
        add(wordCategory, gbc);

        // Create secondary JPanel to group buttons together, give it flow layout and add button panel to parent
        JPanel buttonPanel = new JPanel();
        FlowLayout buttonPanelLayout = new FlowLayout(FlowLayout.CENTER, 10, 4);
        buttonPanel.add(submitAns, buttonPanelLayout);
        buttonPanel.add(clearAns, buttonPanelLayout);

        // add button panel to parent
        add(buttonPanel);
    }

    protected JLabel getWordHint() {
        return wordHint;
    }

    protected void setWordHint(String wordHint) {
        this.wordHint.setText(wordHint);
    }

    protected JLabel getWordCategory() {
        return wordCategory;
    }

    protected void setWordCategory(String wordCategory) {
        this.wordCategory.setText(wordCategory);
    }
}
soccerman stan
  • 121
  • 1
  • 11

1 Answers1

2

One idea might be to use a series of compounding layouts which you can build up to meet your requirements.

At the heart would a JPanel, which would present specially crafted JLabels capable of displaying the characters of the word, for example...

enter image description here

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new GuessingGame());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class GuessingGame extends JPanel {

        public GuessingGame() {
            setLayout(new GridBagLayout());
            JLabel label = new JLabel("<html>A few sentences giving either a definition or a<br> few hints about what the word could be</html>");
            WordPane wordPane = new WordPane("stackoverflow");
            JLabel wordCategory = new JLabel("Word Category");

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.insets = new Insets(4, 4, 4, 4);
            add(label, gbc);
            add(wordPane, gbc);

            JPanel pnlWordCategory = new JPanel(new GridLayout(1, 6, 4, 4));
            pnlWordCategory.add(new LetterLabel("A"));
            pnlWordCategory.add(new LetterLabel("B"));
            pnlWordCategory.add(new LetterLabel("C"));
            pnlWordCategory.add(new LetterLabel("D"));
            pnlWordCategory.add(new LetterLabel("W"));
            pnlWordCategory.add(new LetterLabel("G"));
            add(wordCategory, gbc);
            add(pnlWordCategory, gbc);
        }

    }

    public class WordPane extends JPanel {

        private String word;
        private List<JLabel> labels;

        public WordPane(String text) {
            setLayout(new GridLayout(1, text.length(), 4, 4));
            labels = new ArrayList<>(text.length());
            for (int index = 0; index < text.length(); index++) {
                LetterLabel label = new LetterLabel();
                labels.add(label);
                add(label);
            }
        }

    }

        public class LetterLabel extends JLabel {

            public LetterLabel(String text) {
                this();
                setText(text);
            }

            public LetterLabel() {
                setBorder(new CompoundBorder(new LineBorder(Color.GRAY), new EmptyBorder(4, 4, 4, 4)));
            }

            @Override
            public Dimension getPreferredSize() {
                Insets insets = getInsets();
                Dimension size = new Dimension();
                FontMetrics fm = getFontMetrics(getFont());
                size.width = (insets.left + insets.right) + fm.stringWidth("M");
                size.height = (insets.top + insets.bottom) + fm.getHeight();
                return size;
            }

        }

}

Now, you could use the same idea, but use JTextFields instead of JLabels

enter image description here

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new GuessingGame());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class GuessingGame extends JPanel {

        public GuessingGame() {
            setLayout(new GridBagLayout());
            JLabel label = new JLabel("<html>A few sentences giving either a definition or a<br> few hints about what the word could be</html>");
            WordPane wordPane = new WordPane("stackoverflow");
            JLabel wordCategory = new JLabel("Word Category");

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.insets = new Insets(4, 4, 4, 4);
            add(label, gbc);
            add(wordPane, gbc);

            JPanel pnlWordCategory = new JPanel(new GridLayout(1, 6, 4, 4));
            pnlWordCategory.add(new LetterLabel("A"));
            pnlWordCategory.add(new LetterLabel("B"));
            pnlWordCategory.add(new LetterLabel("C"));
            pnlWordCategory.add(new LetterLabel("D"));
            pnlWordCategory.add(new LetterLabel("W"));
            pnlWordCategory.add(new LetterLabel("G"));
            add(wordCategory, gbc);
            add(pnlWordCategory, gbc);
        }

    }

    public class WordPane extends JPanel {

        private String word;
        private List<JTextField> fields;

        public WordPane(String text) {
            setLayout(new GridLayout(1, text.length(), 4, 4));
            fields = new ArrayList<>(text.length());
            for (int index = 0; index < text.length(); index++) {
                JTextField field = new JTextField(2);
                fields.add(field);
                add(field);
            }
        }

    }

        public class LetterLabel extends JLabel {

            public LetterLabel(String text) {
                this();
                setText(text);
            }

            public LetterLabel() {
                setBorder(new CompoundBorder(new LineBorder(Color.GRAY), new EmptyBorder(4, 4, 4, 4)));
            }

            @Override
            public Dimension getPreferredSize() {
                Insets insets = getInsets();
                Dimension size = new Dimension();
                FontMetrics fm = getFontMetrics(getFont());
                size.width = (insets.left + insets.right) + fm.stringWidth("M");
                size.height = (insets.top + insets.bottom) + fm.getHeight();
                return size;
            }

        }

}

Now, control. In order to manage the process you would need some kind of model or controller which would be capable of taking the input from the WordPane and validating it and then notifying the WordPane that the guess was valid or not so it could update the UI, but that's beyond the scope of the question

Updated

There are a number of ways you might achieve dragging characters from one part to another part, none of the simple.

Probably the simplest is to wrap the String value of your control in a Transferable and update the field once it's dropped on it, something like this for example

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thanks a lot. Yeah I have an idea for the controller class already, and an idea for the models as well. Thanks a bunch! – soccerman stan Mar 01 '15 at 04:47
  • Understand that D'n'D is not the simplest thing in the word, see update – MadProgrammer Mar 01 '15 at 06:10
  • Yeah you're right! But I want to learn something new. I just am not good at the graphical part, I most definitely will struggle to figure it out but it will be a good learning experience – soccerman stan Mar 01 '15 at 06:24