Search code examples
javaswingjcomponentcardlayout

How can set location and size for card layout?


I've been working on this small trivia game as a project to keep me busy, but I can't figure out how to make it look good. preferably, the buttons would be at the top and the question would be towards the bottom with a set window size. Although setSize() or setPreferredSize() aren't working. So the window is very thin and the buttons and question are all at the top.

package mainPackage;

import javax.swing.JFrame;

public class MainGame{
    public static void main(String[] args) {
        new WindowComp();

    }
}

    package mainPackage;

import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

@SuppressWarnings("serial")
public class WindowComp extends JComponent implements ActionListener {

    JFrame frame = new JFrame("trivia game");




    static JButton [] buttons;
    static JLabel question;
    JPanel panelCont = new JPanel();
    JPanel panelStartScreen= new JPanel();
    JPanel panelGame = new JPanel();
    JButton startGame = new JButton("Start Trivia");
    CardLayout cl = new CardLayout();




    public WindowComp(){
        question = new JLabel("default");
        buttons = new JButton[4];
        panelCont.setLayout(cl);



        buttons[0] = new JButton("Answer 1 : " + "default");
        buttons[1] = new JButton("Answer 2 : " + "default");
        buttons[2] = new JButton("Answer 3 : " + "default");
        buttons[3] = new JButton("Answer 4 : " + "default");

        buttons[0].addActionListener(this);
        buttons[1].addActionListener(this);
        buttons[2].addActionListener(this);
        buttons[3].addActionListener(this);
        startGame.addActionListener(this);
        addAll();
        panelCont.add(panelStartScreen, "1");
        panelCont.add(panelGame, "2");



        frame.add(panelCont);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(300, 300);
        frame.pack();
        frame.setVisible(true);



    }


    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == buttons[0]){
            setQuestion("button 1");
            setAnswers( "start", "start", "start", "start");
        }
        if(e.getSource() == buttons[1]){
            setQuestion("button 2");
            setAnswers("final", "final", "final", "final"); 
        }
        if(e.getSource() == buttons[2]){
            setQuestion("button 3");
        }
        if(e.getSource() == buttons[3]){
            setQuestion("button 4");
        }

        if(e.getSource()==startGame){
            cl.show(panelCont, "2");

        }


    }
    public void addAll(){

        panelGame.add(buttons[0]);
        panelGame.add(buttons[1]);
        panelGame.add(buttons[2]);
        panelGame.add(buttons[3]);
        panelGame.add(question);
        panelStartScreen.add(startGame);



    }



    public static void setAnswers( String ans1, String ans2, String ans3,String ans4){
        buttons[0].setText("Answer 1 : " + ans1);
        buttons[1].setText("Answer 2 : " + ans2);
        buttons[2].setText("Answer 3 : " + ans3);
        buttons[3].setText("Answer 4 : " + ans4);

    }

    public static void setQuestion(String q){
        question.setText("Question: " + q);
    }
}

Solution

  • Things to note:

    1. Calling JFrame.pack() rearranges its components and resizes the JFrame.

    2. It's easier (I find) to make a JPanel, call JPanel.setPreferredSize(new Dimension(width, height)), place components inside it, and add it to the JFrame. That way, you may still call JFrame.pack() and the JPanel stays its preferred size.

    3. You can remove JFrame.pack(), call JFrame.setPreferredSize(new Dimension(width, height)), and/or JFrame.setResizable(false).

    4. You can call JFrame.setMinimumSize(new Dimension(width, height)) to keep it from packing too tightly. Note that this method will not guarantee the specified dimensions when you call JFrame.pack(). In your case, the width stretches a bit due to JFrame.pack() being called afterwards.

    5. For your program, I recommend you use JFrame.setLayout(new BorderLayout()), and make a JPanel with a FlowLayout/GridLayout and add your buttons. Then place the JPanel on the BorderLayout.NORTH area. Then create another JPanel, place your questions inside it using a layout of your choice, and add it to BorderLayout.CENTER area in the JFrame. After noting the minimum size that does not interfere with component visibility, configure JFrame.setMinimumSize(new Dimension(width, height)).

    6. Layout managers get rid of all the headaches involved with component placements after resizing a window, but rare instances do exist where using setLayout(null) is the best option (see Fig1). If you don't care about users' ability to resize your app, calling JFrame.setResizable(false) will suffice. This will give rise to compatibility issues with lower resolution displays, however.

    enter image description here Figure 1. Placing buttons in this fashion required me to abandon layout managers and configure placement of these buttons according to the width and height variables that update upon resizing the window.

    Good luck!