我正在尝试解决以下问题:我有一个程序,其中文本字段被动态添加到 JPanel,但是当添加太多字段时,我希望显示滚动条,以便用户不会'不必调整窗口大小才能看到所有字段。到目前为止,我可以毫无问题地生成字段,但添加滚动条似乎不起作用...... 我有以下代码:
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.FlowLayout;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import javax.swing.JScrollBar;
public class AddRuleFrame extends JFrame implements ActionListener {
JPanel panel;
JPanel buttonPanel;
JScrollPane scroll;
private JButton btnAddType;
private JButton btnDeleteField;
private JButton btnSaveRule;
public AddRuleFrame() {
getContentPane().setLayout(new BorderLayout());
this.buttonPanel=new JPanel();
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
//Initializing the JScrollPane
scroll = new JScrollPane(this.panel);
scroll.setViewportView(this.panel);
btnAddType = new JButton("Add type");
btnAddType.addActionListener(this);
buttonPanel.add(btnAddType);
btnDeleteField = new JButton("Delete field");
btnDeleteField.addActionListener(this);
buttonPanel.add(btnDeleteField);
btnSaveRule = new JButton("Save rule");
buttonPanel.add(btnSaveRule);
this.panel = new JPanel();
this.panel.setLayout(new FlowLayout());
getContentPane().add(panel, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(538, 487);
setVisible(true);
}
public void actionPerformed(ActionEvent evt) {
if(evt.getSource()==this.btnAddType){
this.panel.add(new JTextField(20));
this.panel.revalidate();
}
if(evt.getSource()==this.btnDeleteField){
System.out.println("delete pressed");
}
if(evt.getSource()==this.btnSaveRule){
System.out.println("");
}
validate();
}
public static void main(String[] args) {
AddRuleFrame frame = new AddRuleFrame();
}
}
谢谢!
最佳答案
滚动 Pane 的问题很简单,就是您将其添加到任何内容中,并在面板初始化之前设置其视口(viewport)。
但是,我注意到了一些其他问题。
一个问题是 FlowLayout
水平添加组件,因此我将面板的布局更改为 BoxLayout
并创建了 JTextField
的一个小子类来覆盖最大大小。 (BoxLayout
使用最大尺寸来调整组件的大小,因此如果不这样做,文本字段就会拉伸(stretch)到面板的高度。)
我还使用 SwingUtilities.invokeLater
在 Swing 线程上启动程序,如 Initial Threads 中所示。教程。
我没有直接在 JFrame
上调用 setSize
,而是重写 getPreferredSize
并根据屏幕尺寸动态计算尺寸,然后调用 pack()
自动调整组件大小。一般来说,Swing 并不是为显式设置像素尺寸而设计的。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class AddRuleFrame extends JFrame implements ActionListener {
private JPanel panel;
private JPanel buttonPanel;
private JScrollPane scroll;
private JButton btnAddType;
private JButton btnDeleteField;
private JButton btnSaveRule;
public AddRuleFrame() {
getContentPane().setLayout(new BorderLayout());
buttonPanel = new JPanel();
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
btnAddType = new JButton("Add type");
btnAddType.addActionListener(this);
buttonPanel.add(btnAddType);
btnDeleteField = new JButton("Delete field");
btnDeleteField.addActionListener(this);
buttonPanel.add(btnDeleteField);
btnSaveRule = new JButton("Save rule");
buttonPanel.add(btnSaveRule);
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
scroll = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
getContentPane().add(scroll, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null); // this centers the window
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == btnAddType) {
panel.add(new BoxyTextField(20));
panel.revalidate();
}
validate();
}
class BoxyTextField extends JTextField {
BoxyTextField(int width) {
super(width);
}
@Override
public Dimension getMaximumSize() {
Dimension size = super.getMaximumSize();
size.height = getPreferredSize().height;
return size;
}
}
@Override
public Dimension getPreferredSize() {
// See my exchange with MadProgrammer in the comments for
// a discussion of whether Toolkit#getScreenSize() is an
// appropriate way to get the screen dimensions for sizing
// a window.
// Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
// This is the correct way, as suggested in the documentation
// for java.awt.GraphicsEnvironment#getMaximumWindowBounds():
GraphicsConfiguration config = getGraphicsConfiguration();
Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(config);
Dimension size = config.getBounds().getSize();
size.width -= insets.left + insets.right;
size.height -= insets.top + insets.bottom;
// Now we have the actual available space of the screen
// so we can compute a relative size for the JFrame.
size.width = size.width / 3;
size.height = size.height * 2 / 3;
return size;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
AddRuleFrame frame = new AddRuleFrame();
}
});
}
}
<小时/>
对于您的评论,通常使用 BoxLayout
在组件之间添加间隙的正确方法是使用填充组件。这在我已经链接到的教程中进行了讨论。
所以你可以这样做:
@Override
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == btnAddType) {
if (panel.getComponentCount() > 0) {
panel.add(Box.createVerticalStrut(10));
}
panel.add(new BoxyTextField(20));
panel.revalidate();
}
但是,如果您计划动态删除内容,这会产生一些问题,因为您还需要记住删除填充组件:
if (evt.getSource() == btnDeleteField) {
int lastZIndex = panel.getComponentCount() - 1;
if (lastZIndex >= 0) {
panel.remove(lastZIndex);
if (lastZIndex > 0) {
panel.remove(lastZIndex - 1);
}
panel.revalidate();
}
}
validate();
panel.repaint();
}
所以我认为最好的选择是扩展 JPanel
,而不是直接扩展 JTextField
并将文本字段和填充符添加到面板,而是扩展 JPanel
并执行类似的操作:
class BoxyTextFieldCell extends JPanel {
JTextField jTextField;
BoxyTextFieldCell(int width, int margin) {
jTextField = new JTextField(width);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(jTextField);
add(Box.createVerticalStrut(margin));
}
@Override
public Dimension getMaximumSize() {
Dimension size = super.getMaximumSize();
size.height = getPreferredSize().height;
return size;
}
}
@Override
public void actionPerformed(ActionEvent evt) {
if (evt.getSource() == btnAddType) {
panel.add(new BoxyTextFieldCell(20, 10));
panel.revalidate();
}
if (evt.getSource() == btnDeleteField) {
int lastZIndex = panel.getComponentCount() - 1;
if (lastZIndex >= 0) {
panel.remove(lastZIndex);
panel.revalidate();
}
}
validate();
panel.repaint();
}
做这样的事情肯定会给你带来很大的灵 active 。
否则,我认为您也可以使用可编辑的 JTable
使用单个列(其行为或多或少就像一堆文本字段)并使用 setRowMargin(int)
。我想如果您还不太习惯使用布局,那么使用 JTable
可能会更容易。请参阅e.g. here有关在 JTable
中添加和删除行的示例。
关于java - 如何在动态添加文本字段到 JPanel 后显示滚动 Pane ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43739178/