问题
I'm trying to make a kitchen display system using a FlowLayout
and I'm trying to figure out a way to add another panel on the 2nd row when the first row is already full. The width of the GUI will change according to user preference. When wider, it should show more of the components per row.
回答1:
Approach - Variable width with WrapLayout
The GridLayout
solution presumes the GUI requires 6 components per row.
For as many cols as needed to fill the width, & then show the components in as many rows as required, look to WrapLayout.
Approach - Variable width with JList
A JList
can also be used here, since it seems all the components consist of a single (GUI) object.
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.border.*;
public class ListComponents {
public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
String[] listData = {
"Component 1", "Component 2", "Component 3",};
final DefaultListModel<String> model
= new DefaultListModel<String>();
for (String datum : listData) {
model.addElement(datum);
}
JList list = new JList(model);
list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
list.setVisibleRowCount(-1);
list.setCellRenderer(new ObjectCellRenderer());
Action addAction = new AbstractAction("Add New") {
@Override
public void actionPerformed(ActionEvent e) {
model.addElement("New Component");
}
};
JButton addNew = new JButton(addAction);
JPanel ui = new JPanel(new BorderLayout(3, 3));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
ui.add(new JScrollPane(list), BorderLayout.CENTER);
ui.add(addNew, BorderLayout.PAGE_START);
JFrame f = new JFrame("Component List");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setContentPane(ui);
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
class ObjectCellRenderer extends DefaultListCellRenderer {
Border border = new EmptyBorder(20, 5, 20, 5);
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
label.setBorder(border);
return label;
}
}
Approach - Fixed width with GridLayout
Using a GridLayout
, when we know we always want a fixed number per row, regardless of width.
JPanel mainPanel = new JPanel(new GridLayout(0,6));
See new GridLayout(rows,cols):
Creates a grid layout with the specified number of rows and columns. All components in the layout are given equal size.
One, but not both, of rows and cols can be zero, which means that any number of objects can be placed in a row or in a column.
See this code for an example using a GridLayout(0,2)
for the labels beneath Add Another Label
回答2:
You can use a FlowLayout. From the tutorial How to Use FlowLayout:
The
FlowLayout
class puts components in a row, sized at their preferred size. If the horizontal space in the container is too small to put all the components in one row, theFlowLayout
class uses multiple rows. If the container is wider than necessary for a row of components, the row is, by default, centered horizontally within the container.
EDIT If you want your layout to scroll vertically when there are too many rows, you can use a JScrollPane
with horizontal scrolling disabled. You can do that with:
js.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
(where js
is the JScrollPane
that contains your FlowLayout
panel).
EDIT 2 Well, the above isn't enough. You also need to set a viewport view on the JScrollPane
that will track the JScrollPane
width. Here's a class that does this (taken from here):
static class MyPanel extends JPanel implements Scrollable{
@Override
public Dimension getPreferredScrollableViewportSize() {
return this.getPreferredSize();
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect,
int orientation, int direction) {
return 50;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation, int direction) {
return 80;
}
/*
* (non-Javadoc)
* @see javax.swing.Scrollable#getScrollableTracksViewportWidth()
*/
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
You would use this by adding your current FlowLayout
layout to an instance of MyPanel
(instead of directly to the JScrollPane
) and then calling
js.setViewportView(myPanelInstance);
来源:https://stackoverflow.com/questions/26080696/working-with-layout-managers