0

I'm working on a Java GUI and I have a JFrame thats 600x800 that I want to split into two portions, the top which has checkboxes for settings and is 600 x 200 and the bottom which is the "canvas" which will be painted on that is 600x600. I have a JFrame that has a JPanel that contains two other JPanels (one for the settings, the other for the canvas). I'm testing the "painting" and for some reason when I try to paint a 600x600 black rectangle, it paints a much smaller rectangle in the area that the settings JPanel occupies. Any ideas what's going on? I'm using the repaint method to call paintComponent and I've tried calling repaint in both the constructor of my JFrame and in the JPanel that is to be painted.

HPAProgram

public class HPAProgram {
    public static void main(String[] args) {
        MapWindow map = new MapWindow();        
    }
}

MapWindow

//import java.awt.*;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.*;

import javax.swing.*;  //notice javax
public class MapWindow extends JFrame
{
    private static final int WIDTH = 600, HEIGHT = 800;

    JPanel panel = new JPanel();
    SettingsButtonsPanel button_panel = new SettingsButtonsPanel();
    MapImagePanel map_panel = new MapImagePanel();
    public MapWindow()
    {

        setLocationRelativeTo(null);
        setTitle("HPA* Test");
        setSize(WIDTH, HEIGHT);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        add(panel);
        panel.setBounds(0, 0, 600, 800);
        //panel.setLayout(new GridBagLayout());
        /*GridBagConstraints c = new GridBagConstraints();
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 0;*/

        panel.add(button_panel);

        /*c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 1;*/

        panel.add(map_panel);

        button_panel.setLocation(0,0);
        /*map_panel.setLocation(0,200);
        map_panel.setSize(600,600);*/
        map_panel.repaint();

    }

}

SettingsButtonsPanel

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class SettingsButtonsPanel extends JPanel implements ItemListener{
    private static final int WIDTH = 600, HEIGHT = 200;
    private static final int NUM_MAP_TYPE = 2;

    private JCheckBox[] map_type;

    JPanel panel = new JPanel();

    public SettingsButtonsPanel(){

        this.setLayout(new GridBagLayout());

        GridBagConstraints c = new GridBagConstraints();

        this.setBounds(0,0,WIDTH, HEIGHT);

        map_type = new JCheckBox[NUM_MAP_TYPE];

        map_type[0] = new JCheckBox("Sparse");
        map_type[0].setSelected(true);
        //map_type[0].setSize(100,100);


        map_type[1] = new JCheckBox("Maze");
        map_type[1].setSelected(false);
        //map_type[1].setSize(100,100);

        for(int i = 0; i < NUM_MAP_TYPE; i++)
        {
            map_type[i].addItemListener(this);
            c.fill = GridBagConstraints.HORIZONTAL;
            c.gridx = 0;
            c.gridy = i;
            this.add(map_type[i], c);
        }
    }

    public void itemStateChanged(ItemEvent e)
    {
        Object source = e.getItemSelectable();
        //if(source == )
    }
}

