JScrollPane里面的JScrollPane

时间:2014-02-26 13:53:29

标签: java swing jscrollpane

我正在尝试在另一个JScrollPane中添加JScrollPane。 内部JScrollPane仅滚动HORIZONTAL,外部仅滚动VERTICAL。

在此图片中,您可以看到水平滚动条在添加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 + "]";
            }
        }
    }
}

3 个答案:

答案 0 :(得分:2)

根据您对OP的ItachiUchiha评论的回答,它听起来像是你想要的可滚动文本,这是在可滚动的JPanel上。

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

对现有代码的修改很少:

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

答案 1 :(得分:2)

  

JScrollPane中。内部JScrollPane只会滚动HORIZONTAL

然后我认为您需要强制组件适合视口。您可以通过为面板实施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),因此您只能在框架上看到一个小矩形。

答案 2 :(得分: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