-1

I am just throwing together a quick and dirty GUI to display some data when I ran into an odd issue. The last label I add to the JFrame doesn't want to be positioned or display the border I put on it, so it looks like this:

Here is my code:

public DisplayData (Connection tConn)
{
    ID = tID;
    conn = tConn;

    setupObjects();
    setupFrame();
}

private void setupObjects()
{
    JLabel caseLabel = new JLabel ("Case #:");
    JLabel dateLabel = new JLabel ("Date:");
    JLabel reportLabel = new JLabel ("Report:");
    JLabel offenceLabel = new JLabel ("Offence:");
    JLabel descriptionLabel = new JLabel ("Description:");

    this.add(caseLabel);
    this.add(dateLabel);
    this.add(reportLabel);
    this.add(offenceLabel);
    this.add(descriptionLabel);

    caseLabel.setBounds(50, 50, 130, 25); //x, y, width, height
    dateLabel.setBounds(50, 100, 130, 25);
    reportLabel.setBounds(50, 150, 130, 25);
    offenceLabel.setBounds(50, 200, 130, 25);
    descriptionLabel.setBounds(100, 50, 130, 25);

    caseLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    dateLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    reportLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    offenceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    descriptionLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
}

private void setupFrame()
{
    this.setTitle("Data Display");
    this.setSize (650, 700); //Width, Height
    this.setLocation(300, 10);
    this.setResizable(false);
    this.setVisible(true);
    this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    this.setLayout(null);
}

Yes, I know I should be using a proper layout manager, but like I said i just wanted something quick and dirty. Plus, I will not be beaten by something that should be this simple. Any ideas would be appreciated.

EDIT: As Compass and Neophyte pointed out, my order of operations was off. Flipped my method calls and all is good again in the world. Thanks for the 2nd pair of eyes.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
WickedChester
  • 35
  • 1
  • 5
  • Order matters. Don't set the bounds of the items until the frame's size is set. By running setupFrame first and then setupObjects, works as expected. – Compass Oct 25 '17 at 19:52
  • 5
    Two words - layout managers. Sure its "quick" and "dirty" to do it manually, but it's takes longer, increases the number of "unexpected" issues and is generally just a complete waste of time. Focus more on the flow of information/interaction then the "pixel perfect" layout, different platforms/PCs will make a mess of "pixel perfect" layouts. In short, `null` layouts are never the answer, even when you think they are, they're not – MadProgrammer Oct 25 '17 at 20:01

2 Answers2

2

Contrary to the original poster's strategy, or any of the answers so far, the best approach to this problem is to use layouts.

Here is an example that shows how easy it is to position fields using layouts, and to change the GUI on later updates to the specification.

enter image description here

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

public class CourtDetailsGUI {

    private JComponent ui = null;
    static final String[] FIELD_NAMES = {
        "Case #:",
        "Date:",
        "Report:",
        "Offence:",
        "Plaintiff:",
        "Defendant:"
    };

    CourtDetailsGUI(int num) {
        initUI(num);
    }

    public void initUI(int num) {
        if (ui != null) {
            return;
        }

        ui = new JPanel(new BorderLayout(4, 4));
        ui.setBorder(new EmptyBorder(4, 4, 4, 4));

        ui.add(getFieldsPanel(num), BorderLayout.PAGE_START);

        JTextArea ta = new JTextArea(5, 40);
        JScrollPane sp = new JScrollPane(ta);
        JPanel p = new JPanel(new GridLayout());
        p.add(sp);
        p.setBorder(new TitledBorder("Details"));
        ui.add(p);
    }

    private JPanel getFieldsPanel(int num) {
        JPanel outerPanel = new JPanel(new FlowLayout());
        JPanel innerPanel = new JPanel(new GridLayout(0, 1, 15, 15));
        outerPanel.add(innerPanel);
        for (int ii=1; ii<num; ii++) {
            JLabel l = new JLabel(FIELD_NAMES[ii]);
            l.setBorder(new LineBorder(Color.BLACK));
            innerPanel.add(l);
        }

        return outerPanel;
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception useDefault) {
                }
                for (int ii=0; ii<FIELD_NAMES.length; ii++) {
                    CourtDetailsGUI o = new CourtDetailsGUI(ii+1);

                    JFrame f = new JFrame("Data " + (ii+1));
                    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                    f.setLocationByPlatform(true);

                    f.setContentPane(o.getUI());
                    f.pack();
                    f.setMinimumSize(f.getSize());

                    f.setVisible(true);
                }
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 1
    While your answer is factually correct, it doesn't actually address the OP's question of why the JLabel is ignoring its bounds in a null layout. I have never used a null layout in practical use, but that doesn't change the fact that we should understand why this doesn't work, even with BorderLayout, since the default `add` is being used on a JFrame that is originally set to BorderLayout. – Compass Oct 26 '17 at 17:36
  • 1
    @Compass See [Is “Don't do it” a valid answer?](https://meta.stackexchange.com/questions/8891/is-dont-do-it-a-valid-answer) – Andrew Thompson Oct 26 '17 at 18:32
  • 1
    @Compass "the OP's question of why" - Did the OP really ask that somewhere? I don't see it. – Stefan Pochmann Oct 27 '17 at 03:31
0

Your order of operations is incorrect.

You initially call setupObjects();

This plays your objects out onto a JFrame, which has the default LayoutManager of BorderLayout.

By using the default add(Component comp) method, with BorderLayout, you end up putting the component into null for BorderLayout, which is not supposed to be normal. Furthermore, the reason you can't see the border for this object is because the border is actually the size of the frame. If you explicitly set a region for BorderLayout, then you'll see it work, but setting to no region seems to just break BorderLayout.

Additional add calls appear to free the previous item from the BorderLayout null management, allowing the bounds to take over.

Afterwards, you call setupFrame(); which removes the layout manager, but does not refresh what is currently rendered.

This sets the layout to null, which does nothing to how the frame is displayed, but just removes the layout.

To avoid this issue, call setupFrame(); prior to setupObjects();, and then setVisible(true) can be called at the end of setupObjects();

Compass
  • 5,867
  • 4
  • 30
  • 42