Swing: easiest way to align width of [dynamic][static][dynamic] components? - java

What is the easiest way in standard Java Swing to align three components in such a way that:
the dynamic widths of Component1 and Component3 are adjusted to be equal,
while Component2 (which is in between) has constant width?
Imagine we have some resizable JPanel (such as inside a JFrame).
Small width should look like this:
[----------------whole JPanel----------------]
[--Component1--] [Component2] [--Component3--]
Big width should look like this:
[------------------------whole JPanel------------------------]
[------Component1------] [Component2] [------Component3------]
Note: I just "trialed-and-errored" with GroupLayout for too long.

One option is using a GridBagLayout. A quick and dirty snippet to get you started:
GridBagConstraints gbc;
final int A_CENTER = GridBagConstraints.CENTER; // anchor: center
final int F_NONE = GridBagConstraints.NONE; // fill: none
final int F_DX = GridBagConstraints.HORIZONTAL; // fill: dx only
final Insets IN_0 = new Insets(0, 0, 0, 0); // empty insets
setLayout(new GridBagLayout() );
gbc = new GridBagConstraints(0, 0, 1, 1, 50.0, 0.0, A_CENTER, F_DX, IN_0, 0, 0);
add(new JButton("test1"), gbc);
gbc = new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, A_CENTER, F_NONE, IN_0, 0, 0);
add(new JButton("test2"), gbc);
gbc = new GridBagConstraints(2, 0, 1, 1, 50.0, 0.0, A_CENTER, F_DX, IN_0, 0, 0);
add(new JButton("test1"), gbc);
Obviously there's a lot more you can do with a GridBag, and you'll need to do some polishing to get exactly what you want to see, but this should get you started.
The fifth parameter in the GBC constructor is a weight for stretching in the x direction. Setting them equal, and forcing the center component not to stretch (F_NONE) does the dirty work.

