Java Swing 中具有设置像素高度的项目的可滚动列表
Scrollable List with items of set pixel height in Java Swing
我正在尝试在 swing 中创建 GUI。 GUI 将保持可变数量的 JPanel
个固定高度堆叠在一起。当堆栈中 JPanel
的总高度大于封闭框架的高度时,用户应该能够在面板中上下滚动。
____________________
| |
| panel 1 |
| |
|____________________|
| |
| panel 2 |
| |
|____________________|
___|____________________|___
| | panel 3 | |
| | | |
| |____________________| | ^
| | | | |
| | panel 4 | | |
| | | | |
| |____________________| | v
| | | |
| | panel 5 | |
|___|____________________|___|
|____________________|
| |
| panel 6 |
| |
|____________________|
我试过将 JScrollPane
和 JPanel
与 GridLayout
和 GridBagLayout
组合使用,并尝试调用 setPreferedSize
和 setMinimumSize
没有成功。我觉得设置这种 gui 应该相当简单,但似乎无法找到解决方案。
如果您使用 JPanel,那么视口持有的 JPanel 应该覆盖 JPanel class 并且应该实现 Scrollable 接口,为覆盖的方法返回正确的值,尤其是 getPreferredScrollableViewportSize()
方法。不过,为了我的钱,我更愿意使用 JList 并使用适当的渲染器而不是 JPanel,然后通过其 setVisibleRowCount(...)
方法设置我的 JLists visibleRowCount。
例如:
示例编辑为现在显示 JList 和 Scrollable JPanel
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import javax.swing.*;
@SuppressWarnings("serial")
public class VisibleRows extends JPanel {
private DefaultListModel<Datum> dataModel = new DefaultListModel<>();
private JList<Datum> datumList = new JList<>(dataModel);
public VisibleRows() {
DataPanel dataPanel = new DataPanel(8);
for (int i = 0; i < 200; i++) {
String name = "John Smith " + i;
int value = i;
Datum datum = new Datum(name, value);
dataPanel.addDatum(datum);
dataModel.addElement(datum);
}
JScrollPane scrollPane1 = new JScrollPane(dataPanel);
scrollPane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scrollPane1);
datumList.setVisibleRowCount(8);
datumList.setCellRenderer(new DatumRenderer());
datumList.setPrototypeCellValue(new Datum("XXXXXXXXXXX", 200));
JScrollPane scrollPane2 = new JScrollPane(datumList);
scrollPane2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scrollPane2);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("VisibleRows");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new VisibleRows());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
@SuppressWarnings("serial")
class DatumRenderer extends DatumPanel implements ListCellRenderer<Datum> {
@Override
public Component getListCellRendererComponent(JList<? extends Datum> list, Datum value, int index,
boolean isSelected, boolean cellHasFocus) {
setDatum(value);
return this;
}
}
@SuppressWarnings("serial")
class DataPanel extends JPanel implements Scrollable {
private int visibleRowCount = 1;
public DataPanel(int visibleRowCount) {
this.visibleRowCount = visibleRowCount;
setLayout(new GridLayout(0, 1));
}
public void addDatum(Datum datum) {
add(new DatumPanel(datum));
}
@Override
public Dimension getPreferredScrollableViewportSize() {
if (getComponentCount() > 0) {
JComponent comp = (JComponent) getComponents()[0];
int width = getPreferredSize().width;
int height = visibleRowCount * comp.getPreferredSize().height;
Dimension d = new Dimension(width, height);
System.out.println(d);
return d;
} else {
return new Dimension(0, 0);
}
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
if (getComponentCount() > 0) {
JComponent comp = (JComponent) getComponents()[0];
Dimension d = comp.getPreferredSize();
if (orientation == SwingConstants.VERTICAL) {
return d.height;
} else {
return d.width;
}
}
return 0;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
if (getComponentCount() > 0) {
JComponent comp = (JComponent) getComponents()[0];
Dimension d = comp.getPreferredSize();
if (orientation == SwingConstants.VERTICAL) {
return visibleRowCount * d.height;
} else {
return d.width;
}
}
return 0;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
@SuppressWarnings("serial")
class DatumPanel extends JPanel {
private static final int GBC_I = 3;
private Datum datum;
private JLabel nameLabel = new JLabel();
private JLabel valueLabel = new JLabel();
public DatumPanel() {
setLayout(new GridBagLayout());
add(new JLabel("Name:"), createGbc(0, 0));
add(nameLabel, createGbc(1, 0));
add(new JLabel("Value:"), createGbc(0, 1));
add(valueLabel, createGbc(1, 1));
}
public DatumPanel(Datum datum) {
this();
setDatum(datum);
}
public final void setDatum(Datum datum) {
this.datum = datum;
nameLabel.setText(datum.getName());
valueLabel.setText("" + datum.getValue());
}
public Datum getDatum() {
return datum;
}
private GridBagConstraints createGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.insets = new Insets(GBC_I, GBC_I, GBC_I, GBC_I);
gbc.insets.left = x != 0 ? 3 * GBC_I : GBC_I;
gbc.weightx = 0.0;
gbc.weighty = 0.0;
return gbc;
}
}
class Datum {
private String name;
private int value;
public Datum(String name, int value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public int getValue() {
return value;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Name: " + name + "\n");
sb.append("Value: " + value);
return super.toString();
}
}
import javax.swing.*;
public class ButtonsInScrollPane{
public static void main(String[] args){
JFrame frame = new JFrame();
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
p.add(getJButton(p));
JScrollPane scroll = new JScrollPane(p);
frame.setContentPane(scroll);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
static public JButton getJButton(JPanel p){
JButton b = new JButton("more");
b.addActionListener(evt->{
p.add(getJButton(p));
p.revalidate();
p.repaint();
});
return b;
}
}
点击按钮几次,按钮太多,然后会激活滚动。它应该几乎正是你所问的。
我正在尝试在 swing 中创建 GUI。 GUI 将保持可变数量的 JPanel
个固定高度堆叠在一起。当堆栈中 JPanel
的总高度大于封闭框架的高度时,用户应该能够在面板中上下滚动。
____________________
| |
| panel 1 |
| |
|____________________|
| |
| panel 2 |
| |
|____________________|
___|____________________|___
| | panel 3 | |
| | | |
| |____________________| | ^
| | | | |
| | panel 4 | | |
| | | | |
| |____________________| | v
| | | |
| | panel 5 | |
|___|____________________|___|
|____________________|
| |
| panel 6 |
| |
|____________________|
我试过将 JScrollPane
和 JPanel
与 GridLayout
和 GridBagLayout
组合使用,并尝试调用 setPreferedSize
和 setMinimumSize
没有成功。我觉得设置这种 gui 应该相当简单,但似乎无法找到解决方案。
如果您使用 JPanel,那么视口持有的 JPanel 应该覆盖 JPanel class 并且应该实现 Scrollable 接口,为覆盖的方法返回正确的值,尤其是 getPreferredScrollableViewportSize()
方法。不过,为了我的钱,我更愿意使用 JList 并使用适当的渲染器而不是 JPanel,然后通过其 setVisibleRowCount(...)
方法设置我的 JLists visibleRowCount。
例如:
示例编辑为现在显示 JList 和 Scrollable JPanel
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import javax.swing.*;
@SuppressWarnings("serial")
public class VisibleRows extends JPanel {
private DefaultListModel<Datum> dataModel = new DefaultListModel<>();
private JList<Datum> datumList = new JList<>(dataModel);
public VisibleRows() {
DataPanel dataPanel = new DataPanel(8);
for (int i = 0; i < 200; i++) {
String name = "John Smith " + i;
int value = i;
Datum datum = new Datum(name, value);
dataPanel.addDatum(datum);
dataModel.addElement(datum);
}
JScrollPane scrollPane1 = new JScrollPane(dataPanel);
scrollPane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scrollPane1);
datumList.setVisibleRowCount(8);
datumList.setCellRenderer(new DatumRenderer());
datumList.setPrototypeCellValue(new Datum("XXXXXXXXXXX", 200));
JScrollPane scrollPane2 = new JScrollPane(datumList);
scrollPane2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scrollPane2);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("VisibleRows");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new VisibleRows());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
@SuppressWarnings("serial")
class DatumRenderer extends DatumPanel implements ListCellRenderer<Datum> {
@Override
public Component getListCellRendererComponent(JList<? extends Datum> list, Datum value, int index,
boolean isSelected, boolean cellHasFocus) {
setDatum(value);
return this;
}
}
@SuppressWarnings("serial")
class DataPanel extends JPanel implements Scrollable {
private int visibleRowCount = 1;
public DataPanel(int visibleRowCount) {
this.visibleRowCount = visibleRowCount;
setLayout(new GridLayout(0, 1));
}
public void addDatum(Datum datum) {
add(new DatumPanel(datum));
}
@Override
public Dimension getPreferredScrollableViewportSize() {
if (getComponentCount() > 0) {
JComponent comp = (JComponent) getComponents()[0];
int width = getPreferredSize().width;
int height = visibleRowCount * comp.getPreferredSize().height;
Dimension d = new Dimension(width, height);
System.out.println(d);
return d;
} else {
return new Dimension(0, 0);
}
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
if (getComponentCount() > 0) {
JComponent comp = (JComponent) getComponents()[0];
Dimension d = comp.getPreferredSize();
if (orientation == SwingConstants.VERTICAL) {
return d.height;
} else {
return d.width;
}
}
return 0;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
if (getComponentCount() > 0) {
JComponent comp = (JComponent) getComponents()[0];
Dimension d = comp.getPreferredSize();
if (orientation == SwingConstants.VERTICAL) {
return visibleRowCount * d.height;
} else {
return d.width;
}
}
return 0;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
@SuppressWarnings("serial")
class DatumPanel extends JPanel {
private static final int GBC_I = 3;
private Datum datum;
private JLabel nameLabel = new JLabel();
private JLabel valueLabel = new JLabel();
public DatumPanel() {
setLayout(new GridBagLayout());
add(new JLabel("Name:"), createGbc(0, 0));
add(nameLabel, createGbc(1, 0));
add(new JLabel("Value:"), createGbc(0, 1));
add(valueLabel, createGbc(1, 1));
}
public DatumPanel(Datum datum) {
this();
setDatum(datum);
}
public final void setDatum(Datum datum) {
this.datum = datum;
nameLabel.setText(datum.getName());
valueLabel.setText("" + datum.getValue());
}
public Datum getDatum() {
return datum;
}
private GridBagConstraints createGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.insets = new Insets(GBC_I, GBC_I, GBC_I, GBC_I);
gbc.insets.left = x != 0 ? 3 * GBC_I : GBC_I;
gbc.weightx = 0.0;
gbc.weighty = 0.0;
return gbc;
}
}
class Datum {
private String name;
private int value;
public Datum(String name, int value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public int getValue() {
return value;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Name: " + name + "\n");
sb.append("Value: " + value);
return super.toString();
}
}
import javax.swing.*;
public class ButtonsInScrollPane{
public static void main(String[] args){
JFrame frame = new JFrame();
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
p.add(getJButton(p));
JScrollPane scroll = new JScrollPane(p);
frame.setContentPane(scroll);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
static public JButton getJButton(JPanel p){
JButton b = new JButton("more");
b.addActionListener(evt->{
p.add(getJButton(p));
p.revalidate();
p.repaint();
});
return b;
}
}
点击按钮几次,按钮太多,然后会激活滚动。它应该几乎正是你所问的。