Skip to content
Advertisement

How do I stop JFrame/JPanel from auto-formatting the distances between my components?

So I’m writing a program which utilizes a GUI. The GUI is built from a JFrame and a JPanel in Java. I have a JTextArea() and a JButton() that appears beside the JTextArea on the left. I also have an image which I imported locally using the method call below (“f” is the variable name of my JFrame):

f.setIconImage(ImageIO.read(new File("image.png")));

I don’t mind allowing the users to resize the JFrame but what I dislike is that JFrame automatically reformats the components on my JFrame – specifically the distance between my image and the JTextArea(). I’d like, if possible, to keep the distance between my image and the JTextArea the same regardless of the size the user resizes the JFrame to. Here’s the rest of my code if that helps:

public class GUI {
private JFrame f;
private JPanel p;
private JButton b1;
private JLabel lab;
private JTextArea tf;

private static final String FileName = "schedule.txt";
private static final String FileName2 = "schedule2.txt";

public void show()
{
    f = new JFrame("Scheduler");
    f.setSize(600, 400);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    p = new JPanel();
    //p.setPreferredSize(new Dimension(200, 400));

    b1 = new JButton("Run");

    p.add(b1);

    f.add(p);
    f.add(p, BorderLayout.SOUTH);
    f.add(new JLabel(new ImageIcon("image.png")));
    try {
        f.setIconImage(ImageIO.read(new File("image.png")));
    } catch(Exception z){
        System.out.println("Trouble reading file");
    }

    tf = new JTextArea();
    tf.setPreferredSize(new Dimension(300, 200));

    p.add(tf);

    b1.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            String text = tf.getText();
            try {
                FileWriter fw = new FileWriter(FileName);
                fw.write(text);
                fw.close();
                parseInfo();
            }
            catch(Exception ex)
            {

            }
        }
    });
    f.setVisible(true);

}

Advertisement

Answer

There are any number of ways you “might” achieve this, but the basic answer is, you need to choose one or more layout managers which better meets your needs.

For example, using a GridBagLayout, you can do something like…

NormalResized

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.LineBorder;

public class JavaApplication1 {

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

    public JavaApplication1() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                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.gridx = 0;
            gbc.gridy = 0;
            gbc.insets = new Insets(8, 8, 8, 8);

            JLabel label = new JLabel("Image placeholder") {
                // This is done only for demonstration purposes
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(128, 128);
                }
            };
            label.setBorder(new LineBorder(Color.DARK_GRAY));

            add(label, gbc);

            gbc.gridy++;
            gbc.fill = GridBagConstraints.BOTH;
            // This will cause the text area to occupy all the avalilable free space
            //gbc.weightx = 1;
            //gbc.weighty = 1;
            JTextArea ta = new JTextArea(10, 20);
            add(new JScrollPane(ta), gbc);

            JButton btn = new JButton("Run");
            gbc.gridy++;
            // Reset the constraints
            gbc.fill = GridBagConstraints.NONE;
            gbc.weightx = 0;
            gbc.weighty = 0;
            add(btn, gbc);
        }

    }
}

Take a look at Laying Out Components Within a Container for more details and ideas

Recommendations…

There are a few things in your code that are, “off”, but this…

tf = new JTextArea();
tf.setPreferredSize(new Dimension(300, 200));

p.add(tf);

is probably the most striking.

Generally speaking, JTextArea will benefit from been wrapped in a JScrollPane. Also, due to the inconsistencies in how text is rendered across multiple platforms, you should avoid using setPreferredSize (in fact, you should avoid using it in general) and instead rely in the rows, columns constructor, which will make calculations based on the current font and graphics properties.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement