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

时间:2017-03-31 17:02:20

标签: java swing dynamic components jscrollbar

我正在尝试实现一个功能(在我的测试项目中)一旦按下按钮,它会向我的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();
    }
}

enter image description here

enter image description here

我需要他们看起来完全一样。在我拥有现在的代码之前,滚动条会显示在看起来很难看的数字上。我的框架可调整大小错误的原因是因为在我的真实程序中我硬编码了所有尺寸,未来我将根据框架的大小计算正确的尺寸,所以现在设置可调整为真是不合适的这个问题。关于该怎么做的任何建议?

enter image description here

这就是我想要的东西。

1 个答案:

答案 0 :(得分:1)

摆脱设置首选/最小/最大尺寸的所有逻辑。每个组件都知道它的大小。每个布局管理器将反过来知道面板的首选大小应该是什么。让布局管理器使用该信息来完成其工作。

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

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

然后,滚动条将在需要时自动显示。没有听众或其他任何东西。

编辑:

  

我设置所有尺寸的原因是因为如果我拿出它们,那么一切都会显示在中心

了解如何正确有效地使用布局管理器。

例如,使用BoxLayout时,您可以使用以下方法控制组件的对齐:

component.setAlignmentX(JLabel.RIGHT_ALIGNMENT);

,组件将与组件可用空间的右边缘对齐。

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