当滚动条出现时,JScrollPane会调整包含JPanel的大小 [英] JScrollPane resize containing JPanel when scrollbars appear

查看:131
本文介绍了当滚动条出现时,JScrollPane会调整包含JPanel的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a small problem when using JScrollPane in my Java application.

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

I have a JScrollPane containing a JPanel. This JPanel is dynamically updated with buttons (vertically ordered) that can be of any width. The JPanel automatically adjusts its width to the largest JButton component inside.

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

Now when the vertical scrollbar appears, it takes away some space on the right side of my JPanel, which causes the largest buttons not to appear completely. I don't want to use a horizontal scrollbar in addition to display the whole button.

有没有办法调整我的 JPanel 当滚动条出现时,它显示在我的按钮旁边?或者还有其他方法让滚动条出现在我的 JPanel 旁边吗?

Is there a way to resize my JPanel when a scrollbar appears, so it appears nicely next to my buttons? Or is there any other way to have the scrollbar appear next to my JPanel?

提前致谢!

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

EDIT: Here is a demo of my problem. When you resize the window to a smaller height, a little part of the buttons on the right side gets covered.

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();
                }
            }
        });
    }
}


推荐答案

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

Here is a simple, not pretty, solution:

scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

编辑:
我认为这可能无法完成你的工作。这是一个更好的解决方案,虽然它有很多样板:

I thought that might not do the job in your case. Here is a better solution although it has quite a lot of boilerplate:

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以完全控制滚动,是吗一个奇特的技巧,跟踪视口高度,以确保按钮在空间可用时展开,并在任何时候将垂直滚动条的宽度添加到首选宽度。它可以在垂直滚动条可见时展开,但无论如何看起来都很糟糕。像这样使用它:

It implements Scrollable to get full control of scrolling, does a fancy trick with tracking the viewport height to ensure the buttons expand when the space is available and adds on the width of the vertical scroll bar to the preferred width at all times. It could expand when the vertical scroll bar is visible but that looks bad anyway. Use it like this:

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

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

It looks to me like this workaround is required because of a possible bug in javax.swing.ScrollPaneLayout:

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

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

Here extentSize is set to the preferred size of the viewport and viewSize is set to viewport.getViewSize(). This does not seem correct, AFAIK the size of the view inside the viewport should always equal the preferred size. It seems to me that the view size should be compared to the actual size of the viewport rather than its preferred size.

这篇关于当滚动条出现时,JScrollPane会调整包含JPanel的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