Search code examples
javaswinglayoutjpanelgridbaglayout

Using GridBagLayout to set multiple components in one panel, but I dont want to fill up the whole panel


I'm working on a project where I'm building a GUI using java swing. At the moment I have one Jpanel in a JFrame that should contain a label (question) and a set of buttons/textfield (answers), which can change based on the question that is being asked. I want to have the question centered somewhere at the top, with the answers being appropiately centered in the middle. At the moment I use GridBagLayout to set the JLabel and JButtons but still no succes.

public class QuestionPanel extends MoviePanel{

    private String question;

    public QuestionPanel(String type, Application app, String question) throws Exception{
        super(type, app);
        this.question = question;
        JLabel lab = new JLabel(this.question);

        this.getGbc().anchor = GridBagConstraints.PAGE_START;
        this.getGbc().fill = GridBagConstraints.HORIZONTAL;
        this.getGbc().weighty = 0.5;
        this.getGbc().gridx = 2;
        this.getGbc().gridy = 0;

        lab.setFont(new Font("Helvetica", Font.BOLD, 40));
        lab.setForeground(new Color(189, 189, 189, 255));
        add(lab, this.getGbc());

        getAnswers(type);
    }

    private void getAnswers(String type){
        if(type.equals("AgeRestriction")){
            this.getGbc().gridx=0;
            this.getGbc().gridy=1;
            add(new YesButton(this.getApp()),this.getGbc());

            this.getGbc().gridx = 3;
            this.getGbc().gridy = 1;
            add(new NoButton(this.getApp()),this.getGbc());
        }
    }
}

The GridBagLayout is being set in super MoviePanel and this.getGbc() returns the appropiate GridBagConstraints. At the moment the layout I have looks like this:

layout

The idea is to have the yes and no button close to each other and future buttons to be dynamically located in the center.

Solution

I ended up solving by combining the answers of angushjoshi and c0der, so adding an answerPanel in the questionPanel with GridBagLayout. My code now looks like this:

public class QuestionPanel extends MoviePanel {

    private String question;
    private JPanel answerPanel = new JPanel();

    public QuestionPanel(String type, Application app, String question) throws Exception {
        super(type, app);
        this.question = question;
        JLabel lab = new JLabel(this.question);
        answerPanel.setOpaque(false);


        this.getGbc().anchor = GridBagConstraints.PAGE_START;
        this.getGbc().weighty = 1;
        this.getGbc().gridy = 0;
        this.getGbc().gridx = 2;
        this.getGbc().gridwidth = 3;

        lab.setFont(new Font("Helvetica", Font.BOLD, 40));
        lab.setForeground(new Color(189, 189, 189, 255));
        add(lab, this.getGbc());

        getAnswers(type);
    }

    public void getAnswers(String type) {
        if (type.equals("AgeRestriction")) {
            createYesNoButtons();
        }
        if (type.equals("Age")) {
            createAgeField();
        }
        if (type.equals("Genre")){
            createGenreButtons();
        }
        if (type.equals("Actor")){
            createActorField();
        }
    }


    private void createYesNoButtons() {
        this.getGbc().weighty = 0.5;
        this.getGbc().anchor = GridBagConstraints.CENTER;
       answerPanel.add(new YesButton(this.getApp()));
       answerPanel.add(new NoButton(this.getApp()));
       this.add(answerPanel,this.getGbc());
    }

    private void createAgeField() {
        this.getGbc().weighty = 0.5;
        this.getGbc().anchor = GridBagConstraints.CENTER;
        answerPanel.add(new AgeField(this.getApp()));
        this.add(answerPanel,this.getGbc());
    }

    private void createGenreButtons(){
    }

    private void createActorField(){
    }

}

And now the panel looks like this:

layout

Thanks for the help!


Solution

  • I would recommend breaking the layout into smaller, easier to layout parts. In this case use 3 JPanels and demonstrated by the following MRE:

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.GridBagLayout;
    import java.awt.Image;
    import java.io.IOException;
    import java.net.URL;
    import javax.imageio.ImageIO;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    
    public class QuestionAnswerPanel extends JPanel{
    
        private Image background;
        //use publicly available resources when posting questions or answers
        private final String imageLink = "https://www.whatsonnetwork.co.uk/uploads/800x600/98331337cb0f7f31c874e22a8f2b5f8b.jpg";
    
        QuestionAnswerPanel() {
    
            URL url;
            try {
                url = new URL(imageLink);
                background = ImageIO.read(url);
                setPreferredSize(new Dimension(background.getWidth(null), background.getHeight(null)));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
    
            //border layout  allows you to add components to 5 positions,
            //including north and center
            setLayout(new BorderLayout());
    
            //have a JPanel for the question
            JLabel lab = new JLabel("To Be Or Not To Be ?");
            lab.setFont(new Font("Helvetica", Font.BOLD, 40));
            lab.setForeground(new Color(189, 189, 189, 255));
            JPanel questionPanel = new JPanel();
            questionPanel.setOpaque(false);
            questionPanel.add(lab);
            add(questionPanel, BorderLayout.NORTH); //place it at the top
    
            //have a JPanel for the answer
            JPanel answerPanel = new JPanel();
            answerPanel.setOpaque(false);
            //use GridBagLayout to center components
            answerPanel.setLayout(new GridBagLayout());
            //add components as you need
            answerPanel.add(new JButton("Yes"));
            answerPanel.add(new JButton("No"));
            add(answerPanel, BorderLayout.CENTER);//place it at the center
        }
    
    
        @Override //Override to paint image at the background
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(background, 0, 0, null);
        }
    
        public static void main(String[] args) throws IOException {
            JFrame frame=new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new QuestionAnswerPanel());
            frame.pack();
            frame.setVisible(true);
        }
    }
    


    enter image description here