Adding panel with without layout to the NORTH of BorderLayout - java

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().

Related

Java Layout Problems

In a project of mine I have been trying to add a JConsonle to a JPanel witch is contained by another JPanel.
The problem is that the JConsole keeps being set 5px from the top of the JPanel.At first I tought it was the container that wasent beeing set up right but after giving it a red background I realised that the console is being set 5px from the top.
I've also tried to use BorderLayout to set it in the NORTH or CENTER of the JPanel but that
dosent work either.
This is my code:
public class MonopolyPanel extends JPanel {
JPanel consoleP = new JPanel();
JConsole console = new JConsole();
MonopolyPanel(){
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
console.setPreferredSize(new Dimension(530, 300));
consoleP.add(console);
this.add(consoleP);
}
}
The console is added to consoleP which has FlowLayout by default, which by default has a vertical and horizontal gap of 5px. Instantiating that with a FlowLayout with zero gaps should do the trick
consoleP == new JPanel(new FlowLayout(align, 0, 0));
From my experience, the best and most flexible layout is GridBagLayout.
99% of panels in Swing I make are GridBagLayout, otherwise its impossible to get it all right.
Because with that layout, you can set weights, exact padding and spacing parameters.
The other layoutmanagers are to limited and not very configurable.
Have you looked at Borders?
It's possible you need to set the JPanel's or the JConsole's border to an EmptyBorder, like so:
component.setBorder(BorderFactory.createEmptyBorder());
You might also look for something about insets in the Javadocs.

Change the height of a panel at runtime

How to change the height of panel at runtime?
I have some panels inside a JFrame, I tried on one of them:
int w = panel.getWidth();
panel.setSize(w, 1000);
But there's no effect. What's wrong?
You may have to validate and repaint your panel. Try following:
int x=panel.getWidth();
panel.setSize(x,1000);
panel.validate();
panel.repaint();
Check out this answer:
set size wont work in java
"In Swing, you have two options for layout: do everything manually or let a LayoutManager handle it for you."
and
"Try calling setPreferredSize() and setMinimumSize()."
If you are using a layout manager (you probably are), the layout decides what to do with the
contained components. setPreferredSize() usually works because the layout usually asks the
contained components what their preferred sizes are, and then arranges the components
based on (among others) that information.
If you put the panel in a LayoutManager (i.e. the parent has a LayoutManager which is BorderLayout by default) that LayoutManager would override the size and thus your call would have no effect.
Try to call setLayoutManager(null) on the parent although I'd recommend using a LayoutManager and use setPreferredSize(), setMinimumSize() and setMaximumSize().
For changing width and height of JPanel use setPreferredSize method.
JPanel folderPanel = new JPanel();
folderPanel.setPreferredSize(new Dimension(245, 450));// width, height
You just set the visibility of this component (JPanel) as follow:
JPanel panel = new JPanel();
//set your custom size in this with=120; height=570;
panel.setSize(120,570);
panel.setVisible(false);
panel.setVisible(true);
//hope this help! :)

Problem with FlowLayout

public class MyFrame extends JFrame
{
public MyFrame(String title)
{
setSize(200, 200);
setTitle(Integer.toString(super.getSize().width));
setLayout(new FlowLayout());
for (int i = 0; i < 5; ++i)
{
JButton b = new JButton();
b.setSize(90,50);
b.setText(Integer.toString(b.getSize().width));
this.add(b);![alt text][1]
}
this.setVisible(true);
}
}
why if having button widht 90 I'm getting window where three buttons are in one row instead of two?
FlowLayout will lay out Components left-to-right (or right-to-left) wrapping them if required. If you wish to explicitly set the size of each JButton you should use setPreferredSize rather than setSize as layout managers typically make use of the minimum, preferred and maximum sizes when performing a layout.
Size properties are quite confusing - There is an interesting article here. In particular, note:
Are the size properties always
honored?
Some layout managers, such as
GridLayout, completely ignore the size
properties.
FlowLayout, attempts to honor both
dimensions of preferredSize, and
possibly has no need to honor either
minimumSize or maximumSize.
The FlowLayout just places component one beside the other in a left-to-right order. When the width reaches the one of the container that has that layout it simply wraps on the other line.
If you want to arrange them in a grid-style layout (like it seems you want) you can use the GridLayout that allows you to specify the number of columns and rows:
component.setLayout(new GridLayout(2,2))
The only downside of GridLayout is that every cell of the grid will be of the same size (which is usually good if you just have JButtons or JLabels but when you mix things it will be visually bad).
If you really need more power go with the GridBagLayout, very customizable but with a steeper learning curve at the beginning.
Probably your size problem is related to the fact that you are using setSize but in Swing these things have strange behaviours, you should try by setting setPreferredSize(200,200) instead of setSize. But don't ask me why!
NOTE: you should ALWAYS refer to the frame's content pane and not to the frame it self. When you set layout you should do getContentPane().setLayout(..), when you add items you should do getContentPane().add(..) and so on.
Errata: now every JFrame add, remove, setLayout automatically forward to the content pane.
For one thing, you're not using JFrame correctly: you don't add components directly to the frame, you add them to a JPanel that you then pass to the frame with setContentPane().
Also: it's not very elegant to directly subclass JFrame just to add components. Instead, create your frame as a separate object.

