9

JScrollPane在我的 Java 应用程序中使用时有一个小问题。

我有一个JScrollPane包含一个JPanel. 这JPanel是使用可以是任何宽度的按钮(垂直排序)动态更新的。自动将JPanel其宽度调整为JButton内部最大的组件。

现在,当垂直滚动条出现时,它占用了 my 右侧的一些空间JPanel,这导致最大的按钮不会完全出现。除了显示整个按钮之外,我不想使用水平滚动条。

有没有办法JPanel在出现滚动条时调整我的大小,以便它很好地出现在我的按钮旁边?或者有没有其他方法可以让滚动条出现在我的旁边JPanel

提前致谢!

编辑:这是我的问题的演示。当您将窗口大小调整为较小的高度时,右侧的一小部分按钮会被覆盖。

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.GridLayout;

/**
 * @author Dylan Kiss
 */

public class Demo {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    JFrame myFrame = new JFrame("Demo");
                    JPanel sideBar = new JPanel();
                    JPanel centerPanel = new JPanel();
                    centerPanel.add(new JLabel("This is the center panel."));

                    JPanel buttonContainer = new JPanel();
                    JButton myButton = null;

                    for (int i = 0; i < 20; i++) {
                        buttonContainer.setLayout(new GridLayout(20, 1, 0, 0));
                        myButton = new JButton("This is my button nr. " + i);
                        buttonContainer.add(myButton);
                    }

                    sideBar.setLayout(new BorderLayout(0, 0));

                    JScrollPane scrollPane = new JScrollPane(buttonContainer);

                    sideBar.add(scrollPane);

                    myFrame.getContentPane().add(sideBar, BorderLayout.WEST);
                    myFrame.getContentPane().add(centerPanel, BorderLayout.CENTER);

                    myFrame.setLocationByPlatform(true);
                    myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    myFrame.pack();
                    myFrame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
4

3 回答 3

6

这是一个简单但不漂亮的解决方案:

scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

编辑:我认为在你的情况下这可能不起作用。这是一个更好的解决方案,尽管它有很多样板:

private class ButtonContainerHost extends JPanel implements Scrollable {
    private static final long serialVersionUID = 1L;

    private final JPanel buttonContainer;

    public ButtonContainerHost(JPanel buttonContainer) {
        super(new BorderLayout());
        this.buttonContainer = buttonContainer;
        add(buttonContainer);
    }

    @Override
    public Dimension getPreferredScrollableViewportSize() {
        Dimension preferredSize = buttonContainer.getPreferredSize();
        if (getParent() instanceof JViewport) {
            preferredSize.width += ((JScrollPane) getParent().getParent()).getVerticalScrollBar()
                    .getPreferredSize().width;
        }
        return preferredSize;
    }

    @Override
    public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
        return orientation == SwingConstants.HORIZONTAL ? Math.max(visibleRect.width * 9 / 10, 1)
                : Math.max(visibleRect.height * 9 / 10, 1);
    }

    @Override
    public boolean getScrollableTracksViewportHeight() {
        if (getParent() instanceof JViewport) {
            JViewport viewport = (JViewport) getParent();
            return getPreferredSize().height < viewport.getHeight();
        }
        return false;
    }

    @Override
    public boolean getScrollableTracksViewportWidth() {
        return true;
    }

    @Override
    public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
        return orientation == SwingConstants.HORIZONTAL ? Math.max(visibleRect.width / 10, 1)
                : Math.max(visibleRect.height / 10, 1);
    }
}

它实现了 Scrollable 以获得对滚动的完全控制,通过跟踪视口高度来确保按钮在空间可用时展开,并始终将垂直滚动条的宽度添加到首选宽度。当垂直滚动条可见时它可能会扩展,但无论如何看起来很糟糕。像这样使用它:

scrollPane = new JScrollPane(new ButtonContainerHost(buttonContainer));

在我看来,由于 javax.swing.ScrollPaneLayout 中可能存在错误,因此需要这种解决方法:

if (canScroll && (viewSize.height > extentSize.height)) {
    prefWidth += vsb.getPreferredSize().width;
}

这里extentSize 设置为视口的首选大小,viewSize 设置为viewport.getViewSize()。这似乎不正确,AFAIK 视口内的视图大小应始终等于首选大小。在我看来,视图大小应该与视口的实际大小而不是其首选大小进行比较。

于 2012-04-26T11:25:54.943 回答
2

一个简单的解决方法,以满足您的要求

Is there a way to resize my JPanel when a scrollbar appears, so it 
appears nicely next to my buttons? 

EmptyBorder的使用,这会让你实现你想要的,应该发生的,如下图所示:

滚动条设置

我刚刚在这行之后添加了下面写的这行JPanel buttonContainer = new JPanel();

加线

buttonContainer.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

这是您添加的代码:

import java.awt.BorderLayout;
import java.awt.EventQueue;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.GridLayout;

/**
 * @author Dylan Kiss
 */

public class Demo 
{
    public static void main(String[] args) 
    {
        EventQueue.invokeLater(new Runnable() 
        {
            @Override
            public void run() 
            {
                try 
                {
                    JFrame myFrame = new JFrame("Demo");
                    JPanel sideBar = new JPanel();
                    JPanel centerPanel = new JPanel();
                    centerPanel.add(new JLabel("This is the center panel."));

                    JPanel buttonContainer = new JPanel();
                    buttonContainer.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
                    JButton myButton = null;

                    for (int i = 0; i < 20; i++) 
                    {
                        buttonContainer.setLayout(new GridLayout(20, 1, 0, 0));
                        myButton = new JButton("This is my button nr. " + i);
                        buttonContainer.add(myButton);
                    }

                    sideBar.setLayout(new BorderLayout(0, 0));

                    JScrollPane scrollPane = new JScrollPane(buttonContainer);      

                    sideBar.add(scrollPane);

                    myFrame.getContentPane().add(sideBar, BorderLayout.WEST);
                    myFrame.getContentPane().add(centerPanel, BorderLayout.CENTER);

                    myFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                    myFrame.pack();
                    myFrame.setLocationByPlatform(true);
                    myFrame.setVisible(true);
                } 
                catch (Exception e) 
                {
                    e.printStackTrace();
                }
            }
        });
    }
}
于 2012-04-26T13:01:06.977 回答
0

当 JPanel 需要调整大小时,您可以通过调用 setPreferredSize 来调整 JPanel 的大小。

buttonContainer.setPreferredSize(Dimension d);
于 2012-04-26T11:38:08.933 回答