当前位置: 首页 > 知识库问答 >
问题:

如何动态添加元素到JScrollPanel?

江育
2023-03-14

我正在尝试使用Java中的Swing制作一个GUI,它可以执行以下操作:

当按下“添加”按钮时,会创建一个JPanel,并填满图形用户界面的整个宽度。在JPanel中,JLabels将使用FlowLayout来排列,该FlowLayout告诉特定的细节(例如名称、用户ID等)。每当随后按下添加按钮时,我都希望在前面的按钮下添加一个新的JPanel,以便JScrollPane在必要时激活其垂直滚动条。基本上,我希望JScrollPane能够在其中动态添加新的JPanels。

然而,我在尝试这样做时遇到了一些问题。在JScrollPane中,我无法确定要为面板使用哪个LayoutManager。我尝试过使用GridlLayout,但这似乎不起作用,因为当有足够多的JPanel覆盖整个JScrollPane时,GridLayout只会创建一个新列,在新的JPanel中挤压,而不是将其添加到以前的JPanel下面。为了实现这一目标,我应该做些什么?以下是我所拥有的一些图片和我希望发生的事情的一个例子。

以下是我希望发生的事情:

任何帮助将不胜感激,提前感谢!:)

编辑:下面是我用GridLayout尝试的代码示例

public Window() {


    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 701, 400);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    contentPane.setLayout(new BorderLayout(0, 0));
    setContentPane(contentPane);

    JPanel buttonPanel = new JPanel();
    contentPane.add(buttonPanel, BorderLayout.SOUTH);

    JButton btnAdd = new JButton("Add");
    buttonPanel.add(btnAdd);

    JScrollPane scrollPane = new JScrollPane();
    contentPane.add(scrollPane, BorderLayout.CENTER);

    JPanel systemsPanel = new JPanel();
    scrollPane.setViewportView(systemsPanel);
    systemsPanel.setLayout(new GridLayout(8, 1, 0, 0)); //8 rows for now



    for (int i = 1; i < 50; i++) {
        systemsPanel.add(new JButton("test"), "cell 0 " + i);
    }
    Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
    this.setLocation(dim.width / 2 - this.getSize().width / 2, dim.height / 2 - this.getSize().height / 2); //Center the Frame 

}

共有1个答案

施晗日
2023-03-14

如果您想将行JPanel添加到GUI中,我会将它们放在使用GridLayout(0,1)或(0,1,x,y)的JPanel中。0表示行数可变,1表示1列,x和y表示垂直和水平间隙。然后,我将使用JPanel将其放置到BorderLayout中的NORTH位置,这样行就不会像它们希望的那样展开以填充scrollpane的视口。我将第二个包装器JPanel放入JScrollPane的视口中。

添加任何组件后,我将调用容器上的revalidate和repait,以便其布局管理器能够激活并正确放置新组件,并重新绘制以去除可能挂起的任何脏像素(在移除组件时更为重要)。

例如,我的MCVE:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;

import javax.swing.*;

public class AddRowA extends JPanel {
    private static final int PREF_W = 650;
    private static final int PREF_H = 400;

    // JPanel to hold all rows. uses gridlayout that has 1 column and variable number
    // of rows
    private JPanel rowHolderPanel = new JPanel(new GridLayout(0, 1, 1, 1));

    public AddRowA() {
        // outerPanel is a wrapper or container JPanel that is 
        // held by JScrollPane's viewport that holds the rowHolderPanel in 
        // a BorderLayout.PAGE_START location, so the rows don't expand unnecessarily
        JPanel outerPanel = new JPanel(new BorderLayout());
        outerPanel.add(rowHolderPanel, BorderLayout.PAGE_START);
        JScrollPane scrollPane = new JScrollPane(outerPanel);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        JPanel addPanel = new JPanel();
        addPanel.add(new JButton(new AddAction("Add")));

        setLayout(new BorderLayout());
        add(scrollPane, BorderLayout.CENTER);
        add(addPanel, BorderLayout.PAGE_END);
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    private class AddAction extends AbstractAction {
        public AddAction(String name) {
            super(name);
            int mnemonic = (int) name.charAt(0);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            JPanel panel = new JPanel();
            panel.add(new JLabel("Foo"));
            panel.add(Box.createHorizontalStrut(25));
            panel.add(new JButton("Bar"));
            panel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 3));

            rowHolderPanel.add(panel);
            rowHolderPanel.revalidate();
            rowHolderPanel.repaint();
        }
    }

    private static void createAndShowGui() {
        JFrame frame = new JFrame("Add Row A");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new AddRowA());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

