JScrollPane "stretching" 出我添加的面板
JScrollPane "stretching" out the panel that I add to it
我必须制作一个可滚动列表,我可以在其中多次添加带有 3 个标签的面板。
我有点让它工作,但第一个面板被拉伸并占据了 JScrollPane 的所有区域,我无法弄清楚如何解决这个问题,我多次尝试更改布局但仍然无法修复它。
我希望添加的面板占据固定大小,但我无法弄清楚。此图片中的示例:
https://i.stack.imgur.com/LNznP.png
左边的是我得到的,右边的(编辑过的)是我想要的。
这是我第一天使用 Swing,所以代码很可能是乱七八糟的,提前抱歉。
代码如下:
public class MainWindow extends JFrame implements ActionListener{
private JPanel viewportPanel;
private JButton addButton,remButton;
private JScrollPane scrollPane;
private int counter = 0;
private JLabel dateLabel,dateLabel_1,dateLabel_2;
public MainWindow(boolean run) {
//BUTTONS
addButton = new JButton("Add");
addButton.setLocation(521, 11);
addButton.setSize(101, 100);
addButton.addActionListener(this);
remButton = new JButton("Remove");
remButton.setLocation(521, 122);
remButton.setSize(101, 100);
remButton.addActionListener(this);
//SCROLLPANE
scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(10, 11, 501, 211);
add(scrollPane);
//PANELS
viewportPanel = new JPanel(new GridLayout(0,1));
scrollPane.setViewportView(viewportPanel);
//FRAME
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 650, 273);
setResizable(false);
//setIconImage(new ImageIcon("epic.png").getImage());
setLayout(null);
if(run) setVisible(true);
add(addButton);
add(remButton);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == addButton) {
//LABELS
dateLabel = new JLabel("DATE");
dateLabel.setFont(new Font("Tahoma", Font.BOLD, 28));
dateLabel.setSize(500,500);
dateLabel_1 = new JLabel("LABEL1");
dateLabel_1.setFont(new Font("Tahoma", Font.BOLD, 22));
dateLabel_1.setBounds(10, 45, 481, 30);
dateLabel_2 = new JLabel("LABEL2");
dateLabel_2.setFont(new Font("Tahoma", Font.ITALIC, 22));
dateLabel_2.setBounds(10, 45, 481, 30);
//PANEL WITH ALL THE STUFF
JPanel componentPanel = new JPanel();
componentPanel.setLayout(new GridLayout(3, 1));
componentPanel.setMaximumSize(new Dimension(50,50));
componentPanel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.BLACK));
componentPanel.setBackground(Color.gray);
componentPanel.add(dateLabel);
componentPanel.add(dateLabel_1);
componentPanel.add(dateLabel_2);
viewportPanel.add(componentPanel); //add panel with labels to viewportpanel
counter++;
}
if(e.getSource() == remButton) {
Component[] componentList = viewportPanel.getComponents();
int lastElement = (componentList.length);
viewportPanel.remove(--lastElement);
--counter;
}
viewportPanel.revalidate();
viewportPanel.repaint();
}
}
有些帮助会很棒!
首先,永远不要这样做:
setLayout(null);
接下来,如果您希望将内容压缩在容器顶部,请使用执行此操作的布局。例如 BorderLayout,将压缩项目放入 JPanel(可能使用 GridLayout 的 JPanel)中 BorderLayout.PAGE_START
实际上,看起来您最好的解决方案是给我们一个 JList,它使用自定义呈现器将您的时间 JLabel 和两个文本 JLabel 放入 JPanel 中,并将其显示在列表中。那么让我们来探讨一下。
首先创建一个class来保存JList显示的数据,看起来是一个日期和两行文本:
public class ListItem {
private LocalDate date;
private String text1;
private String text2;
public ListItem(LocalDate date, String text1, String text2) {
super();
this.date = date;
this.text1 = text1;
this.text2 = text2;
}
public LocalDate getDate() {
return date;
}
public String getText1() {
return text1;
}
public String getText2() {
return text2;
}
}
然后让我们创建一个渲染器,JList 可以使用该渲染器在 JPanel 中显示上述信息。这更复杂,需要 class 创建一个 JPanel 将标签放置在我们想要的位置,也许使用具有 1 列和 3 行的 GridLayout,加上行之间的一些间隙:setLayout(new GridLayout(3, 1, 2 * gap, 2 * gap));
。 class 必须实现 ListCellRenderer<T>
接口,该接口具有一个方法:public Component getListCellRendererComponent(...)
。 Java 会将参数传入此方法,包括一个 ListItem 值,我们将使用该值来填充我们添加到此 JPanel 中的 JLabel。编辑以突出显示所选项目。
import java.awt.*;
import java.time.format.DateTimeFormatter;
import javax.swing.*;
import javax.swing.border.Border;
@SuppressWarnings("serial")
public class ListItemRenderer extends JPanel implements ListCellRenderer<ListItem> {
private static final Color LIGHT_BLUE = new Color(204, 255, 255);
private static final Color REDDISH_GREY = new Color(205, 126, 121);
private DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
private static final int GAP = 2;
private Border emptyBorder = BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP);
private Border blackBorder = BorderFactory.createLineBorder(Color.BLACK);
private Border redBorder = BorderFactory.createLineBorder(REDDISH_GREY, 2);
private JLabel dateLabel = new JLabel();
private JLabel text1Label = new JLabel();
private JLabel text2Label = new JLabel();
public ListItemRenderer() {
dateLabel.setFont(dateLabel.getFont().deriveFont(Font.BOLD, 14f));
text1Label.setFont(text1Label.getFont().deriveFont(Font.BOLD));
text2Label.setFont(text1Label.getFont().deriveFont(Font.ITALIC));
int gap = 2;
setLayout(new GridLayout(0, 1, 2 * gap, 2 * gap));
setBorder(BorderFactory.createCompoundBorder(emptyBorder, blackBorder));
add(dateLabel);
add(text1Label);
add(text2Label);
}
@Override
public Component getListCellRendererComponent(JList<? extends ListItem> list, ListItem value, int index,
boolean isSelected, boolean cellHasFocus) {
if (value != null) {
String dateText = dateFormatter.format(value.getDate());
dateLabel.setText(dateText);
text1Label.setText(value.getText1());
text2Label.setText(value.getText2());
} else {
dateLabel.setText("");
text1Label.setText("");
text2Label.setText("");
}
if (isSelected ) {
setBackground(LIGHT_BLUE);
setBorder(BorderFactory.createCompoundBorder(emptyBorder, redBorder));
} else {
setBackground(null);
setBorder(BorderFactory.createCompoundBorder(emptyBorder, blackBorder));
}
return this;
}
}
现在是将所有这些放在一起的主程序,经过编辑以显示删除项目:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Random;
import javax.swing.*;
@SuppressWarnings("serial")
public class MainPanel extends JPanel {
DefaultListModel<ListItem> listModel = new DefaultListModel<>();
private JList<ListItem> jList = new JList<>(listModel);
private JScrollPane scrollPane = new JScrollPane(jList);
private JButton addButton = new JButton("Add");
private JButton removeButton = new JButton("Remove");
public MainPanel() {
jList.setPrototypeCellValue(new ListItem(LocalDate.now(),
"This is text 1 for testing. This is text 1 for testing. This is text 1 for testing",
"This is text 2 for testing. This is text 2 for testing. This is text 2 for testing"));
jList.setVisibleRowCount(4);
jList.setCellRenderer(new ListItemRenderer());
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 3, 3));
buttonPanel.add(addButton);
buttonPanel.add(removeButton);
addButton.setMnemonic(KeyEvent.VK_A);
removeButton.setMnemonic(KeyEvent.VK_R);
addButton.addActionListener(e -> addEvent());
removeButton.addActionListener(e -> removeEvent());
JPanel rightPanel = new JPanel();
rightPanel.add(buttonPanel);
int gap = 5;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new BorderLayout());
add(scrollPane);
add(rightPanel, BorderLayout.LINE_END);
}
private void removeEvent() {
int[] selectedIndices = jList.getSelectedIndices();
for (int i = selectedIndices.length - 1; i >= 0; i--) {
listModel.remove(selectedIndices[i]);
}
}
private void addEvent() {
// this adds random stuff to the JList
String text1 = "Some random text: " + randomText();
String text2 = "Some random text: " + randomText();
listModel.addElement(new ListItem(LocalDate.now(), text1, text2));
// TODO: change this so that it adds *real* data to the JList
}
private String randomText() {
Random random = new Random();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 2 + random.nextInt(3); i++) {
for (int j = 0; j < 3 + random.nextInt(5); j++) {
char c = (char) ('a' + random.nextInt('z' - 'a'));
builder.append(c);
}
builder.append(" ");
}
return builder.toString();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
输出如下:
我必须制作一个可滚动列表,我可以在其中多次添加带有 3 个标签的面板。 我有点让它工作,但第一个面板被拉伸并占据了 JScrollPane 的所有区域,我无法弄清楚如何解决这个问题,我多次尝试更改布局但仍然无法修复它。 我希望添加的面板占据固定大小,但我无法弄清楚。此图片中的示例: https://i.stack.imgur.com/LNznP.png 左边的是我得到的,右边的(编辑过的)是我想要的。
这是我第一天使用 Swing,所以代码很可能是乱七八糟的,提前抱歉。
代码如下:
public class MainWindow extends JFrame implements ActionListener{
private JPanel viewportPanel;
private JButton addButton,remButton;
private JScrollPane scrollPane;
private int counter = 0;
private JLabel dateLabel,dateLabel_1,dateLabel_2;
public MainWindow(boolean run) {
//BUTTONS
addButton = new JButton("Add");
addButton.setLocation(521, 11);
addButton.setSize(101, 100);
addButton.addActionListener(this);
remButton = new JButton("Remove");
remButton.setLocation(521, 122);
remButton.setSize(101, 100);
remButton.addActionListener(this);
//SCROLLPANE
scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setBounds(10, 11, 501, 211);
add(scrollPane);
//PANELS
viewportPanel = new JPanel(new GridLayout(0,1));
scrollPane.setViewportView(viewportPanel);
//FRAME
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 650, 273);
setResizable(false);
//setIconImage(new ImageIcon("epic.png").getImage());
setLayout(null);
if(run) setVisible(true);
add(addButton);
add(remButton);
}
public void actionPerformed(ActionEvent e) {
if(e.getSource() == addButton) {
//LABELS
dateLabel = new JLabel("DATE");
dateLabel.setFont(new Font("Tahoma", Font.BOLD, 28));
dateLabel.setSize(500,500);
dateLabel_1 = new JLabel("LABEL1");
dateLabel_1.setFont(new Font("Tahoma", Font.BOLD, 22));
dateLabel_1.setBounds(10, 45, 481, 30);
dateLabel_2 = new JLabel("LABEL2");
dateLabel_2.setFont(new Font("Tahoma", Font.ITALIC, 22));
dateLabel_2.setBounds(10, 45, 481, 30);
//PANEL WITH ALL THE STUFF
JPanel componentPanel = new JPanel();
componentPanel.setLayout(new GridLayout(3, 1));
componentPanel.setMaximumSize(new Dimension(50,50));
componentPanel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.BLACK));
componentPanel.setBackground(Color.gray);
componentPanel.add(dateLabel);
componentPanel.add(dateLabel_1);
componentPanel.add(dateLabel_2);
viewportPanel.add(componentPanel); //add panel with labels to viewportpanel
counter++;
}
if(e.getSource() == remButton) {
Component[] componentList = viewportPanel.getComponents();
int lastElement = (componentList.length);
viewportPanel.remove(--lastElement);
--counter;
}
viewportPanel.revalidate();
viewportPanel.repaint();
}
}
有些帮助会很棒!
首先,永远不要这样做:
setLayout(null);
接下来,如果您希望将内容压缩在容器顶部,请使用执行此操作的布局。例如 BorderLayout,将压缩项目放入 JPanel(可能使用 GridLayout 的 JPanel)中 BorderLayout.PAGE_START
实际上,看起来您最好的解决方案是给我们一个 JList,它使用自定义呈现器将您的时间 JLabel 和两个文本 JLabel 放入 JPanel 中,并将其显示在列表中。那么让我们来探讨一下。
首先创建一个class来保存JList显示的数据,看起来是一个日期和两行文本:
public class ListItem {
private LocalDate date;
private String text1;
private String text2;
public ListItem(LocalDate date, String text1, String text2) {
super();
this.date = date;
this.text1 = text1;
this.text2 = text2;
}
public LocalDate getDate() {
return date;
}
public String getText1() {
return text1;
}
public String getText2() {
return text2;
}
}
然后让我们创建一个渲染器,JList 可以使用该渲染器在 JPanel 中显示上述信息。这更复杂,需要 class 创建一个 JPanel 将标签放置在我们想要的位置,也许使用具有 1 列和 3 行的 GridLayout,加上行之间的一些间隙:setLayout(new GridLayout(3, 1, 2 * gap, 2 * gap));
。 class 必须实现 ListCellRenderer<T>
接口,该接口具有一个方法:public Component getListCellRendererComponent(...)
。 Java 会将参数传入此方法,包括一个 ListItem 值,我们将使用该值来填充我们添加到此 JPanel 中的 JLabel。编辑以突出显示所选项目。
import java.awt.*;
import java.time.format.DateTimeFormatter;
import javax.swing.*;
import javax.swing.border.Border;
@SuppressWarnings("serial")
public class ListItemRenderer extends JPanel implements ListCellRenderer<ListItem> {
private static final Color LIGHT_BLUE = new Color(204, 255, 255);
private static final Color REDDISH_GREY = new Color(205, 126, 121);
private DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy");
private static final int GAP = 2;
private Border emptyBorder = BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP);
private Border blackBorder = BorderFactory.createLineBorder(Color.BLACK);
private Border redBorder = BorderFactory.createLineBorder(REDDISH_GREY, 2);
private JLabel dateLabel = new JLabel();
private JLabel text1Label = new JLabel();
private JLabel text2Label = new JLabel();
public ListItemRenderer() {
dateLabel.setFont(dateLabel.getFont().deriveFont(Font.BOLD, 14f));
text1Label.setFont(text1Label.getFont().deriveFont(Font.BOLD));
text2Label.setFont(text1Label.getFont().deriveFont(Font.ITALIC));
int gap = 2;
setLayout(new GridLayout(0, 1, 2 * gap, 2 * gap));
setBorder(BorderFactory.createCompoundBorder(emptyBorder, blackBorder));
add(dateLabel);
add(text1Label);
add(text2Label);
}
@Override
public Component getListCellRendererComponent(JList<? extends ListItem> list, ListItem value, int index,
boolean isSelected, boolean cellHasFocus) {
if (value != null) {
String dateText = dateFormatter.format(value.getDate());
dateLabel.setText(dateText);
text1Label.setText(value.getText1());
text2Label.setText(value.getText2());
} else {
dateLabel.setText("");
text1Label.setText("");
text2Label.setText("");
}
if (isSelected ) {
setBackground(LIGHT_BLUE);
setBorder(BorderFactory.createCompoundBorder(emptyBorder, redBorder));
} else {
setBackground(null);
setBorder(BorderFactory.createCompoundBorder(emptyBorder, blackBorder));
}
return this;
}
}
现在是将所有这些放在一起的主程序,经过编辑以显示删除项目:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Random;
import javax.swing.*;
@SuppressWarnings("serial")
public class MainPanel extends JPanel {
DefaultListModel<ListItem> listModel = new DefaultListModel<>();
private JList<ListItem> jList = new JList<>(listModel);
private JScrollPane scrollPane = new JScrollPane(jList);
private JButton addButton = new JButton("Add");
private JButton removeButton = new JButton("Remove");
public MainPanel() {
jList.setPrototypeCellValue(new ListItem(LocalDate.now(),
"This is text 1 for testing. This is text 1 for testing. This is text 1 for testing",
"This is text 2 for testing. This is text 2 for testing. This is text 2 for testing"));
jList.setVisibleRowCount(4);
jList.setCellRenderer(new ListItemRenderer());
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 3, 3));
buttonPanel.add(addButton);
buttonPanel.add(removeButton);
addButton.setMnemonic(KeyEvent.VK_A);
removeButton.setMnemonic(KeyEvent.VK_R);
addButton.addActionListener(e -> addEvent());
removeButton.addActionListener(e -> removeEvent());
JPanel rightPanel = new JPanel();
rightPanel.add(buttonPanel);
int gap = 5;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new BorderLayout());
add(scrollPane);
add(rightPanel, BorderLayout.LINE_END);
}
private void removeEvent() {
int[] selectedIndices = jList.getSelectedIndices();
for (int i = selectedIndices.length - 1; i >= 0; i--) {
listModel.remove(selectedIndices[i]);
}
}
private void addEvent() {
// this adds random stuff to the JList
String text1 = "Some random text: " + randomText();
String text2 = "Some random text: " + randomText();
listModel.addElement(new ListItem(LocalDate.now(), text1, text2));
// TODO: change this so that it adds *real* data to the JList
}
private String randomText() {
Random random = new Random();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 2 + random.nextInt(3); i++) {
for (int j = 0; j < 3 + random.nextInt(5); j++) {
char c = (char) ('a' + random.nextInt('z' - 'a'));
builder.append(c);
}
builder.append(" ");
}
return builder.toString();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
输出如下: