Setting a control's location and dimension in Swing - java

Coming from Windows Forms (.net), I'm tempted to write the following code:
JFrame frame = new JFrame();
frame.setSize(new Dimension(300, 200));
frame.setVisible(true);
JList list = new JList();
list.setLocation(new Point(50, 50));
list.setSize(new Dimension(100, 100));
list.setVisible(true);
frame.add(list);
JButton button = new JButton();
button.setLocation(new Point(0, 0));
button.setSize(new Dimension(50, 50));
button.setText("myButton");
button.setVisible(true);
frame.add(button);
That should create a window (frame) with a 300x200 size and a list and a button at (50,50) and (0, 0).
Yet when I run the code, all I see is a button (covering the whole area). I guess this must have some special layout system, but I'd like to know how to just put the controls in the specified (x,y) locations with the specified (w,h) dimensions.
Thanks

You need to use Layout Managers:
http://download.oracle.com/javase/tutorial/uiswing/layout/using.html
Although you might be tempted to manually specify a location and size, I would recommend against this unless absolutely necessary. It might seem like learning to use a layout manager is a waste, but the investment will be worth it in the long run.

Using Swing, if you don't specify any layout manager to a top-level container, BorderLayout is used. This layout manager gives you the result you have.
If you want to use absolute positioning, you have to disable the default layout manager first:
frame.setLayout(null);
Then, you can place your components.

What you would be looking for here is a null layout manager.
If you are looking to specify the exact size and location of the objects, then you can use your approach from above.
Take a look at this article
http://www.tech-recipes.com/rx/1205/java-null-layout-manager-swing/
The author, has the same type of example as you, the major difference is the addition of the line
getContentPane().setLayout(null);
In your current implementation you have the default layout, so you would just be layering the list and button on top of each other.

You need absolute positioning. Just set the container's layout manager to null by calling setLayout(null).
Here is the link:
http://download.oracle.com/javase/tutorial/uiswing/layout/none.html

Related

JPanel button is not at the correct place

i made a custom JFrame for the desktop application and i added a JPanel on the very top of the app to serve as a subtitute of the title box. the problem is when i added a button it located right in the middle of the JPanel instead of the usual left top. AND it would not move even if i set it at a different location.
here is the code:
JFrame f = new JFrame("Hello");
f.setResizable(true);
JPanel pa = new JPanel();
JButton btn = new JButton("Exit");
btn.setBackground(Color.white);
btn.setText("Button");
btn.setSize(300, 80);
btn.setLocation(50, 0);
pa.setBackground(Color.red);
pa.setPreferredSize(new Dimension(width,60));
pa.add(btn);
f.setBackground(Color.white);
f.setUndecorated(true);
f.getContentPane().add(pa, BorderLayout.NORTH);
f.setSize(new Dimension(width,height));
f.setLocation(200, 200);
f.setVisible(true);
You use a BorderLayout in the frame. You can do the same thing in the panel.
pa.setLayout(new BorderLayout());
pa.add(btn, BorderLayout.WEST);
In general, setLocation tends to fight against the layout manager, so you usually don't want to use it unless you're going to position everything by hand.
that is one way to do it, but BorderLayout way is not very good way because i also want to add another button next to it.
Then what this might need is a FlowLayout using FlowLayout.LEADING as the alignment.
But as general tips:
Provide ASCII art or a simple drawing of the intended layout of the GUI (showing all components) at minimum size, and if resizable, with more width and height - to show how the extra space should be used.
For better help sooner, post a
Minimal, Complete, and Verifiable example or Short, Self Contained, Correct Example of your attempt.

jLabel and jTable conflict [duplicate]

I am extremely new to Java Swing, and I'm having quite a bit of issues getting a nice layout going. I have checked out google, and even other answers on this website, but no information I find seems to solve the issue. Here is the result of my efforts:
As you can see, the label, text field, and button are all out of alignment. It is my goal for all of them to have the same left-hand border, and for the button and text field to have the same right-hand border, with these left and right hand borders being each the same distance from the left and righthand sides of my window.
Here are the important parts of my code:
public void run()
{
JFrame frame = new JFrame("Arduino Server");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
InstancePanel = new ServerGUIPanel();
frame.getContentPane().add(InstancePanel);
frame.pack();
frame.setVisible(true);
}
And, in ServerGUIPanel.java:
public ServerGUIPanel()
{
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setPreferredSize(new Dimension(500, 500));
setBorder(new EmptyBorder(10, 10, 10, 10));
StatusLabel = new JLabel("STATUS: BOOTUP");
add(StatusLabel);
PortField = new JTextField();
PortField.setPreferredSize(new Dimension(5000, 20));
PortField.setMaximumSize(PortField.getPreferredSize());
PortField.setActionCommand("PortChanged");
add(PortField);
ConnectionButton = new JButton();
ConnectionButton.setPreferredSize(new Dimension(5000, 20));
ConnectionButton.setMaximumSize(ConnectionButton.getPreferredSize());
ConnectionButton.setActionCommand("ConnectionClicked");
add(ConnectionButton);
}
Does anyone have a simple solution to this? What am I doing wrong here?
Thank you very much!
--Georges Oates Larsen
Read the section from the Swing tutorial on How to Use BoxLayout for the basics of using a BoxLayout as well as a section on alignment issues.
Basically you need to make sure the alignmentX value of all components is set to be left aligned.
Also:
Don't use setPreferredSize() to set the size of a component. Each Swing component will determine its own preferred size.
Use Java naming conventions. Variable names should NOT start with an upper case character.
I would not recommend using setPreferredSize() AND setMaximumSize(). The latter will cause problems when stretching your main frame. [Your components will likely not want resize]
You should be using layout managers to handle all the alignments itself. I would stay away from using BoxLayout in this case, as different components want to size differently, and that will sway the alignment when added into your BoxLayout panel.
Moreover, you might want to give your main frame a layout as well.
Can you post how you used your GridBagLayout?

