0

I want to have 2 JPanels in my app, side by side. One that will have some info about my custom board on the right and one about painting that custom board on the left. The first JPanel is a classic, but the second is a custom panel. It seems that im having problems with putting my custom panel into the frame.

I've created a class named BoardPanel within my gui class to draw my custom board. I don't know if this is the best approach. Should i create a separate class instead?

This is the code of the gui class:

public class BattleshipGUI extends JFrame {

    private BoardPanel mainPanel;


    ///////////////////////////////////////////////////////////////////////////////////////////////
    // Create my frame
    ///////////////////////////////////////////////////////////////////////////////////////////////
    public BattleshipGUI() {

        JPanel container = new JPanel(new BorderLayout()); //the container panel that contains the 2 other panels

        mainPanel = new BoardPanel(); //main panel with my custom painting
        JPanel detailsPanel = new JPanel(new BorderLayout()); //secondary panel with various details about the game

        container.add(mainPanel, BorderLayout.CENTER); //add the 2 panels in the container
        container.add(detailsPanel, BorderLayout.EAST);

        this.add(container); //add container to my frame
        //this.setContentPane(container);



        this.setIconImage(Toolkit.getDefaultToolkit().getImage(BattleshipGUI.class.getResource("/resources/battleship_128.png")));
        this.setTitle("My Battleship Game");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //this.setBounds(100, 100, 850, 700);
        //this.pack();
        this.setSize(850, 600);

        this.setVisible(true);

    }

And this is the code of the inner class for the custom painting

class BoardPanel extends JPanel {

        private static final int ROWS = 20;
        private static final int COLUMNS = 20;


        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            int sqSize = this.getHeight()/ROWS;

            for(int i=0; i<ROWS; i++) {
                for(int j=0; j<COLUMNS; j++) {
                    int x = j * sqSize;
                    int y = i * sqSize;
                    g.drawRect(x, y, sqSize, sqSize);

                }
            }

        }
    }

Aside from all these, i have a question. If i want to have a custom painting, is it possible to work along side with the WindowsBuilderPro? I begun using that tool at first. But, i saw that i cant draw something custom with the tool and i had to write code to do that. Is it possible to write code for a custom paint AND use the tool at the same time for different purposes, like adding a simple text label, or even to edit that custon paint? The expected result that i want to see, appears when i run the program. My frame with the two panels. But when i open the WindowsBuilderPro, my custom panel does not appear and the result is a bit wrong. Thit is the reason why i have a question about my approach and if i can write code and use the tool at the same time. Thank you and sorry for the long text guys. I am too confused about this.

Chris
  • 17
  • 5
  • `BoardPanel` needs to provide sizing hints. You need to override `getPreferredSize` and return the "preferred" size the component would like to be – MadProgrammer Mar 26 '19 at 10:26
  • @MadProgrammer Why should i do that? I mean, what does it solve and what's the problem not to include it? Like this? `public Dimension getPreferredSize() { return new Dimension(400, 600); }` – Chris Mar 26 '19 at 12:27
  • The layout manager will use the sizing hints to make decisions about how best to layout your components, with no sizing hints, the default size of your component is 0x0 – MadProgrammer Mar 26 '19 at 18:12
  • @MadProgrammer So, i have to do this everytime, right? Do i have to do it for the first classic Panel as well? I implemented that public method inside my BoardPanel, but i dont see the size of the BoardPanel's component change. – Chris Mar 27 '19 at 08:32
  • @MadProgrammer Is it possible to help me a bit on this? For the size and for my question about my approach for the two panels. I dont really know how to proceed, etc. Thanks. – Chris Mar 29 '19 at 09:07

1 Answers1

1

Layied out

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

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 TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.fill = gbc.BOTH;
            gbc.gridx = 0;
            gbc.gridy = 0;

            JPanel filler = new JPanel() {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(200, 300);
                }
            };
            filler.setBackground(Color.BLUE);

            add(filler, gbc);
            gbc.gridx++;
            add(new BoardPanel(), gbc);
        }

    }

    class BoardPanel extends JPanel {

        private static final int ROWS = 20;
        private static final int COLUMNS = 20;
        private int sqSize = 20;

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(COLUMNS * sqSize, ROWS * sqSize);
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            for (int i = 0; i < ROWS; i++) {
                for (int j = 0; j < COLUMNS; j++) {
                    int x = j * sqSize;
                    int y = i * sqSize;
                    g.drawRect(x, y, sqSize, sqSize);

                }
            }

        }
    }

}

Take the time to read through Laying Out Components Within a Container to get a better understanding how the layout management API works

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Wow. Thanks for this. But i have some questions because i really need to understand this very well. I've read the GridBagLayout and BorderLayout from the above link. How am i supposed to know which one of all these layouts should i use? I've used (badly) the BorderLayout. You used the GridBadLayout. Also, you call the .pack() method instead of the setSize. Is it preferrable? Does the frame have any size when you call that method? – Chris Apr 01 '19 at 10:29
  • Layout choice is matter of design, you use compound layouts to achieve advanced layouts. A window has a default size of 0x0, using pack will take the preferred size of the contents and wrap the frame decorations around it - it’s important to note that the frame decorations can be different sizes depending on configuration and OS – MadProgrammer Apr 01 '19 at 10:47
  • Aha, i see. So, i could use the BorderLayout if i wanted? GridBagLayout seems very interesting though. Also, i've read this: _If you are not interested in learning all the details of layout management, you might prefer to use the GroupLayout layout manager combined with a builder tool to lay out your GUI. One such builder tool is the NetBeans IDE. Otherwise, if you want to code by hand and do not want to use GroupLayout, then GridBagLayout is recommended as the next most flexible and powerful layout manager._. I guess this answers my question about using tool and writing code at the same time. – Chris Apr 02 '19 at 11:49
  • What's more preferrable for a beginner? Using GroupLayout plus builder tool or writing by hand? As i said, i've discovered Windowsbuilder Pro and it has some potential, but it wasn't much of a help with my case. – Chris Apr 02 '19 at 11:52
  • IMHO you make the time to learn how to use the layout managers by hand. GUI editors generate poor habits and generally locks you into a single editor. GUI editors also tend to generate poor code and I’ve had my fair share of issues with group layout – MadProgrammer Apr 02 '19 at 18:29
  • Right. I would follow that. I will learn more code by doing that. One last thing. The way that you structure the code is the "normal" one? I mean, you created a class, had the main method in it and called its constructor. And in that constructor, you initialiaze your frame. I extended my class with JFrame. Is that wrong policy? – Chris Apr 05 '19 at 09:06
  • After some days, i found this link: https://docs.oracle.com/javase/tutorial/uiswing/components/frame.html. In that link i found a java file named FrameDemo which has a similar way of building code. So, i guess this is how we build it? Is this the correct way? – Chris Apr 15 '19 at 13:59