Java Simple Question about working with JPanels

Just a quick question here. I have a program in which I need to create a number of JPanels, which will then each contain some objects (usually JLabels).
There are a few operations that I have to do each time i create a new JPanel, and I'm wondering if the order in which I do them has any bearing, or if there is a standard practice.
The operations I do are the following:
Declare the JPanel: JPanel panel = new JPanel(...)
Declare the JLabel: JLabel laberl = new JLabel...
Add the JPanel to some other content pane: frame.getContentPane().add(panel)
Set the bounds of the JPanel: panel.setBounds(...)
Add the JLabel to the JPanel: panel.add(label)
In general order isn't important as long as you add all the components to the panel and the panel is added to the content pane "before" you make the frame visible.
The standard practice is to use a layout manager, so there would be no need to set the bounds of the panel you added to the content pane.
The order doesn't matter. However, after creating and adding everything, you need to call revalidate() on the panel (or pack() on its parent window) so that the layout manager (I presume you're using one!) arranges the components as they should be.
Have a method createPanel() that returns the panel with all its children added.
Panel p = createPanel();
p.setBounds(...); // if you must
frame.getContentPane().add(p);
And then
Panel createPanel() {
Panel p = new Panel();
Label l = new Label("Heading");
p.add(l);
return p;
}
The order of constructing and adding items isn't important, except that when you add children, you should add them in the order you want them in the panel.

Can you set a permanent size for a JPanel inside of a JFrame?

My current problem is that I have a JFrame with a 2x2 GridLayout. And inside one of the squares, I have a JPanel that is to display a grid. I am having a field day with the java swing library... take a look
Image
Java is automatically expanding each JLabel to fit the screen. I want it to just be those blue squares (water) and the black border and not that gray space. Is there a way I can just set the size of that JPanel permanently so that I don't have to go through changing the size of the JFrame a million times before I get the exact dimension so that the gray space disappears?
I also would like to set the size of those buttons so they are not so huge (BorderLayout is being used for the buttons and TextField)
GridBagLayout is what you really want to use. The GridLayout will force the same size for each component in the layout no matter what size constraints you put on them. GridBagLayout is a lot more powerful and a lot more complicated. Study up on the API page for it. Using GridBagLayout, the components won't fill the whole grid space if you don't want them to and can even stay the size that you ask it to be. To keep a component's size from changing, I would set all three available size constraints:
water.setPreferredSize(new Dimension(20, 20));
water.setMinimumSize(new Dimension(20, 20));
water.setMaximumSize(new Dimension(20, 20));
For your buttons, I would definitely use an inner panel as Bryan mentions. You could use either a GridLayout like he suggests or a FlowLayout if you don't want all the buttons to be the same size. Add all your buttons to that inner panel instead of the main one.
If you want the two checkerboards to stay the same size, then you'll need to have them each contained in their own JPanel. Set each of those parent JPanel's to have a layout type of GridBagLayout. Set the preferedSize for each checkerboard component and then add them to their respective containers. GridBagLayout should by default lay each board out in the center of the parent JPanel. So as the window is resized, the JPanel parent area will get larger or smaller, but the checkerboard components inside will remain the same size.
Alternatively, you could have your blue squares scale to the right size as the window is resized by having each checkboard square be a JPanel with a BorderLayout layout manager and adding the JLabel (with a blue background color) to its BorderLayout.CENTER location.
As for your buttons, try something like this:
JPanel theButtonPanel = new JPanel(new BorderLayout());
JButton button1 = new JButton("Fire");
JButton button2 = new JButton("Pass");
JButton button3 = new JButton("Forfiet");
JPanel innerButtonContainer = new JPanel(new Grid(1, 3, 8, 8));
innerButtonContainer.add(button1);
innerButtonContainer.add(button2);
innerButtonContainer.add(button3);
theButtonPanel.add(innterButtonContainer);
Lastly, consider using a design tool for your Swing user interface. Netbeans has an excellent UI designer built into it. Download Netbeans here.
If you can setResizeable( false ) on the top level frame you can then set your layout manager to null and hard code each location and size via setBounds. This is how I would do it (contingent on resizing of course).
I have had success solving problems like these using TableLayout which is a third party layout manager. You will need to download it and read the tutorial but the key would be to set the justification to CENTER when adding the JButtons to their positions in the layout.

Categories