Adding panel with without layout to the NORTH of BorderLayout

Colleagues.
I'm trying to construct simple GUI in Java, where JFrame has Border Layout. I want to put JScrollPane with JTable to CENTER, and JPanel without layout to NORTH.
The problem is that JPanel doesn't visible. There is simple examle of the problem:
JFrame frame = new JFrame("Test frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Test button");
button.setBounds(10, 10, 40, 20);
JPanel panelN = new JPanel(null); // layout = null, panelN without layout
panelN.add(button);
frame.add(panelN, BorderLayout.NORTH);
JTable table = new JTable(new DefaultTableModel(4, 4));
JScrollPane scrollPane = new JScrollPane(table);
frame.add(scrollPane, BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setVisible(true);
You have to use a LayoutManager. It's totally discouraged not using layoutManager, but if you want this you have to set panel.setBounds(..) to the panel too.
By default JPanel has FlowLayout so if you put
JPanel panelN = new JPanel(); // FlowLayout used
panelN.add(button);
frame.add(panelN, BorderLayout.NORTH);
So your frame will look like this.
Layout Managers determines the size and position of the components within a container. Although components can provide size and alignment hints, a container's layout manager has the final say on the size and position of the components within the container.
It's strongly recommended cause for example if you have to resizes components or show in differentes resolutions you delegate this work to layout managers
I don't know the expected behavior of a null layout, but without further requirements you might as well just instantiate with the zero-arg constructor:
new JPanel();
If you didn't set any layout to the panel, when adding components the panel don't know where to put the component, so baisicly the component don't show until you set a specific location for components one by one by component.setBounds(x,y,width,hieght) method.
Note that it's not a good practice to remove the layout manager because of the different platformes, suppose that your program working on Window and MacOS and Linux, you'v better to use the layout managers instead.
Take a look at this post also and see #Andrew Thompson's comment on my answer:
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. For a robust GUI, instead
use layout managers, or combinations of them, along with layout
padding & borders for white space, to organize the components.
After all:
If you have a requirement or an assignment telling you you must use absolute layout, then use it, otherwise avoid it.
It is OK to use containers with no layout manager because you actually CAN set container's layout to NULL. And it's a nice idea to position your components with setBounds(). But in this case, you just have to consider your container. What size it need to be? A layout manager would calculate this for you, and if you don't have one, you have to set the size of your panel by yourself, according to components you have added to it.
As pointed by others here, the case it that the border-layout manager of your frame needs the preferred size of your NORTH panel (actually, the preferred height). And you have to set it, or values will be zeros and the container will become invisible. Note that for the CENTER panel this is not needed as it gets all space possible.
I had a problem like yours before and have written a fast function to resize a container according to bounds of a given component. It will be as large as needed to show this component, so dimension (w,h) and position (x,y) are considered. There's an "auto-resize" version that can be used once, after all components are added.
public static void updatePreferredSize(Container cont, Component comp) {
int w = cont.getPreferredSize().width;
int h = cont.getPreferredSize().height;
int W = comp.getBounds().x + comp.getBounds().width;
int H = comp.getBounds().y + comp.getBounds().height;
if (W>w||H>h) cont.setPreferredSize(new Dimension(W>w?W:w, H>h?H:h));
}
public static void autoPreferredSize(Container cont) {
for (Component comp : cont.getComponents())
updatePreferredSize(cont, comp);
}
You can use updatePreferredSize() after adding every component to a panel, or use autoPreferredSize() once, after all addings.
// [...]
panelN.add(button);
updatePreferredSize(panelN, button);
// [...]
// or...
// [...]
autoPreferredSize(panelN);
// [...]
frame.setVisible(true);
This way, if you do not set you north panel height with a fixed value, with help of these functions you can expect your button will be visible according the position you set it with setBounds().

Glue Equivalent in MigLayout

I am using MigLayout and I would like to create an effect like using BoxLayout's "glue" to create an invisible space that will flexibly fill the area between two components. From the tutorial:
I understand that in MigLayout, gaps are used to create spaces between components. I can create a rigid space with "gap 10". The MiG Layout Cheatsheet says that I can append push to a bound size with a gap to "make that gap "greedy" and take any left over space" (e.g. "gap rel:push"), but that doesn't seem to work in the following code that I've tried:
JFrame frame = new JFrame("Test");
JPanel panel = new JPanel(new MigLayout());
JLabel label1 = new JLabel("Testing");
label1.setBorder(BorderFactory.createLineBorder(Color.black)); //Border to clearly show JLabel boundaries
panel.add(label1, "");
JLabel label2 = new JLabel("Testing Once Again");
label2.setBorder(BorderFactory.createLineBorder(Color.black)); //Border to clearly show JLabel boundaries
panel.add(label2, "gap rel:push");
frame.setContentPane(panel);
frame.pack();
frame.setMinimumSize(new Dimension(400, 100));
frame.setPreferredSize(new Dimension(400, 100));
frame.setVisible(true);
Which displays a window like this:
I would expect for the "gap rel:push" parameter to work like horizontal glue in the picture above and thus push the JLabel on the right all the way to the right edge of the window, but it doesn't.
How can I get the same effect as BoxLayout's glue using MigLayout? Am I misusing the "gap" parameter or is there some other way to accomplish it?
Also, I realize that I could use docking in the example given, but I'd like an answer without that because it won't work in a more complex layout I'm creating.
Save yourself some sanity points and enable debug borders on the MiGLayout: new MigLayout("debug").
It's possible that the gap is indeed pushing the components apart, but the layout isn't using all of the available space. This should be obvious if you turn on debug borders. Try making the layout use all available space: new MigLayout("debug, fill").
Instead of placing a gap between your label and the cell edge, you may want to place a gap between the two columns: new MigLayout("debug, fill", "[]rel:push[]"). The difference should become clear when using a multi-row layout. In this case, you may not need the fill constraint: new MigLayout("debug", "[]rel:push[]").
I don't have a compiler handy to run this against, but I hope I've given you something to work with.

Java GUI layout problems

I'm writing a small Java GUI program, and I'm having some issues with Java not laying things out properly. I haven't done much Java GUI code lately, so I'm having trouble seeing where the problem lies.
final JFreeChart chart = createChart(dataset);
final ChartPanel chartPanel = new ChartPanel(chart, false);
chartPanel.setPreferredSize(new Dimension(500, 270));
JPanel buttonPanel = new JPanel();
buttonPanel.setPreferredSize(new Dimension(500,50));
JButton toggleButton = new JButton("Toggle");
final JTextField minRange = new JTextField("10");
final JTextField maxRange = new JTextField("1000");
JButton setLimits = new JButton("Set Limits");
buttonPanel.add(toggleButton, BorderLayout.NORTH);
buttonPanel.add(minRange, BorderLayout.SOUTH);
buttonPanel.add(maxRange, BorderLayout.SOUTH);
buttonPanel.add(setLimits);
JSplitPane jsp = new JSplitPane(JSplitPane.VERTICAL_SPLIT, chartPanel, buttonPanel);
jsp.setDividerLocation(0.8);
setContentPane(jsp);
What's happening here is that all of the layout options are completely being ignored. The GUI components are showing up properly, and the divider specifically is ignoring the preferred size of JFreeChart, and squeezing it to about 5% of space at the top of the frame.
In addition to problems with the splitpane not respecting your desired sizes, you are using BorderLayout constants but you haven't specified the layout for the panel (the default is FlowLayout).
This:
JPanel buttonPanel = new JPanel();
Should be:
JPanel buttonPanel = new JPanel(new BorderLayout());
I believe that using a float proportion on JSplitPane only works once the split pane is "realized", otherwise you're getting a proportion of zero because it doesn't know how big its going to be.
also:
buttonPanel.add(minRange, BorderLayout.SOUTH);
buttonPanel.add(maxRange, BorderLayout.SOUTH);
BorderLayout only allows one component to be in each area, so min range will never appear, as maxRange is now "the" south component. if you want both you'll need to put those 2 components in another panel, then add that panel to the south.
Try setting the minimum size too.
See: Java GUI Problems
JSplitPane pays attention to the minimum size, not the preferred size. Try simply changing setPreferredSize to setMinumumSize.
Dan Dyer is correct, you didn't set the Layout.
You could also set it by buttonPanel.setLayout(new BorderLayout())
And John Gardner is correct that you set a component to BorderLayout.SOUTH twice.
Also check out MigLayout if you don't already know about it. Its the least "surprising" layout manager I've ever used. It just works. It takes some learning, but very straight forward once you get over the syntax.
And I would avoid SplitPane if you can...its very finicky
Never call setPreferredSize() - it should be a calculation.
For example, your ButtonPanel is being set to a fixed preferred size.
What if you add I18N support and the user is using a language with very long localizations? What if the user resizes the frame?
Check out my article on layout managers for details on how you should really use them. It's from 1999 but still applies:
http://java.sun.com/developer/onlineTraining/GUI/AWTLayoutMgr/
Enjoy!

Categories