当滚动条出现时,JScrollPane会调整包含JPanel的大小

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

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

现在当出现垂直滚动条时,它会占用我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(); } } }); } } 

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

 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视口内视图的大小应始终等于首选大小。 在我看来,视图大小应该与视口的实际大小而不是其首选大小进行比较。

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

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

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

 buttonContainer.setPreferredSize(Dimension d);