MapImagePanel

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class MapImagePanel extends JPanel{
    public MapImagePanel()
    {
        this.setBounds(0,200, 600,600);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.fillRect(0,0,600,600);
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
zaloo
  • 879
  • 3
  • 13
  • 27
  • 2
    Make use of appropriate layout managers. Don't use setBounds, instead override getPreferredSize to provide appropriate size hints to the layout manager – MadProgrammer Jan 14 '14 at 20:23
  • I don't understand why I'd use getPreferredSize instead in this instance. I know exactly what sizes i need and they aren't going to change, why should I override getPreferredSize? Sorry if I'm being dense :P – zaloo Jan 14 '14 at 20:28
  • To expand on the advice of @MadProgrammer. Java GUIs might have to work on a number of platforms, on different screen resolutions & using different PLAFs. As such they are not conducive to exact placement of components. To organize the components for a robust GUI, instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556), along with layout padding & borders for [white space](http://stackoverflow.com/q/17874717/418556). – Andrew Thompson Jan 14 '14 at 20:31
  • *"I know exactly what sizes i need.."* Hmmm.. *"Paint in JPanel is painting in the wrong location and size"* ..might suggest you don't know as well as you *think* you do. O_o – Andrew Thompson Jan 14 '14 at 20:36
  • @AndrewThompson Could it be that he does know it but he cannot make his code to obey those constraints? – mostruash Jan 14 '14 at 20:38
  • I had the MapWindow class using a layout manager but I removed it while I was debugging the paint issue. I'm using a layout manager for SettingsButtonsPanel and I am not putting any JComponents inside of MapImagePanel. It seems like I'm doing what you've mentioned, but I'm not sure if I understood you correctly. Also, how would you set the size of a JPanel if not using setBounds? If I know exactly how big my panel and "sub-panels" need to be, what is the proper way to set the size of the panels? Thanks for the help! – zaloo Jan 14 '14 at 20:40
  • @mostruash Many things 'could be'. If the OP were to post an [MCVE](http://stackoverflow.com/help/mcve) as well as Provide ASCII art (or an image with a simple drawing) of the GUI as it should appear in smallest size and (if resizable) with extra width/height, then we can turn maybes into something more tangible. But for the moment, I am knocking off for the day. – Andrew Thompson Jan 14 '14 at 20:40
  • @mostruash That's exactly it! The look I want is very intuitive, I'm just having trouble getting my GUI to represent what I want. All I want is a 600x800 panel divided into two Jpanels split with a horizontal line, the top one being 200 pixels tall and the bottom one being 600 pixels tall. When I try to paint the bottom panel black, the rectangle is too small. I'm not sure why, which why I pasted all of my code I have so far. – zaloo Jan 14 '14 at 20:43
  • @mostruash As an aside, I suggest sizes for the chess board pieces in [this GUI](http://stackoverflow.com/questions/21077322/create-a-chess-board-with-jpanel/21096455#21096455) by (first) adding a transparent icon to each square. It is also possible to use an image as a rendering surface, which allows us to side-step having to extend or set a preferred size to anything. ;) – Andrew Thompson Jan 14 '14 at 20:44

1 Answers1

2

The are a number of misconceptions you seem to have...

JPanel, by default uses a FlowLayout. FlowLayout makes use of each of the components preferred size to determine the size of each component. By default, a component has a preferred size of 0x0.

The layout manager is also responsible for positing the components, so using setBounds and setLocation and setSize is counter productive.

Assuming the size is also not always possible, especially when dealing with text, as this can change size based on differences in the fonts, display drivers, rendering pipelines etc...

This is why Java makes extensive layout managers. Take a look at Laying Out Components Within a Container for more details

Update with simple example

Don't be afaird to mix layouts, using compound components with different layouts, to achieve your desired results, for example...

SimpleLayout

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SimpleLayout100 {

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

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

                JPanel header = new JPanel();
                header.add(new JLabel("Hello, I'm the header"));

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(header, BorderLayout.NORTH);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(600, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.GREEN);
            g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
            g2d.setColor(Color.RED);
            g2d.fillRect(150, 50, 300, 100);
            g2d.dispose();
        }
    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • 1
    So what you're saying is I should abandon my idea of setting each panel to a specific size and let the layoutmanager do its thing? I'll give that a try and let you know if it fixes my paint issue – zaloo Jan 14 '14 at 20:50
  • @zaloo Although I also suggest that you should read about layout managers and use them extensively, you can also set the layout manager of your `JPanel` to null and use `setBounds` etc. http://docs.oracle.com/javase/tutorial/uiswing/layout/none.html – mostruash Jan 14 '14 at 20:50
  • I'm honestly confused on how to use the layout manager to get my panels to become smaller or larger. I want my top panel to be as small as possible but I have no clue how to do that – zaloo Jan 14 '14 at 20:57
  • Check the available link in answer and update example – MadProgrammer Jan 14 '14 at 22:30
  • 1
    @mostruash The only time I would even consider using a `null` layout manager is if I were animating components or were replicating my own windowing system. Otherwise, `null` managers introduce and considerable overhead of complexity and management... – MadProgrammer Jan 14 '14 at 22:31
  • @MadProgrammer Most of the time, software GUIs are designed to be rectangular flows of smaller pieces of rectangular GUIs. Consider stackoverflow, in a rectangular browser window, there is a rectangular panel at the top, another one at the righthand side etc. However one may decide on a hyperbolic (huh?) or totally non-patterned UI design in which case layout managers of Java would not help much. My point is, I would try to avoid bold statements. – mostruash Jan 14 '14 at 22:47