What LayoutManager should I use to achieve a transposed version of FlowLayout?
Essentially, I want a vertical list which occupies multiple columns if it can't fit all of it's components within one column.
+------------------------+
| item 1 |
| item 2 |
| item 3 |
| ite开发者_如何学Pythonm 4 |
| item 5 |
| item 6 |
| item 7 |
| item 8 |
+------------------------+
or
+------------------------+
| item 1 item 7 |
| item 2 item 8 |
| item 3 |
| item 4 |
| item 5 |
| item 6 |
+------------------------+
this wrapping logic needs to happen dynamically, ie as the container is resized.
very easy,you just need this.
yourPanel.setLayout(new BoxLayout(yourPanel, BoxLayout.Y_AXIS));
after this,you just add view to yourPanel and you will get vertical flow layout.
I'm working on a solution to my own question (very similar: I need to flow vertically but constrain width horizontally), I got a quick example sort of working and maybe it gets you started with a custom layout manager:
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager2;
import java.util.Random;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import com.google.common.collect.Sets;
public class VerticalFlowLayout implements LayoutManager2
{
final private Set<Component> components = Sets.newLinkedHashSet();
private int hgap = 0;
private int vgap = 0;
public void setHGap(int hgap) { this.hgap = hgap; }
public void setVGap(int vgap) { this.vgap = vgap; }
@Override public void addLayoutComponent(Component comp, Object constraints) {
this.components.add(comp);
}
/* these 3 methods need to be overridden properly */
@Override public float getLayoutAlignmentX(Container target) {
// TODO Auto-generated method stub
return 0;
}
@Override public float getLayoutAlignmentY(Container target) {
// TODO Auto-generated method stub
return 0;
}
@Override public void invalidateLayout(Container target) {
// TODO Auto-generated method stub
}
@Override public void addLayoutComponent(String name, Component comp) {
this.components.add(comp);
}
@Override public void layoutContainer(Container parent) {
int x = 0;
int y = 0;
int columnWidth = 0;
for (Component c : this.components)
{
if (c.isVisible())
{
Dimension d = c.getPreferredSize();
columnWidth = Math.max(columnWidth, d.width);
if (y+d.height > parent.getHeight())
{
x += columnWidth + this.hgap;
y = 0;
}
c.setBounds(x, y, d.width, d.height);
y += d.height + this.vgap;
}
}
}
/* these 3 methods need to be overridden properly */
@Override public Dimension minimumLayoutSize(Container parent) {
return new Dimension(0,0);
}
@Override public Dimension preferredLayoutSize(Container parent) {
return new Dimension(200,200);
}
@Override public Dimension maximumLayoutSize(Container target) {
return new Dimension(600,600);
}
@Override public void removeLayoutComponent(Component comp) {
this.components.remove(comp);
}
public static void main(String[] args) {
JFrame frame = new JFrame("VerticalFlowLayoutTest");
VerticalFlowLayout vfl = new VerticalFlowLayout();
JPanel panel = new JPanel(vfl);
vfl.setHGap(20);
vfl.setVGap(2);
int n = 19;
Random r = new Random(12345);
for (int i = 0; i < n; ++i)
{
JLabel label = new JLabel(labelName(i,r));
panel.add(label);
}
frame.setContentPane(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static String labelName(int i, Random r) {
StringBuilder sb = new StringBuilder();
sb.append("label #");
sb.append(i);
sb.append(" ");
int n = r.nextInt(26);
for (int j = 0; j < n; ++j)
sb.append("_");
return sb.toString();
}
}
I modified the GridLayout to layout components by column first instead of by row:
http://forums.oracle.com/forums/thread.jspa?messageID=5716765#5716765
Either you'll need a custom layout manager or you can use something like a GridBagLayout and control yourself.
An example:
Component parent = ...;
GridBagConstraints c = ...;
//set other parameters
c.gridx = 0;
c.gridy = 0;
parent.add([component1], c);
c.gridy++;
parent.add([component2], c);
c.gridy++;
This post is quite old :)
Codes in below link does not work fine, (calculate the height of invisible items which it is wrong!) http://www.java2s.com/Code/Java/Swing-JFC/AverticallayoutmanagersimilartojavaawtFlowLayout.htm
I changed some parts so it works fine now.
I also clean up insets so, if you need it, please add it yourself. thanks
package Common;
/**
* @author Pasban
*/
import java.awt.*;
import java.util.*;
public class VerticalLayout implements LayoutManager {
public final static int CENTER = 0;
public final static int RIGHT = 1;
public final static int LEFT = 2;
public final static int BOTH = 3;
public final static int TOP = 1;
public final static int BOTTOM = 2;
private int vgap;
private int alignment;
private int anchor;
private Hashtable comps;
public VerticalLayout() {
this(5, CENTER, TOP);
}
public VerticalLayout(int vgap) {
this(vgap, CENTER, TOP);
}
public VerticalLayout(int vgap, int alignment) {
this(vgap, alignment, TOP);
}
public VerticalLayout(int vgap, int alignment, int anchor) {
this.vgap = vgap;
this.alignment = alignment;
this.anchor = anchor;
}
private Dimension layoutSize(Container parent, boolean minimum) {
Dimension dim = new Dimension(0, 0);
Dimension d;
synchronized (parent.getTreeLock()) {
int n = parent.getComponentCount();
for (int i = 0; i < n; i++) {
Component c = parent.getComponent(i);
if (c.isVisible()) {
d = minimum ? c.getMinimumSize() : c.getPreferredSize();
dim.width = Math.max(dim.width, d.width);
dim.height += d.height;
if (i > 0) {
dim.height += vgap;
}
}
}
}
Insets insets = parent.getInsets();
dim.width += insets.left + insets.right;
dim.height += insets.top + insets.bottom + vgap + vgap;
return dim;
}
public void layoutContainer(Container parent) {
Insets insets = parent.getInsets();
synchronized (parent.getTreeLock()) {
int n = parent.getComponentCount();
Dimension pd = parent.getSize();
int y = 0;
for (int i = 0; i < n; i++) {
Component c = parent.getComponent(i);
Dimension d = c.getPreferredSize();
if (c.isVisible()) {
y += d.height + vgap;
}
}
y -= vgap;
if (anchor == TOP) {
y = insets.top;
} else if (anchor == CENTER) {
y = (pd.height - y) / 2;
} else {
y = pd.height - y - insets.bottom;
}
for (int i = 0; i < n; i++) {
Component c = parent.getComponent(i);
Dimension d = c.getPreferredSize();
if (!c.isVisible()) {
continue;
}
int x = 1;
int wid = pd.width - 3;
c.setBounds(x, y, wid, d.height);
y += d.height + vgap;
}
}
}
public Dimension minimumLayoutSize(Container parent) {
return layoutSize(parent, false);
}
public Dimension preferredLayoutSize(Container parent) {
return layoutSize(parent, false);
}
public void addLayoutComponent(String name, Component comp) {
}
public void removeLayoutComponent(Component comp) {
}
public String toString() {
return getClass().getName() + "[vgap=" + vgap + " align=" + alignment + " anchor=" + anchor + "]";
}
}
The solution of Jason S works for me. The only issue I corrected is I don't have com.google.common.collect.Sets or java.collections.LinkedHashSet libs (Java 7)...
so I just replace
final private Set<Component> components = Sets.newLinkedHashSet();
by
final private List<Component> components = new LinkedList<>();
and all seems to be ok :)
精彩评论