How about the MigLayout manager? It is not a part of JRE, but is a great layout manager, which can easily produce the layout you require with less code than GridBag. Check out their demo.
Could not resist to post the totally grid bag cartoon... enjoy (:

Related

Word wrapping a JLabe/JTextArea in a JPanel in a JScrollPane

In my application, I need to word wrap Labels, which are contained in a JPanel (with GridBagLayout), which in turn is contained in a JScrollPane, which is contained in a resizable JFrame. The text should always be as wide as the Scrollpane allows(i.e. be completly visible at once). I tried multiple things already:
Putting tags around the text.
Result: Nothing
Putting on the Text
Result: Wraps, but with static width (does not respond to the Frame being resized) (duh)
Putting on the Text
Result: Nothing
Using a JTextArea, as in https://stackoverflow.com/a/26426585/4936150
Result: Appears to work at first, when the width of the Frame is increased, the words get "unwrapped" (so they are all on one line), but when the width is decreased afterwards, it will stay that way and not "wrap back". Also, weirdly doesn't work in the Nimbus L&F
Implementing Scrollable on the JPanel and returning true from getScrollableTracksViewportWidth()
Result: Works, but I DO want it to scroll horizontally if the Frame is too small for other Components
For reference, here is the source for my Panel class, without any wrapping:
public class ProgPanel extends JPanel {
/**
* Create the panel.
*/
public ProgPanel() {
GridBagLayout gridBagLayout = new GridBagLayout();
gridBagLayout.columnWidths = new int[]{0};
gridBagLayout.rowHeights = new int[]{59, 0, 0};
gridBagLayout.columnWeights = new double[]{1.0};
gridBagLayout.rowWeights = new double[]{0.0, 1.0, Double.MIN_VALUE};
setLayout(gridBagLayout);
JLabel lblName = new JLabel("Long, long text taht needs to be wrapped, because it is displayed in a very big font on a kindof small screen, bla bla bla bhlergh lol rofl 1337");
GridBagConstraints gbc_lblName = new GridBagConstraints();
gbc_lblName.gridwidth = 2;
gbc_lblName.anchor = GridBagConstraints.WEST;
gbc_lblName.insets = new Insets(0, 0, 5, 0);
gbc_lblName.gridwidth = 1;
gbc_lblName.gridx = 0;
gbc_lblName.gridy = 0;
add(lblName, gbc_lblName);
lblName.setBorder(new EmptyBorder(10, 5, 0, 10));
lblName.setIconTextGap(10);
lblName.setIcon(new ImageIcon("someicon.png"));
lblName.setFont(getFont().deriveFont(Font.BOLD+Font.ITALIC, 48));
}
}
EDIT: Here is the implementation using a JTextArea, which will only grow in width, but not shrink: https://pastebin.com/egMXfwK1 (Pastebin due to long length and tedious SO formatting)
EDIT2: Here are some pictures showing the issue: http://imgur.com/a/mhtV9

Fixing JPanel Size

I have 4 JPanels in a dialog that are arranged vertically using GridBagLayout. All of them should have equal length ideally.
Every thing works fine except Panel 2 from the top whose contents are added and removed dynamically depending on the selection made by a combo-box that is also contained in the same Panel and are not of the fixed size. Due to the nature of the contents I use GridBagLayout for Panel 2 itself as well and initially set the Min., Max. and PreferredSize of the Panel to the largest posible size of the contents and wants this panel to stick to this size. But that doesn't work as Panel2 is also get effected by Panel1 and Panel2 contents(Their contents are also added and removed but always has the same size)
Any suggestion? Wanted to add the photo of the panels but coudn't due the strange restrictions imposed here
OK after viewing the comments on the question, i am going to add some code snippet here
JPanel dataPanel=new JPanel();
dataPanel.setLayout(new GridBagLayout());
final GridBagConstraints constraintAmpliaciones = new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0);
//dataPanel.add(panelIdOrigen, constraintAmpliaciones);
constraintAmpliaciones.gridy++;
dataPanel.add(panel1,constraintAmpliaciones );
constraintAmpliaciones.gridy++;
dataPanel.add(panel2,constraintAmpliaciones);
constraintAmpliaciones.gridy++;
dataPanel.add(panel3, constraintAmpliaciones);
constraintAmpliaciones.gridy++;
dataPanel.add(panel4,constraintAmpliaciones);
Where as Panel2(the problematic one) is some thing like this:
void initComponents() {
panelGeneral = new JPanel();
panelGeneral.setLayout(new GridBagLayout());
panelGeneral.add(panelLarger, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
/**
* here for dimension,I have tried different sizes including the fixed size in pixels of panelLarger
*/
Dimension dimension = new Dimension((int) panelGeneral.getPreferredSize().getWidth(), (int) panelGeneral.getPreferredSize().getHeight());
panelGeneral.setMaximumSize(dimension);
panelGeneral.setPreferredSize(dimension);
panelGeneral.setMinimumSize(dimension);
this.add(panelGeneral);
}
/**
* is called upon combox selection
*/
void updateComponents() {
if (selection1) {
panelGeneral.remove(panelLarger);
panelGeneral.add(panelSmaller, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
} else {
panelGeneral.remove(panelSmaller);
panelGeneral.add(panelLarger, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER,
GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
}
}
I'm not sure I understand correctly, but you could try this:
Put a JLabel in Panel2 under all the other components in Panel2 (I'm assuming Panel2 is too small vertically when it doesn't have all the components it could have in it) . Make sure the Jlabel text is set to "" so it will appear invisible to the user.
After this, you want to set the GridBagConstraints of the JLabel to fill = VERTICAL and weighty = 1.0.
This should push all the other components to the top of Panel2 as the JLabel expands vertically underneath them, and it should preserve the size of the Panel and prevent it from shrinking. I suppose if you know exactly how big the image would have been each time, you could put in a JLabel of this size instead of having it scale vertically.
Swing can be tricky since I can't see all your code, but I frequently make use of hidden JLabels in my GUIs to make panels scale how I want them too.

GridBagLayout Assistance

I've tried all combinations and looked at all the documentation but I can't figure out how to use GridBagLayout.
I've got 3 components in a JPanel with GridBagLayout being the LayoutManager of the JPanel and using GridBagConstraints on the 3 components.
With the current code (as shown below) the 3 elements appear on the panel properly. The issue is that the first component is a JLabel which sometimes is quite long, if this is the case then it will expand and make the other 2 components smaller.
My objective is to have a JPanel with a GridBagLayout of 1 row and 4 columns, where the first element takes up the first 2 columns, and the other 2 elements take up the remaining 2, and that these elements to do not expand out of their columns.
private static void setConstraints(GridBagConstraints constraints, int gridx, int gridy, int weightx, Insets insets) {
constraints.gridx = gridx;
constraints.weightx = weightx;
constraints.insets = insets;
}
gridBagLayout = new GridBagLayout();
constraints = new GridBagConstraints();
centerPanel = new JPanel(gridBagLayout);
constraints.fill = GridBagConstraints.HORIZONTAL;
fileNameLabel = new JLabel("Resolving: '" + EngineHelpers.trimStringToFitPanel(urlTextField.getText(), 70) + "'");
setConstraints(constraints, 0, 0, 2, new Insets(0, 5, 5, 0));
gridBagLayout.setConstraints(fileNameLabel, constraints);
progressBar = new JProgressBar();
progressBar.setStringPainted(true);
setConstraints(constraints, 1, 0, 1, new Insets(0, 5, 5, 0));
gridBagLayout.setConstraints(progressBar, constraints);
cancelDownloadButton = new JButton("Cancel");
setConstraints(constraints, 2, 0, 1, new Insets(0, 0, 0, 0));
gridBagLayout.setConstraints(cancelDownloadButton, constraints);
centerPanel.add(fileNameLabel);
centerPanel.add(progressBar);
centerPanel.add(cancelDownloadButton);
Thanks in advance everyone, sorry for the stupid question!
You probably want weightx set to 0 for both the button and progress bar. For the label, set the weight to 1. This will keep the button and progress bar from expanding at all and let the progress bar take all the extra space.
Also set gridwidth on the progress bar constraints to 2 so it actually uses 2 columns.
Finally, depending on where centerPanel is placed, it may not actual expand to fill the container. If centerPanel is being placed in a parent with a BorderLayout, it should expand. To make sure, you can add a border with centerPanel.setBorder(BorderFactory.createLineBorder(Color.RED)) for debugging. This can also be useful on the button, label and progress bars too.

JLabel resizes when redrawing other components

I'm having a problem with my Java layout. I'm trying to place a JLabel across the very top follow by a grid of five WorldWindowGLCanvas's. Something like:
------------------------------------------------
JLabel
------------------------------------------------
|
WWCanvas | WWCanvas
|
------------------------------------------------
|
WWCanvas | WWCanvas
|
I'm currently using a GridBagLayout inside of a JPanel. When the program first starts everything looks as it should. However, upon the first redraw of all the WorldWindowGLCanvas's the top JLabel immediately doubles in size and takes up was too much space. Here's some relevant code:
JFrame f = new JFrame("ScintDisplay");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new GridBagLayout());
JLabel timeLabel = new JLabel(getTime(), JLabel.CENTER);
timeLabel.setSize(new Dimension(200,200));
WorldWindowGLCanvas wwd1 = new WorldWindowGLCanvas();
wwd1.setPreferredSize(new java.awt.Dimension(960, 1000));
WorldWindowGLCanvas wwd2 = new WorldWindowGLCanvas();
wwd2.setPreferredSize(new java.awt.Dimension(500, 480));
WorldWindowGLCanvas wwd3 = new WorldWindowGLCanvas();
wwd3.setPreferredSize(new java.awt.Dimension(500, 480));
WorldWindowGLCanvas wwd4 = new WorldWindowGLCanvas();
wwd4.setPreferredSize(new java.awt.Dimension(500, 480));
WorldWindowGLCanvas wwd5 = new WorldWindowGLCanvas();
wwd5.setPreferredSize(new java.awt.Dimension(500, 480));
wwd1.setModel(new BasicModel());
wwd2.setModel(new BasicModel());
wwd3.setModel(new BasicModel());
wwd4.setModel(new BasicModel());
wwd5.setModel(new BasicModel());
addComponent(f, wwd2, 0, 2, 1, 4, GridBagConstraints.CENTER, GridBagConstraints.BOTH);
addComponent(f, wwd1, 1, 2, 2, 8, GridBagConstraints.CENTER, GridBagConstraints.BOTH);
addComponent(f, wwd3, 3, 2, 1, 4, GridBagConstraints.CENTER, GridBagConstraints.BOTH);
addComponent(f, wwd4, 0, 6, 1, 4, GridBagConstraints.CENTER, GridBagConstraints.BOTH);
addComponent(f, wwd5, 3, 6, 1, 4, GridBagConstraints.CENTER, GridBagConstraints.BOTH);
addComponent(f, timeLabel, 0, 0, 4, 1, GridBagConstraints.WEST, GridBagConstraints.NONE);
f.setSize(1920, 1200);
f.setVisible(true);
double lat1 = getTimeLon();
for( ; ; )
{
//System.out.println(lat);
timeLabel.setText(getTime());
System.out.println(timeLabel.getSize());
wwd1.getView().setEyePosition(Position.fromDegrees(0, lat1, 10500000));
wwd2.getView().setEyePosition(Position.fromDegrees(0, 0, 23500000));
wwd3.getView().setEyePosition(Position.fromDegrees(0, 0, 23500000));
wwd4.getView().setEyePosition(Position.fromDegrees(0, 0, 23500000));
wwd5.getView().setEyePosition(Position.fromDegrees(0, 0, 23500000));
wwd1.redraw();
wwd2.redraw();
wwd3.redraw();
wwd4.redraw();
wwd5.redraw();
Thread.sleep(30000);
lat1 = getTimeLon();
}
private static void addComponent(Container container, Component component, int gridx, int gridy, int gridwidth, int gridheight, int anchor, int fill)
{
GridBagConstraints gbc = new GridBagConstraints(gridx, gridy, gridwidth, gridheight, 1.0, 1.0, anchor, fill, insets, 0, 0);
container.add(component, gbc);
}
I've never done a GUI with GL components that redraw before. Am I missing something? Is this a layout problem. or something to do with redrawing?
Thanks,
-B
You're trying to ask GridBagLayout to do too much and instead should use nested JPanels to achieve this. Have the center JPanel use GridBagLayout, sure, but have it held by another JPanel that uses BorderLayout. Add the center panel to the BorderLayout.CENTER position, and the JLabel to the main BorderLayout-using JPanel's BorderLayout.NORTH or BorderLayout.PAGE_START position. Also be sure that the JLabel has been set to display it's text centered.
Also, you've got code there that looks dangerous from a Swing threading point of view. That non-stopping loop and Thread.sleep(...) appear to be called on the Swing event thread or EDT, and this can cause your application to freeze. Consider using a SwingWorker to allow this code to be called on a background thread.

<br>? \n? a line break in java

I have three JLabels and three JTextAreas. I have them in borderlayout, center, but I want each of them in a different line, that's not happening and the top ten search results in Google for line break java don't solve the problem. How can I do a simple line break?
If this is a Swing application, you should use a layout manager to position your fields in the container.
Line break won't help with placing Swing objects; you need to place a layout on a center JPanel. That is, the center of your border layout should be a single Swing object, a JPanel, and you should set that to a style which allows you to stack each widget. GridLayout(6,1) may do it.
You can use layout managers like GridLayout or GridBagLayout. Even though the latter one is only recommended for code generated by GUI generators I prefer it because it gives me the most flexibility.
JPanel panel = new JPanel();
GridBagLayout layout = new GridBagLayout();
panel.setLayout(layout);
layout.add(label1, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
layout.add(area1, new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
layout.add(label2, new GridBagConstraints(0, 1, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
layout.add(area2, new GridBagConstraints(1, 1, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
layout.add(label3, new GridBagConstraints(0, 2, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
layout.add(area3, new GridBagConstraints(1, 2, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
panel.add(label1);
panel.add(label2);
panel.add(label3);
panel.add(area1);
panel.add(area2);
panel.add(area3);
Of course this looks butt-ugly but should get you started.
You can also abuse a BorderLayout:
JPanel panel = new JPanel(new BorderLayout());
JPanel topRow = new JPanel();
panel.add(topRow, BorderLayout.PAGE_START);
topRow.add(label1);
topRow.add(area1);
JPanel middleRowBox = new JPanel(new BorderLayout());
panel.add(middleRowBox, BorderLayout.CENTER);
JPanel middleRow = new JPanel();
middleRowBox.add(middleRow, BorderLayout.PAGE_START);
middleRow.add(label2);
middleRow.add(area2);
JPanel bottomRowBox = new JPanel();
middleRowBox.add(bottomRowBox, BorderLayout.CENTER);
JPanel bottomRow = new JPanel();
bottomRowBox.add(bottomRow, BorderLayout.PAGE_START);
bottomRow.add(label3);
bottomRow.add(area3);
bottomRowBix.add(new JPanel(), BorderLayout.CENTER);
Try using a GridLayout for starters:
panel.setLayout(new GridLayout(0,2));
// the order of added components is important
panel.add(labelA);
panel.add(textAreaA);
panel.add(labelB);
panel.add(textAreaB);
...
Doesn't look too pretty but it gets you started.
If you don't set a LayoutManager to a new panel, it will use a FlowLayout which behaves somewhat like HTML layout. But there is no such thing as an intended line break in a FlowLayout. It will just put component after component until it reaches the end of the available space and then start a new row.
If you want control over your layouts - don't use FlowLayout.
Layout managers you might want to get to know are:
BorderLayout - very good if you want resizeable content
GridLayout - simple equals width and height grid
null - allows you to use setBounds on each component to get absolute positions
There are more, but these three should allow you to layout 95% of your panels.

Categories