Java在滚动条出现时动态更改组件

Java在滚动条出现时动态更改组件,java,swing,dynamic,components,jscrollbar,Java,Swing,Dynamic,Components,Jscrollbar,我正在尝试实现一个特性,在我的测试项目中,一旦按下一个按钮,它就会向我的JPanel添加一个随机数。我使用我的布局,因为在我的真实程序中,我有更多的项目在里面,它显示正确。但是我需要我的程序来识别我实现的滚动条何时可见,但是有点延迟。我所说的延迟是指我按下按钮添加一个数字,如果滚动条变为可见,则什么也不会发生。但下一次我按下按钮时,它会像我想的那样移动。我现在关注的另一个问题是,当我动态更改JPanel的大小时,如果滚动条可见,我将其设置为将宽度更改为我的宽度-滚动条的宽度。但当滚动条可见时,新

我正在尝试实现一个特性,在我的测试项目中,一旦按下一个按钮,它就会向我的JPanel添加一个随机数。我使用我的布局,因为在我的真实程序中,我有更多的项目在里面,它显示正确。但是我需要我的程序来识别我实现的滚动条何时可见,但是有点延迟。我所说的延迟是指我按下按钮添加一个数字,如果滚动条变为可见,则什么也不会发生。但下一次我按下按钮时,它会像我想的那样移动。我现在关注的另一个问题是,当我动态更改JPanel的大小时,如果滚动条可见,我将其设置为将宽度更改为我的宽度-滚动条的宽度。但当滚动条可见时,新输入的数字似乎会移动两倍于滚动条宽度,而不是一次。我已经在我的程序的这一部分工作了一天多,但我想不出来。我将添加我的完整代码和一些屏幕截图

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;


public class Main {
    JFrame frame;
    JPanel topPanel;
    JPanel memoryPanel;
    JScrollPane sPane;
    JButton button;
    ArrayList<Integer> list = new ArrayList<>();
    boolean isVScrollVisible = false;
    int scrollBarSize = 0;

    public class MyChangeListener implements ChangeListener {
        @Override
        public void stateChanged(ChangeEvent e) {
            isVScrollVisible = (sPane.getVerticalScrollBar().isVisible());
        }
    }

    public class ButtonListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            Random random = new Random();
            int r = random.nextInt(10);

            list.add(r);

            int n;
            if (isVScrollVisible) {
                n = scrollBarSize;
            } else {
                n = 0;
            }

            JPanel nextPanel = new JPanel();
            nextPanel.setName("" + r);
            nextPanel.setForeground(Color.BLACK);
            nextPanel.setPreferredSize(new Dimension(200 - n, 55));
            nextPanel.setMinimumSize(new Dimension(200 - n, 55));
            nextPanel.setMaximumSize(new Dimension(200 - n, 55));

            JPanel labelPanel = new JPanel();
            labelPanel.setLayout(new BorderLayout());

            JLabel label = new JLabel();
            label.setText("" + r);
            label.setPreferredSize(new Dimension(200 - n, 55));
            label.setMinimumSize(new Dimension(200 - n, 55));
            label.setMaximumSize(new Dimension(200 - n, 55));
            label.setHorizontalAlignment(JLabel.RIGHT);
            label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 17));
            label.setFont(new Font("Sans-Serif", Font.BOLD, 20));
            labelPanel.add(label);

            nextPanel.add(labelPanel, BorderLayout.LINE_START);

            for (int i = 0; i < memoryPanel.getComponents().length; i++) {
                memoryPanel.getComponent(i).setPreferredSize(new Dimension(200 - n, 55));
                memoryPanel.getComponent(i).revalidate();
                memoryPanel.getComponent(i).repaint();
            }


            memoryPanel.add(nextPanel, 0);

            memoryPanel.revalidate();
            memoryPanel.repaint();
            sPane.revalidate();
            sPane.repaint();
        }
    }

    public Main() {
        frame = new JFrame();

        topPanel = new JPanel();
        memoryPanel = new JPanel();
        memoryPanel.setLayout(new BoxLayout(memoryPanel, BoxLayout.Y_AXIS));

        sPane = new JScrollPane(memoryPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        sPane.setPreferredSize(new Dimension(200, 300));
        sPane.getViewport().addChangeListener(new MyChangeListener());

        scrollBarSize = ((Integer)UIManager.get("ScrollBar.width")) + 1;

        button = new JButton("Add Random Number");
        button.addActionListener(new ButtonListener());

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());

        topPanel.add(button);

        frame.add(topPanel, BorderLayout.PAGE_START);
        frame.add(sPane, BorderLayout.CENTER);

        frame.setResizable(false);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new Main();
    }
}
我需要它们看起来完全一样。在我得到现在的代码之前,滚动条会出现在看起来很难看的数字上。我之所以将框架大小设置为false,是因为在我的实际程序中,我硬编码了所有的大小,将来我会根据框架的大小计算出正确的大小,所以现在将resizeable设置为true是不可能的。有什么建议吗


这正是我试图做到的。

摆脱所有设置首选/最小/最大大小的逻辑。每个组件都知道其大小。每个布局管理器将依次知道面板的首选尺寸。让布局管理器使用这些信息来完成其工作

动态添加组件的基本逻辑是:

panel.add(...);
panel.revalidate();
panel.repaint();
然后,滚动条将在需要时自动显示。不需要听众或任何东西

编辑:


我设置所有尺寸的原因是,如果我把它们拿出来,那么所有的东西都会居中

学习如何正确有效地使用布局管理器

例如,在使用BoxLayout时,可以通过以下方式控制零部件的对齐:

component.setAlignmentX(JLabel.RIGHT_ALIGNMENT);
组件将与组件可用空间的右边缘对齐


使用JLabel时,可能还需要在JLabel上设置一个属性,以便将文本与标签的右边缘对齐。阅读JLabel API以了解适当的方法。

我设置所有大小的原因是,如果我将它们取出,则所有内容都将显示为中心1似乎此用例更适合于带有ListCellRenderer的JScrollPane中的JList。。2当存在定义的常量时,不要猜测字体名称,例如,new FontSans Serif,font.BOLD,20应为new FontFont.SANS_Serif,font.BOLD,20我没有使用JList,因为在我的实际程序中,每个标签都有按钮。按钮的作用是什么?我基本上是用java lol创建一个windows 10计算器。这些数字将在内存历史记录中显示存储的数字。然后,按钮将清除内存,向存储的数字添加一个数字或从存储的数字中减去一个数字。如果你有windows 10,它是计算器上最右边的内存按钮。你是说像在计算机上看到的那样吗?我看到列表下方有一个“清除所有历史记录”按钮,但列表项本身没有按钮。这将有可能在JList中复制。