但是,你最好使用JTable。。。例如:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class AddRowB extends JPanel {
    private MyTableModel tableModel = new MyTableModel();
    private JTable table = new JTable(tableModel);

    public AddRowB() {
        JPanel addPanel = new JPanel();
        addPanel.add(new JButton(new AddAction("Add")));

        setLayout(new BorderLayout());
        add(new JScrollPane(table));
        add(addPanel, BorderLayout.PAGE_END);
    }

    private class AddAction extends AbstractAction {
        public AddAction(String name) {
            super(name);
            int mnemonic = (int) name.charAt(0);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            RowData row = new RowData("Type", "Address", "User ID");
            tableModel.addRow(row);
        }
    }

    private static void createAndShowGui() {
        JFrame frame = new JFrame("Add Row B");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new AddRowB());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

class MyTableModel extends DefaultTableModel {
    private static final String[] COLUMNS = {"Type", "Address", "User ID"};

    public MyTableModel() {
        super(COLUMNS, 0);
    }

    public void addRow(RowData rowData) {
        Object[] row = {
                rowData.getType(),
                rowData.getAddress(),
                rowData.getUserID()
        };
        addRow(row);
    }
}

class RowData {
    String type;
    String address;
    String userID;

    public RowData(String type, String address, String userID) {
        this.type = type;
        this.address = address;
        this.userID = userID;
    }

    public String getType() {
        return type;
    }

    public String getAddress() {
        return address;
    }

    public String getUserID() {
        return userID;
    }

}
 类似资料:
  • 问题内容: 我想将通过JSOn格式的URL接收的数据动态附加到我的列表视图中。但是我不知道它是如何工作的。 移动网站以以下格式检索对象: 在.html中,我有一个listview和一个函数,在其中尝试附加接收到的数据。我只展示身体。 也许这很容易,但是我是Web编程的新手,我不知道该如何附加检索到的数据。 有人可以帮我吗? 问题答案: 这是上述解决方案的jsfiddle(还有一个使用 代替的示例

  • 问题内容: 我有以下代码: Angular2中 有什么方法可以将HTML添加到中吗?因为上述内容仅添加到组件HTML的末尾。 我也尝试过: 但这是行不通的,因为@ViewChild指令必须在函数之外,我再也无法控制它了 我也这样尝试过: 我不能做的事情是因为我的内容是动态的并且使用唯一的ID,并且我不能动态使用[innerHtml](它仅适用于我第一次放入它们的面板,然后其他任何更改都不能再使用i

  • 问题内容: 我使用jquery fancybox 1.3.4作为弹出表单。 但是我发现fancybox无法绑定到动态添加的元素。例如,当我向当前文档中添加html元素时。 像这样:首先我使用jquery将一个元素附加到主体, 我叫fancybox, 但fancybox不适用于动态添加的元素。 我不能从此元素调用fancybox吗? 问题答案: 将fancybox(v1.3.x)绑定到动态添加的元素

  • 我读过许多关于动态添加字段集的博客和帖子,但它们都给出了非常复杂的答案。我要求的不是那么复杂。 我的HTML代码: 因此,用户将在字段中输入一个整数值(我正在使用javascript检查验证)。点击链接,会出现相应数量的输入字段供他输入。我想用javascript实现这一点。 我不是javascript方面的专家。我在想如何通过链接检索用户在字段中填写的整数,并显示相应数量的输入字段。

  • 我对JavaFX相对较新,我很困惑为什么我下面的代码没有产生预期的结果,即添加到网格中的标签。 我想做的是运行一个测试,将JavaFX标签添加到我的FXML GridPane,因为我想在不久的将来构建一个方法,允许用户选择一个文件,然后在用户选择文件时生成一个标签并将该标签添加到GridPane。 提前感谢, 代码: FXML代码是一个标准文件,其中定义了一个网格窗格,上面列出了fx:id。

  • 问题内容: 我已经有了一个状态: 现在,我想用新信息对其进行更新。因此,向其添加另一个div。 像这样: 我该怎么做?或者我需要从零开始设置新状态 问题答案: 我认为以组件状态存储jsx组件不是一个好主意。我认为您应该仅以呈现组件所需的状态保存数据。 如果您真的想在状态中存储jsx,为什么不将“对话”属性定义为数组?然后,您可以向其中添加新组件。 但是最好只存储数据,例如“ first”和“ ne