java - 如何在动态添加文本字段到 JPanel 后显示滚动 Pane ?

标签 java swing scrollbar

我正在尝试解决以下问题:我有一个程序,其中文本字段被动态添加到 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 并不是为显式设置像素尺寸而设计的。

enter image description here

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/

相关文章:

java - 比较字符串ArrayList

java.lang.ClassNotFoundException : org. springframework.ui.ModelMap 错误

java - 无法使用 setValueAt 使用自定义 TableModel 更改 JTable 中的值

Java JTextArea - 添加换行符

Java - 修改对象的内部数据,或使用修改后的数据创建新对象

java - 在 Java 中使用 LIBSVM 实现精确度和召回率

java - ActionListener java 遇到问题

Firefox 底部水平滚动条不起作用

html - CSS : Scroll two div side by side independently

html -::webkit-scrollbar 样式不适用于 DOM 元素