I'am using panel with absolute layout (don't ask why) and I need to add elements on it programmatically. I done that part, but now I want to surround panel with JScrollPane so that when user add more items, scroll bar does its job. But surrounding panel with scroll bar doesn't work. What can I do here.
JFrame frame = new JFrame();
frame.setSize(582, 451);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(10, 11, 546, 391);
frame.getContentPane().add(scrollPane);
JPanel panel = new JPanel();
scrollPane.setViewportView(panel);
panel.setLayout(null);
for(int i=0;i<labelList.size();i++){
if(a==4){
a=0;
b++;
}
labelList.get(i).setBounds(10+120*a+10*a, 10+130*b+10*b, 120, 130);
labelList.get(i).setOpaque(true);
labelList.get(i).setBackground(Color.WHITE);
labelList.get(i).setText(Integer.toString(i));
panel.add(labelList.get(i));
a++;
}
You're not going to like my answer, but I feel that we should be compelled to give you the best answer, which is not always what you want to hear. And that is this: use layout managers to do your component layouts. Yes while it might seem to newbies that null layouts are the easiest to use, as you gain more experience you will find that exactly the opposite is true. Null layout use makes for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain. Instead you will want to study and learn the layout managers and then nest JPanels, each using its own layout manager to create pleasing and complex GUI's that look good on all OS's.
As for ease of use, I invite you to create a complex GUI with your null layout, and then later try to add a component in the middle of this GUI. This will require you to manually re-calculate all the positions and sizes of components added to the left or below the new component, which is prone to many errors. The layout managers will all do this automatically for you.
Specifically use of valid layout managers will update your JPanel's preferredSize automatically increase as more components are added and as the JPanel is revalidated (the layouts are told to re-layout their components). Your null JPanel will not do this, and so the JScrollPane will not work. Yes, a work around is for you to manually calculate and set your JPanel's preferredSize, but this is dangerous and not recommended for the same reasons noted above.
Related
I have a panel derived from JPanel. I have a custom control derived from JLabel. I am attempting to center this custom JLabel on my panel.
The only way I know to do this that will work is to use the a null layout (setLayout(null)) and then calculate the custom JLabel's setLocation() point so that it's in the right spot.
The custom JLabel is physically moved from one panel to this panel in this app and I believe the location previously set in setLocation is affecting things. However when I set it to (0,0) the component goes up into the upper left corner.
BorderLayout doesn't work because when only 1 component is provided and placed into BorderLayout.CENTER, the central section expands to fill all of the space.
An example I cut and pasted from another site used BoxLayout and component.setAlignmentX(Component.CENTER_ALIGNMENT). This didn't work either.
Another answer mentioned overriding the panel's getInset() function (I think that's what it was called), but that proved to be a dead end.
So far I'm working with a panel with a GridBagLayout layout and I include a GridBagConstraints object when I insert the custom JLabel into my panel. This is inefficient, though. Is there a better way to center the JLabel in my JPanel?
Set GridBagLayout for JPanel, put JLabel without any GridBagConstraints to the JPanel, JLabel will be centered
example
import java.awt.*;
import javax.swing.*;
public class CenteredJLabel {
private JFrame frame = new JFrame("Test");
private JPanel panel = new JPanel();
private JLabel label = new JLabel("CenteredJLabel");
public CenteredJLabel() {
panel.setLayout(new GridBagLayout());
panel.add(label);
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(panel);
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
CenteredJLabel centeredJLabel = new CenteredJLabel();
}
});
}
}
Supose your JLabel is called label, then use:
label.setHorizontalAlignment(JLabel.CENTER);
Forget all the LayoutManagers in the Java Standard Library and use MigLayout. In my experience it's much easier to work with an usually does exactly what you expect it to do.
Here's how to accomplish what you're after using MigLayout.
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class Test
{
public static void main( String[] args )
{
JFrame frame = new JFrame( );
JPanel panel = new JPanel( );
// use MigLayout
panel.setLayout( new MigLayout( ) );
// add the panel to the frame
frame.add( panel );
// create the label
JLabel label = new JLabel( "Text" );
// give the label MigLayout constraints
panel.add( label, "push, align center" );
// show the frame
frame.setSize( 400, 400 );
frame.setVisible( true );
}
}
Most of that is just boilerplate. The key is the layout constraint: "push, align center":
align center tells MigLayout to place the JLabel in the center of its grid cell.
push tells MigLayout to expand the grid cell to fill available space.
BoxLayout is the way to go. If you set up a X_AXIS BoxLayout, try adding horizontal glues before and after the component:
panel.add(Box.createHorizontalGlue());
panel.add(label);
panel.add(Box.createHorizontalGlue());
I don't like the answers here.
I've never seen a valid use of a GridBagLayout ever in my career. Not saying there isn't one, just saying I haven't seen [a valid] one, and there might be correlation there. Moreover, adding a single JLabel to the middle of a Container might make it center for demonstrational purposes, but you're going to have a lot harder of a time later on if you try to continue to work with that over some other layouts.
I do like the suggestion about the BoxLayout, because that is actually a great way to do it. That said, that answer is only part of the puzzle, hence why I'm dredging up a 7 year old question.
My 'Answer'
Really there is no short answer to your question. There is an exact answer to your question based on what you asked, but StackOverflow is about a community learning from each other, and I suspect you're trying to learn how to use layouts in general (or you were 7 years ago) and telling you to type a combination of keys to do exactly your demo case is not going to teach you the answer.
I'm going to try not to explain any layouts that you can't web-search the answer for on your own (with a link to the Oracle tutorial at the end, because I think it explains the different layouts fairly well).
BoxLayout
BoxLayout is one way to do it, and there is already a code snippet to demo it above so I won't provide one. I'll expand on it to say that, just as mentioned, that only answers your question exactly, but doesn't really teach you anything. Glue, as the BoxLayout refers to it, basically gives you an equal amount of remaining real-estate between all the 'glue' currently in the Container. So, if you were to do something like
panel.add(Box.createHorizontalGlue());
panel.add(label);
panel.add(Box.createHorizontalGlue());
panel.add(otherLabel);
You would find that your JLabel is no longer centered, because the 'glue' is only the remaining real-estate left, after two JLabels were added to the Container which will be equally divided between the two 'slots' (two calls to Container#add(Component) with a glue parameter) in theContainer`.
BorderLayout
BorderLayout is another way to go about this. BorderLayout is broken down into 5 regions. BorderLayout#CENTER, as you might guess, is the center region. The important note about this layout and how it centers things is how it obeys sizes of the Component that is in the center. That I won't detail though; the Oracle tutorial at the end covers it well enough if you're interested, I think.
Worth Noting
I suppose you could use a GridLayout, but it's a more simple way to do it over a GridBagLayout, which I already said even that I think is not a good approach. So I won't detail this one either.
The Point of it All
Now all that said, I think all LayoutManagers are worth a look. Just like anything else with relation to programming - use the tool that fits the job. Don't just assume because you used X layout before, that you should always use X layout and no other layout is viable. Figure out what you want your display to look like, and how you think it should behave with respect to resizing components, and then pick what you think would work best.
Another dual meaning of picking the right tool, is that you don't have to just fit all of your components into one single Container and make one layout do everything. There is nothing stopping you (and I strongly encourage you to) use multiple Containers and group them all together. Control each Container with a layout that is appropriate for that section of the display, and a different layout for a different Container.
Important!!
The reason why this is very important is because each layout has rules and things that they obey, and other things that they respect, and then others that are effectively ignored (i.e. preferred, maximum, and minimum sizes, for instance). If you use different layouts [correctly], you will find your display accepts dynamically being resized while still obeying the shape that you wanted it to hold. This is a very important key difference between doing it the right way, and just settling with GridBagLayout.
JPanel outer = new JPanel(new BorderLayout());
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.PAGE_AXIS));
JPanel southPanel = new JPanel(new CardLayout());
outer.add(centerPanel, BorderLayout.CENTER);
outer.add(southPanel, BorderLayout.SOUTH);
Figure out what is appropriate to your scenario, and go with that. There is no one-size-fits-all unless you want something overly cumbersome and made redundant by other layouts (i.e. GridBagLayout).
Oracle's Tutorial
If you've made it this far, then I think you're looking for as much information as you can get. In which case, I strongly encourage you to read Oracle's tutorial on layout managers because it lays out general details of them all very well: https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
Use this.
labelName.setHorizontalAlignment(SwingConstants.CENTER);
or
labelName.setHorizontalAlignment(JPanel.CENTER);
Both of them must work.
Do like this instead of libraries and layouts :
JLabel jlabel = new JLabel("Label Text", SwingConstants.CENTER);
Make sure to import javax.swing.SwingConstants INTERFACE , BUT DO NOT IMPLEMENT IT. It contains only constants and no methods.
Put the JLabel in a JPanel or else it will come at the center of the JFrame or JWindow (your top level container).
How can I position a JButton under a JTable? What kind of layouts? How? I have a JTable table what is scrollable, and the table is in a frame.
There are many layouts to fulfill this need.
The simplest is using BorderLayout:
JFrame frame = new JFrame();
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(new JScrollPane(jtable), BorderLayout.CENTER);
contentPane.add(button, BorderLayout.SOUTH);
If you want this button to be not resized just add JPanel to contentPane. This JPanel should contain your button centered using almost any layout.
If you would like to use more sophisticated layout - the best in my opinion is MigLayout
To correct LoveToCode's well-meaning but misleading advice, you would never want to give a JTable itself a layout. The solution to your problem is not to set the JTable's layout but to set the layout for the JPanel that holds both the JTable's JScrollPane and the JButton. Likely a BorderLayout would work best with the JScrollPane being placed BorderLayout.CENTER and the JPanel that holds the JButton BorderLayout.SOUTH.
Note, if you're adding these components to the JFrame, then know that its contentPane already uses BorderLayout (the tutorials will tell you this -- please read them). So just add these guys to the contentPane as described above.
If hard coding of swing and awt is not mandatory, try using the WindowsBuilder Pro, a Free tool now from google, install its plugin in to eclipse, then Use
GroupLayout - Introduced by NetBeans team in 2005 integrated in WindowsBuilder Pro, is one of the most convenient way create a good gui in less time in Java.
It seems that you can set the layout of a jtable the same way in which you can set the layout of a jframe or a jpane:
table.setLayout(new grideLayout(4, 3)
would give it a grid layout with 4 rows and 3 columns.
the scrollable feature allows you to 'scroll' through your table with the moving bar. It may be a default feature, or it may be that you must use it, try seeing what methods your table gives you.
Lastly, your table should be in a frame, so that you can view it on your window, make you class extend JFrame and it will automatically be a frame upon which you can simply add a table!
BorderLayout does something strange. If I add two panels to a Container with the same constraint (BorderLayout.CENTER for instance), then the first one goes away, even if the second one is deleted or made invisible
It seems as though it would make sense for it to "stack" each element on top of the previous ones.
Is this correct and by design? If so, is there some documentation on it?
Has anyone else been frustrated by it? Have you a solution, such as a custom LayoutManager?
Sample code:
JFrame frame = new JFrame();
frame.setSize(500, 500);
JPanel panel1 = new JPanel();
panel1.setBackground(Color.blue);
frame.getContentPane().add(panel1);
JPanel panel2 = new JPanel();
panel2.setBackground(Color.red);
frame.getContentPane().add(panel2);
panel2.setVisible(false); // Seems like it should allow us to see panel1.
frame.setVisible(true);
This creates and displays a 500x500 blank box.
BorderLayout was simply not designed to do what you want. Separation of responsibility. If you want that behavior you should compose: combine the BorderLayout with a CardLayout. Though for the actual stack behavior, you'll have to code something yourself (or find someone who already has.)
Is this correct and by design?
Yes.
You need to understand the basics of how layout managers work. One of the jobs of the layout manager is to set the "location" and "size" of the components added to the panel. In the case of a BorderLayout it only tracks 5 components so only the last component added to the CENTER is known by the layout manager.
Layout management is not done when components are added to the panel. It is done when the frame is packed, or made visible (or the revalidate() method is invoked) . In this case the blue panel is not part of the components managed by the BorderLayout so its size remains (0, 0), which means there is nothing to paint.
Try changing your code to:
JPanel panel1 = new JPanel();
panel1.setSize(200, 200);
and you will see the blue panel painted at the specified size.
Now try commenting out:
//panel2.setVisible(false);
and you will see both panels. This is because as components are added to the panel they are assigned a ZOrder. Basically the last component added is painted first, which is why the blue panel is painted on top of the red panel. Check out the setComponentZOrder() method of the Container class for more information.
The CardLayout is probably the layout manager you should be using, but you can check out the Overlap Layout as well.
I have a small "popup" like this:
But I don't want the padding around the button, I want it to be as small as it can be with the supplied text.
btn.setMargin(new Insets(1, 1, 1, 1));
panel.add(lbl, "wrap");
panel.add(btn);
frame.pack();
frame.setVisible(true);
At least this doesn't work...
Can this be achieved on MigLayout or should I use some other layout manager for this frame.
What's your MigLayout constraints that it was built with? You might want to try using novisualpadding if you aren't already. Also, the debug layout constraint will draw boxes around your components to show what room they take up. (I think the red dotted lines are the size of the components and the blue dotted lines are the "cells" that the component is in.)
// old version
// JPanel panel = new JPanel(new MigLayout());
// new verion
JPanel panel = new JPanel(new MigLayout("debug, novisualpadding"));
I use MigLayout pretty often and have found the "cheat sheet" pretty useful. http://migcalendar.com/miglayout/cheatsheet.html
A layout manager should not affect the way a component is painted.
The setMargin(...) works fine for me when using the Metal LAF. Maybe your LAF doesn't support the setMargin() method. Or maybe you have some code elsewhere that is overriding the preferred size of the button causing it to paint like this.
However, if the MIG layout turns out to be the problem, you could try the Wrap Layout.
Taking MIke's answer as a startup, I found in the MIG "CheatSheet" a possible solution to your problem.
When you set up a MIGLayout, you can specify the gap between component with an integer between the square brackets defining columns and rows.
E.g.
MigLayout buttonMig = new MigLayout("", "[139px,grow]0[179px,grow]50[142px,grow][143px,grow]", "0[60px:60px:60px,center]");
I've just been having this issue too. I discovered that the following worked for me:
this.add(okButton, "width pref:pref:pref");
or
this.add(okButton, "wmax pref");
Also when using the substance look and feel there is a feature where the minimum size is always too wide. This can be overridden with this obscure hack.
okButton.putClientProperty(
SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, Boolean.TRUE);
JPanel pMeasure = new JPanel();
....
JLabel economy = new JLabel("Economy");
JLabel regularity = new JLabel("Regularity");
pMeasure.add(economy);
pMeasure.add(regularity);
...
When I run the code above I get this output:
Economy Regularity
How can I get this output, where each JLabel starts on a new line? Thanks
Economy
Regularity
You'll want to play around with layout managers to control the positioning and sizing of the controls in your JPanel. Layout managers are responsible for placing controls, determining where they go, how big they are, how much space is between them, what happens when you resize the window, etc.
There are oodles of different layout managers each of which allows you to layout controls in different ways. The default layout manager is FlowLayout, which as you've seen simply places components next to each other left to right. That's the simplest. Some other common layout managers are:
GridLayout - arranges components in a rectangular grid with equal-size rows and columns
BorderLayout - has one main component in the center and up to four surrounding components above, below, to the left, and to the right.
GridBagLayout - the Big Bertha of all the built-in layout managers, it is the most flexible but also the most complicated to use.
You could, for example, use a BoxLayout to layout the labels.
BoxLayout either stacks its components on top of each other or places them in a row — your choice. You might think of it as a version of FlowLayout, but with greater functionality. Here is a picture of an application that demonstrates using BoxLayout to display a centered column of components:
An example of code using BoxLayout would be:
JPanel pMeasure = new JPanel();
....
JLabel economy = new JLabel("Economy");
JLabel regularity = new JLabel("Regularity");
pMeasure.setLayout(new BoxLayout(pMeasure, BoxLayout.Y_AXIS));
pMeasure.add(economy);
pMeasure.add(regularity);
...
I read this piece of code:
pMeasure.setLayout(new BoxLayout(pMeasure, BoxLayout.VERTICAL));
It seems BoxLayout doesn't have VERTICAL. Upon searching, this will work using the following code:
pMeasure.setLayout(new BoxLayout(pMeasure, BoxLayout.Y_AXIS));
Here is what you need to use:
JLabel economy = new JLabel("<html>Economy<br>Regularity</html>");
A quick way is to use html within the JLabel.
For instance include the <br/> tag.
Otherwise, implement a BoxLayout.
Make a separate JPanel for each line, and set the dimensions to fit each word:
JLabel wordlabel = new JLabel("Word");
JPanel word1 = new JPanel();
word1.setPreferredSize(new Dimension(#,#);
This should work for each word. You can then add each of those JPanels to your main JPanel. This also allows you to add other components next to each word.