2014-02-26 97 views
0

我试图在另一个JScrollPane中添加JScrollPane。 内部JScrollPane只会滚动HORIZONTAL,而外部只会滚动VERTICAL。JScrollPane中的JScrollPane

在这张图片中可以看到,水平滚动条添加mainPanel时工作(但不加入横向滚动条尚)

enter image description here

这里是添加outerVerticalScroller时到JFrame(在它的外观单杠消失):

enter image description here

任何想法如何可以这样做?

如果我跳过mainPanel,而是键入:

JScrollPane outerVerticalScroller = new JScrollPane(panelScroller, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 

然后,它看起来完美与两个滚动条:

enter image description here

但我需要那额外 “的mainPanel”。有任何想法吗?

public class ScrollersTest extends JFrame { 

    public ScrollersTest() { 
     super("A JScrollPane inside a JScrollPane"); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     init(); 
     setVisible(true); 
     pack(); 
    } 

    public void init() { 
     ScrollablePanel panelScroller = new ScrollablePanel(new GridBagLayout()); 
     panelScroller.setScrollableWidth(ScrollablePanel.ScrollableSizeHint.FIT); 

     GridBagConstraints c = new GridBagConstraints(); 

     // INNER SCROLLPANE: ONLY SCROLL HORIZONTAL 
     JTextArea innerText = new JTextArea("This text is inside a JScrollPane of its own. But no scroller is shown when the frames size is decreased. Wrong viewPort?...................................."); 
     JScrollPane innerHorizantalScroller = new JScrollPane(innerText, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 
     c.fill = GridBagConstraints.HORIZONTAL; 
     c.weightx = 1; 
     panelScroller.add(innerHorizantalScroller, c); 

     // SET SIZE OF SCROLLER HEIGHT 
     Dimension d = innerHorizantalScroller.getPreferredSize(); 
     innerHorizantalScroller.setPreferredSize(new Dimension(d.width, d.height * 2)); 
     innerHorizantalScroller.setMinimumSize(new Dimension(0, d.height * 2)); 

     // EXTRA PANEL NEEDED (BUT MAKES HORIZANTAL SCROLLING DISAPEAR) 
     JPanel mainPanel = new JPanel(new BorderLayout()); 
     mainPanel.add(panelScroller, BorderLayout.CENTER); 

     // THE FRAME SCROLLPANE: ONLY SCROLL VERTICAL 
     JScrollPane outerVerticalScroller = new JScrollPane(mainPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
     // WORKS BUT NO MAINPANEL 
     // JScrollPane outerVerticalScroller = new JScrollPane(panelScroller, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 

     getContentPane().add(outerVerticalScroller, BorderLayout.CENTER); 
     // getContentPane().add(mainPanel, BorderLayout.CENTER); // WORKS_BUT_NO_VERTICAL_SCROLL 
    } 

    public static void main(String args[]) { 
     new ScrollersTest(); 
    } 

    static class ScrollablePanel extends JPanel implements Scrollable, SwingConstants { 
     public enum ScrollableSizeHint { 
      NONE, FIT, STRETCH; 
     } 

     public enum IncrementType { 
      PERCENT, PIXELS; 
     } 

     private ScrollableSizeHint scrollableHeight = ScrollableSizeHint.NONE; 
     private ScrollableSizeHint scrollableWidth = ScrollableSizeHint.NONE; 

     private IncrementInfo horizontalBlock; 
     private IncrementInfo horizontalUnit; 
     private IncrementInfo verticalBlock; 
     private IncrementInfo verticalUnit; 

     /** 
     * Default constructor that uses a FlowLayout 
     */ 
     public ScrollablePanel() { 
      this(new FlowLayout()); 
     } 

     /** 
     * Constuctor for specifying the LayoutManager of the panel. 
     * 
     * @param layout 
     *   the LayountManger for the panel 
     */ 
     public ScrollablePanel(LayoutManager layout) { 
      super(layout); 

      IncrementInfo block = new IncrementInfo(IncrementType.PERCENT, 100); 
      IncrementInfo unit = new IncrementInfo(IncrementType.PERCENT, 10); 

      setScrollableBlockIncrement(HORIZONTAL, block); 
      setScrollableBlockIncrement(VERTICAL, block); 
      setScrollableUnitIncrement(HORIZONTAL, unit); 
      setScrollableUnitIncrement(VERTICAL, unit); 
     } 

     /** 
     * Get the height ScrollableSizeHint enum 
     * 
     * @return the ScrollableSizeHint enum for the height 
     */ 
     public ScrollableSizeHint getScrollableHeight() { 
      return scrollableHeight; 
     } 

     /** 
     * Set the ScrollableSizeHint enum for the height. The enum is used to 
     * determine the boolean value that is returned by the 
     * getScrollableTracksViewportHeight() method. The valid values are: 
     * 
     * ScrollableSizeHint.NONE - return "false", which causes the height of 
     * the panel to be used when laying out the children 
     * ScrollableSizeHint.FIT - return "true", which causes the height of 
     * the viewport to be used when laying out the children 
     * ScrollableSizeHint.STRETCH - return "true" when the viewport height 
     * is greater than the height of the panel, "false" otherwise. 
     * 
     * @param scrollableHeight 
     *   as represented by the ScrollableSizeHint enum. 
     */ 
     public void setScrollableHeight(ScrollableSizeHint scrollableHeight) { 
      this.scrollableHeight = scrollableHeight; 
      revalidate(); 
     } 

     /** 
     * Get the width ScrollableSizeHint enum 
     * 
     * @return the ScrollableSizeHint enum for the width 
     */ 
     public ScrollableSizeHint getScrollableWidth() { 
      return scrollableWidth; 
     } 

     /** 
     * Set the ScrollableSizeHint enum for the width. The enum is used to 
     * determine the boolean value that is returned by the 
     * getScrollableTracksViewportWidth() method. The valid values are: 
     * 
     * ScrollableSizeHint.NONE - return "false", which causes the width of 
     * the panel to be used when laying out the children 
     * ScrollableSizeHint.FIT - return "true", which causes the width of the 
     * viewport to be used when laying out the children 
     * ScrollableSizeHint.STRETCH - return "true" when the viewport width is 
     * greater than the width of the panel, "false" otherwise. 
     * 
     * @param scrollableWidth 
     *   as represented by the ScrollableSizeHint enum. 
     */ 
     public void setScrollableWidth(ScrollableSizeHint scrollableWidth) { 
      this.scrollableWidth = scrollableWidth; 
      revalidate(); 
     } 

     /** 
     * Get the block IncrementInfo for the specified orientation 
     * 
     * @return the block IncrementInfo for the specified orientation 
     */ 
     public IncrementInfo getScrollableBlockIncrement(int orientation) { 
      return orientation == SwingConstants.HORIZONTAL ? horizontalBlock : verticalBlock; 
     } 

     /** 
     * Specify the information needed to do block scrolling. 
     * 
     * @param orientation 
     *   specify the scrolling orientation. Must be either: 
     *   SwingContants.HORIZONTAL or SwingContants.VERTICAL. 
     * @paran type specify how the amount parameter in the calculation of 
     *  the scrollable amount. Valid values are: IncrementType.PERCENT 
     *  - treat the amount as a % of the viewport size 
     *  IncrementType.PIXEL - treat the amount as the scrollable 
     *  amount 
     * @param amount 
     *   a value used with the IncrementType to determine the 
     *   scrollable amount 
     */ 
     public void setScrollableBlockIncrement(int orientation, IncrementType type, int amount) { 
      IncrementInfo info = new IncrementInfo(type, amount); 
      setScrollableBlockIncrement(orientation, info); 
     } 

     /** 
     * Specify the information needed to do block scrolling. 
     * 
     * @param orientation 
     *   specify the scrolling orientation. Must be either: 
     *   SwingContants.HORIZONTAL or SwingContants.VERTICAL. 
     * @param info 
     *   An IncrementInfo object containing information of how to 
     *   calculate the scrollable amount. 
     */ 
     public void setScrollableBlockIncrement(int orientation, IncrementInfo info) { 
      switch (orientation) { 
      case SwingConstants.HORIZONTAL: 
       horizontalBlock = info; 
       break; 
      case SwingConstants.VERTICAL: 
       verticalBlock = info; 
       break; 
      default: 
       throw new IllegalArgumentException("Invalid orientation: " + orientation); 
      } 
     } 

     /** 
     * Get the unit IncrementInfo for the specified orientation 
     * 
     * @return the unit IncrementInfo for the specified orientation 
     */ 
     public IncrementInfo getScrollableUnitIncrement(int orientation) { 
      return orientation == SwingConstants.HORIZONTAL ? horizontalUnit : verticalUnit; 
     } 

     /** 
     * Specify the information needed to do unit scrolling. 
     * 
     * @param orientation 
     *   specify the scrolling orientation. Must be either: 
     *   SwingContants.HORIZONTAL or SwingContants.VERTICAL. 
     * @paran type specify how the amount parameter in the calculation of 
     *  the scrollable amount. Valid values are: IncrementType.PERCENT 
     *  - treat the amount as a % of the viewport size 
     *  IncrementType.PIXEL - treat the amount as the scrollable 
     *  amount 
     * @param amount 
     *   a value used with the IncrementType to determine the 
     *   scrollable amount 
     */ 
     public void setScrollableUnitIncrement(int orientation, IncrementType type, int amount) { 
      IncrementInfo info = new IncrementInfo(type, amount); 
      setScrollableUnitIncrement(orientation, info); 
     } 

     /** 
     * Specify the information needed to do unit scrolling. 
     * 
     * @param orientation 
     *   specify the scrolling orientation. Must be either: 
     *   SwingContants.HORIZONTAL or SwingContants.VERTICAL. 
     * @param info 
     *   An IncrementInfo object containing information of how to 
     *   calculate the scrollable amount. 
     */ 
     public void setScrollableUnitIncrement(int orientation, IncrementInfo info) { 
      switch (orientation) { 
      case SwingConstants.HORIZONTAL: 
       horizontalUnit = info; 
       break; 
      case SwingConstants.VERTICAL: 
       verticalUnit = info; 
       break; 
      default: 
       throw new IllegalArgumentException("Invalid orientation: " + orientation); 
      } 
     } 

     // Implement Scrollable interface 

     public Dimension getPreferredScrollableViewportSize() { 
      return getPreferredSize(); 
     } 

     public int getScrollableUnitIncrement(Rectangle visible, int orientation, int direction) { 
      switch (orientation) { 
      case SwingConstants.HORIZONTAL: 
       return getScrollableIncrement(horizontalUnit, visible.width); 
      case SwingConstants.VERTICAL: 
       return getScrollableIncrement(verticalUnit, visible.height); 
      default: 
       throw new IllegalArgumentException("Invalid orientation: " + orientation); 
      } 
     } 

     public int getScrollableBlockIncrement(Rectangle visible, int orientation, int direction) { 
      switch (orientation) { 
      case SwingConstants.HORIZONTAL: 
       return getScrollableIncrement(horizontalBlock, visible.width); 
      case SwingConstants.VERTICAL: 
       return getScrollableIncrement(verticalBlock, visible.height); 
      default: 
       throw new IllegalArgumentException("Invalid orientation: " + orientation); 
      } 
     } 

     protected int getScrollableIncrement(IncrementInfo info, int distance) { 
      if (info.getIncrement() == IncrementType.PIXELS) 
       return info.getAmount(); 
      else 
       return distance * info.getAmount()/100; 
     } 

     public boolean getScrollableTracksViewportWidth() { 
      if (scrollableWidth == ScrollableSizeHint.NONE) 
       return false; 

      if (scrollableWidth == ScrollableSizeHint.FIT) 
       return true; 

      // STRETCH sizing, use the greater of the panel or viewport width 

      if (getParent() instanceof JViewport) { 
       return (((JViewport) getParent()).getWidth() > getPreferredSize().width); 
      } 

      return false; 
     } 

     public boolean getScrollableTracksViewportHeight() { 
      if (scrollableHeight == ScrollableSizeHint.NONE) 
       return false; 

      if (scrollableHeight == ScrollableSizeHint.FIT) 
       return true; 

      // STRETCH sizing, use the greater of the panel or viewport height 

      if (getParent() instanceof JViewport) { 
       return (((JViewport) getParent()).getHeight() > getPreferredSize().height); 
      } 

      return false; 
     } 

     /** 
     * Helper class to hold the information required to calculate the scroll 
     * amount. 
     */ 
     static class IncrementInfo { 
      private IncrementType type; 
      private int amount; 

      public IncrementInfo(IncrementType type, int amount) { 
       this.type = type; 
       this.amount = amount; 
      } 

      public IncrementType getIncrement() { 
       return type; 
      } 

      public int getAmount() { 
       return amount; 
      } 

      public String toString() { 
       return "ScrollablePanel[" + type + ", " + amount + "]"; 
      } 
     } 
    } 
} 
+4

Y你需要一个JScrollPane在另一个JscrollPane内吗? – ItachiUchiha

+0

@IchichiUchiha可以说我在内部JScrollPane之前和之后有大量数据。然后,只需滚动需要滚动的内容而不滚动整个框架就会看起来更好。 – Grains

+0

我认为最好的方法是http://www.java2s.com/Code/Java/Swing-JFC/AquickdemonstrationofJScrollBarbothverticalandhorizo​​ntal。htm –

回答

1
import java.awt.BorderLayout; 
    import java.awt.GridBagConstraints; 
    import java.awt.GridBagLayout; 
    import javax.swing.JFrame; 
    import javax.swing.JLabel; 
    import javax.swing.JPanel; 
    import javax.swing.*; 
    import java.awt.*; 

class ScrollersTest { 
public static void main(String args[]) { 
JFrame frame = new JFrame("Tabbed Pane Sample"); 
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
JTextArea innerText = new JTextArea("This text is inside a JScrollPane of its own." 
     +" But no scroller is shown when the frames size is decreased. Wrong viewPort?....................................\n" 
     +" But no scroller is shown when the frames size is decreased. Wrong viewPort?....................................\n" 
     +" But no scroller is shown when the frames size is decreased. Wrong viewPort?....................................\n"); 
innerText.setBounds(100,100,500,500); 
JScrollPane innerScroller = new JScrollPane(innerText); 
innerScroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 
innerScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); 
JPanel p = new JPanel(new GridBagLayout()); 
p.add(innerScroller); 
JScrollPane jScrollPane = new JScrollPane(p); 
jScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 
jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); 
frame.add(jScrollPane, BorderLayout.CENTER); 
frame.setSize(400, 150); 
frame.setVisible(true); 
    } 
} 

enter image description here

+0

看到的滚动条是外部的“jScrollPane”。我希望滚动条出现在“innerScroller”上。 – Grains

2

根据你的回答在OP ItachiUchiha的评论,它只是听起来好像要滚动文本,这是一个滚动的JPanel。

而不是使用JLabel,如何使用更适合滚动文本的JTextArea(像标签一样装饰)?

用很少的修改现有的代码:

import java.awt.*; 
import javax.swing.*; 

public class ScrollersTest extends JFrame { 
    public static void main(String args[]) { 
    new ScrollersTest(); 
    } 

    public ScrollersTest() { 
    super("A JScrollPane inside a JScrollPane"); 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    init(); 
    pack(); 
    setVisible(true); 
    } 

    public void init() { 
    JPanel p = new JPanel(new GridBagLayout()); 
    GridBagConstraints c = new GridBagConstraints(); 

    String text = "This text is inside a JScrollPane of its own. " 
     + "But no scroller is shown when the frames size is decreased. " 
     + "Wrong viewPort?...................................."; 

    // INNER SCROLLPANE: 
    JTextArea innerText = new JTextArea(1, 20); 
    innerText.setText(text); 
    innerText.setEditable(false); 
    innerText.setOpaque(false); 

    JScrollPane innerScroller = new JScrollPane(innerText, 
     JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 
    p.add(innerScroller); 

    // FRAMES SCROLLPANE: ONLY SCROLL VERTICAL 
    JScrollPane frameScrollpane = new JScrollPane(p, 
     JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
    getContentPane().add(frameScrollpane, BorderLayout.CENTER); 
    } 
} 
+0

JTextArea具有固定大小。我希望该区域填充JFrame大小。 – Grains

+0

那么,你可以用适当的布局管理器和/或在JTextArea上的设置来控制它。然而,这引出了一个问题:如果文本要与框架水平拉伸,那么您将如何能够滚动它,因为其面板可以通过外部滚动条进行滚动?尝试一下你的自我:在我的例子中删除JTextArea构造函数的参数,你会明白我的意思,即使你为fraem而不是'pack()'使用固定的初始大小。 – splungebob

2

JScrollPane中。内部JScrollPane只会滚动水平

然后,我认为你需要强制组件适合视口。你可以通过为你的面板实现Scrollable interface来做到这一点。或者,更简单的方法是使用为您完成所有工作的Scrollable Panel

import java.awt.*; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 

import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 

public class ScrollersTest extends JFrame { 

    public ScrollersTest() { 
     super("A JScrollPane inside a JScrollPane"); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     init(); 
     setVisible(true); 
     pack(); 
    } 

    public void init() { 
//  JPanel p = new JPanel(new GridBagLayout()); 
     ScrollablePanel p = new ScrollablePanel(new BorderLayout()); 
     p.setScrollableWidth(ScrollablePanel.ScrollableSizeHint.FIT); 

     GridBagConstraints c = new GridBagConstraints(); 

     // INNER SCROLLPANE: ONLY SCROLL HORIZONTAL: DOSE NOT WORK... 
     JLabel innerText = new JLabel("This text is inside a JScrollPane of its own. But no scroller is shown when the frames size is decreased. Wrong viewPort?...................................."); 
     JScrollPane innerScroller = new JScrollPane(innerText, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 
     Dimension d = innerScroller.getPreferredSize(); 
     innerScroller.setPreferredSize(new Dimension(d.width, d.height * 2)); 
//  p.add(innerScroller, c); 
     p.add(innerScroller, BorderLayout.NORTH); 

     // FRAMES SCROLLPANE: ONLY SCROLL VERTICAL 
     JScrollPane frameScrollpane = new JScrollPane(p, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
     getContentPane().add(frameScrollpane, BorderLayout.CENTER); 
    } 

    public static void main(String args[]) { 
     new ScrollersTest(); 
    } 
} 

我在这个例子中使用了BorderLayout,因为它更简单。如果您想使用GridBagLayout,那么您需要正确配置约束条件,以便组件以合理的方式增长/收缩。当您使用默认值时,组件将默认为其最小尺寸(0,0),因此您只会在框架上看到一个小矩形。

+0

真的很棒的回答!谢谢!唯一剩下的问题是我需要在将“ScrollablePanel”添加到另一个JPanel之前添加到“frameScrollpane”。编辑了这个问题。 +1 – Grains

+0

'我需要在将“ScrollablePanel”添加到另一个JPanel之前将其添加到“frameScrollpane” - 不知道我是否理解问题,只能将一个组件添加到一个scrollPane中,因此您可以使用ScrollablePanel作为主面板将标签添加到NORTH,然后将其他组件添加到CENTER中。此外,嵌套面板是解决布局问题的常用方法。 – camickr