0

我试图设置JTextAreaJPanel

JPanel panel=new JPanel(new BorderLayout());
JTextArea ta=new JTextArea();
ta.setColumns(20);
ta.setEditable(false);
ta.setLineWrap(true);
ta.setRows(5);
ta.setWrapStyleWord(true);

panel.add(ta,BorderLayout.CENTER);

JPanel panel1=new JPanel();
panel1.setLayout(new VerticalLayout(5,VerticalLayout.BOTH));
panel1.add(panel);

JFrame frame=new JFrame();
frame.getContentPane().add(panel1);
    ...

问题是......当panel1重新调整尺寸更宽然后变窄时,JTextArea就会被切断。我的意思是它的行不会恢复到 5,而是保持为 1,所以它的所有文本都在一行中,当然,它WrapStyleWord是非活动的:S

所以我的问题是如何JTextArea在调整帧大小时恢复到原来的比例?

这是垂直布局代码。

...

好吧,基于 Guillaume Polet 片段,我尝试编写某种垂直面板列表,但出现了前面提到的问题 :( 这是代码

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.util.Hashtable;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class TestTextArea {

    private void initUI() {
        JFrame frame = new JFrame("test");


        JPanel listPanel = new JPanel();
        listPanel.setLayout(new VerticalLayout(5, VerticalLayout.BOTH));


        JPanel mainPanel=new JPanel(new GridLayout());
        JScrollPane sp=new JScrollPane();
        sp.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        sp.setViewportView(listPanel);

        mainPanel.add(sp);

        listPanel.add(new MyPanel());
        listPanel.add(new MyPanel());
        listPanel.add(new MyPanel());
        listPanel.add(new MyPanel());
        listPanel.add(new MyPanel());

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestTextArea().initUI();
            }
        });
    }

    class MyPanel extends JPanel
    {
        public MyPanel(){

        this.setLayout(new BorderLayout());

        JTextArea ta = new JTextArea();
        ta.setText("Hello world Hello world Hello world Hello world " + "Hello world Hello world Hello world Hello world "
                + "Hello world Hello world Hello world Hello world " + "Hello world Hello world Hello world Hello world ");
        ta.setColumns(20);
        ta.setEditable(false);
        ta.setLineWrap(true);
        ta.setRows(5);
        ta.setWrapStyleWord(true);

        this.add(ta, BorderLayout.CENTER);


        }

    }

    public static class VerticalLayout implements LayoutManager {

        /**
         * The horizontal alignment constant that designates centering. Also used to designate center anchoring.
         */
        public final static int CENTER = 0;
        /**
         * The horizontal alignment constant that designates right justification.
         */
        public final static int RIGHT = 1;
        /**
         * The horizontal alignment constant that designates left justification.
         */
        public final static int LEFT = 2;
        /**
         * The horizontal alignment constant that designates stretching the component horizontally.
         */
        public final static int BOTH = 3;

        /**
         * The anchoring constant that designates anchoring to the top of the display area
         */
        public final static int TOP = 1;
        /**
         * The anchoring constant that designates anchoring to the bottom of the display area
         */
        public final static int BOTTOM = 2;
        private int vgap; // the vertical vgap between components...defaults to 5
        private int alignment; // LEFT, RIGHT, CENTER or BOTH...how the components are justified
        private int anchor; // TOP, BOTTOM or CENTER ...where are the components positioned in an overlarge space
        private Hashtable comps;

        // Constructors
        /**
         * Constructs an instance of VerticalLayout with a vertical vgap of 5 pixels, horizontal centering and anchored to the top of the
         * display area.
         */
        public VerticalLayout() {
            this(5, CENTER, TOP);
        }

        /**
         * Constructs a VerticalLayout instance with horizontal centering, anchored to the top with the specified vgap
         *
         * @param vgap
         *            An int value indicating the vertical seperation of the components
         */
        public VerticalLayout(int vgap) {
            this(vgap, CENTER, TOP);
        }

        /**
         * Constructs a VerticalLayout instance anchored to the top with the specified vgap and horizontal alignment
         *
         * @param vgap
         *            An int value indicating the vertical seperation of the components
         * @param alignment
         *            An int value which is one of <code>RIGHT, LEFT, CENTER, BOTH</code> for the horizontal alignment.
         */
        public VerticalLayout(int vgap, int alignment) {
            this(vgap, alignment, TOP);
        }

        /**
         * Constructs a VerticalLayout instance with the specified vgap, horizontal alignment and anchoring
         *
         * @param vgap
         *            An int value indicating the vertical seperation of the components
         * @param alignment
         *            An int value which is one of <code>RIGHT, LEFT, CENTER, BOTH</code> for the horizontal alignment.
         * @param anchor
         *            An int value which is one of <code>TOP, BOTTOM, CENTER</code> indicating where the components are to appear if the
         *            display area exceeds the minimum necessary.
         */
        public VerticalLayout(int vgap, int alignment, int anchor) {
            this.vgap = vgap;
            this.alignment = alignment;
            this.anchor = anchor;
        }

        // ----------------------------------------------------------------------------
        private Dimension layoutSize(Container parent, boolean minimum) {
            Dimension dim = new Dimension(0, 0);
            Dimension d;
            synchronized (parent.getTreeLock()) {
                int n = parent.getComponentCount();
                for (int i = 0; i < n; i++) {
                    Component c = parent.getComponent(i);
                    if (c.isVisible()) {
                        d = minimum ? c.getMinimumSize() : c.getPreferredSize();
                        dim.width = Math.max(dim.width, d.width);
                        dim.height += d.height;
                        if (i > 0) {
                            dim.height += vgap;
                        }
                    }
                }
            }
            Insets insets = parent.getInsets();
            dim.width += insets.left + insets.right;
            dim.height += insets.top + insets.bottom + vgap + vgap;
            return dim;
        }

        // -----------------------------------------------------------------------------
        /**
         * Lays out the container.
         */
        @Override
        public void layoutContainer(Container parent) {
            Insets insets = parent.getInsets();
            synchronized (parent.getTreeLock()) {
                int n = parent.getComponentCount();
                Dimension pd = parent.getSize();
                int y = 0;
                // work out the total size
                for (int i = 0; i < n; i++) {
                    Component c = parent.getComponent(i);
                    Dimension d = c.getPreferredSize();
                    y += d.height + vgap;
                }
                y -= vgap; // otherwise there's a vgap too many
                // Work out the anchor paint
                if (anchor == TOP) {
                    y = insets.top;
                } else if (anchor == CENTER) {
                    y = (pd.height - y) / 2;
                } else {
                    y = pd.height - y - insets.bottom;
                }
                // do layout
                for (int i = 0; i < n; i++) {
                    Component c = parent.getComponent(i);
                    Dimension d = c.getPreferredSize();
                    int x = insets.left;
                    int wid = d.width;
                    if (alignment == CENTER) {
                        x = (pd.width - d.width) / 2;
                    } else if (alignment == RIGHT) {
                        x = pd.width - d.width - insets.right;
                    } else if (alignment == BOTH) {
                        wid = pd.width - insets.left - insets.right;
                    }
                    c.setBounds(x, y, wid, d.height);
                    y += d.height + vgap;
                }
            }
        }

        // -----------------------------------------------------------------------------
        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return layoutSize(parent, false);
        }

        // -----------------------------------------------------------------------------
        @Override
        public Dimension preferredLayoutSize(Container parent) {
            return layoutSize(parent, false);
        }

        // ----------------------------------------------------------------------------
        /**
         * Not used by this class
         */
        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        // -----------------------------------------------------------------------------
        /**
         * Not used by this class
         */
        @Override
        public void removeLayoutComponent(Component comp) {
        }

        // -----------------------------------------------------------------------------
        @Override
        public String toString() {
            return getClass().getName() + "[vgap=" + vgap + " align=" + alignment + " anchor=" + anchor + "]";
        }
    }

}

我不太确定如何使 JTextArea 达到其原始宽度?或者也许有一些更优化的方法?

4

2 回答 2

2

您似乎在发布SSCCE时遇到了问题,所以也许您可以从这个开始,可能会更改它,然后编辑您的问题,向我们展示您遇到的问题。

编辑:(根据更新的问题更改了 SSCCE)

问题是滚动窗格的ViewPortView没有实现Scrollable。使用作为 ViewPortView 添加的专用类 ScrollablePanel 尝试下面的代码。

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.util.Hashtable;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

public class TestTextArea {

    private void initUI() {
        JFrame frame = new JFrame("test");

        class ScrollablePanel extends JPanel implements Scrollable {

            /**
             * Returns the preferred size of the viewport for a view component. This is implemented to do the default behavior of returning
             * the preferred size of the component.
             * 
             * @return the <code>preferredSize</code> of a <code>JViewport</code> whose view is this <code>Scrollable</code>
             */
            @Override
            public Dimension getPreferredScrollableViewportSize() {
                return getPreferredSize();
            }

            /**
             * Components that display logical rows or columns should compute the scroll increment that will completely expose one new row
             * or column, depending on the value of orientation. Ideally, components should handle a partially exposed row or column by
             * returning the distance required to completely expose the item.
             * <p>
             * The default implementation of this is to simply return 10% of the visible area. Subclasses are likely to be able to provide a
             * much more reasonable value.
             * 
             * @param visibleRect
             *            the view area visible within the viewport
             * @param orientation
             *            either <code>SwingConstants.VERTICAL</code> or <code>SwingConstants.HORIZONTAL</code>
             * @param direction
             *            less than zero to scroll up/left, greater than zero for down/right
             * @return the "unit" increment for scrolling in the specified direction
             * @exception IllegalArgumentException
             *                for an invalid orientation
             * @see JScrollBar#setUnitIncrement
             */
            @Override
            public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
                switch (orientation) {
                case SwingConstants.VERTICAL:
                    return visibleRect.height / 10;
                case SwingConstants.HORIZONTAL:
                    return visibleRect.width / 10;
                default:
                    throw new IllegalArgumentException("Invalid orientation: " + orientation);
                }
            }

            /**
             * Components that display logical rows or columns should compute the scroll increment that will completely expose one block of
             * rows or columns, depending on the value of orientation.
             * <p>
             * The default implementation of this is to simply return the visible area. Subclasses will likely be able to provide a much
             * more reasonable value.
             * 
             * @param visibleRect
             *            the view area visible within the viewport
             * @param orientation
             *            either <code>SwingConstants.VERTICAL</code> or <code>SwingConstants.HORIZONTAL</code>
             * @param direction
             *            less than zero to scroll up/left, greater than zero for down/right
             * @return the "block" increment for scrolling in the specified direction
             * @exception IllegalArgumentException
             *                for an invalid orientation
             * @see JScrollBar#setBlockIncrement
             */
            @Override
            public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
                switch (orientation) {
                case SwingConstants.VERTICAL:
                    return visibleRect.height;
                case SwingConstants.HORIZONTAL:
                    return visibleRect.width;
                default:
                    throw new IllegalArgumentException("Invalid orientation: " + orientation);
                }
            }

            /**
             * Returns true if a viewport should always force the width of this <code>Scrollable</code> to match the width of the viewport.
             * For example a normal text view that supported line wrapping would return true here, since it would be undesirable for wrapped
             * lines to disappear beyond the right edge of the viewport. Note that returning true for a <code>Scrollable</code> whose
             * ancestor is a <code>JScrollPane</code> effectively disables horizontal scrolling.
             * <p>
             * Scrolling containers, like <code>JViewport</code>, will use this method each time they are validated.
             * 
             * @return true if a viewport should force the <code>Scrollable</code>s width to match its own
             */
            @Override
            public boolean getScrollableTracksViewportWidth() {
                return true;
            }

            /**
             * Returns true if a viewport should always force the height of this <code>Scrollable</code> to match the height of the
             * viewport. For example a columnar text view that flowed text in left to right columns could effectively disable vertical
             * scrolling by returning true here.
             * <p>
             * Scrolling containers, like <code>JViewport</code>, will use this method each time they are validated.
             * 
             * @return true if a viewport should force the Scrollables height to match its own
             */
            @Override
            public boolean getScrollableTracksViewportHeight() {
                return false;
            }

        }

        JPanel listPanel = new ScrollablePanel();
        listPanel.setLayout(new VerticalLayout(5, VerticalLayout.BOTH));

        JPanel mainPanel = new JPanel(new GridLayout());
        JScrollPane sp = new JScrollPane();
        sp.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        sp.setViewportView(listPanel);

        mainPanel.add(sp);

        listPanel.add(new MyPanel());
        listPanel.add(new MyPanel());
        listPanel.add(new MyPanel());
        listPanel.add(new MyPanel());
        listPanel.add(new MyPanel());

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestTextArea().initUI();
            }
        });
    }

    class MyPanel extends JPanel {
        public MyPanel() {

            this.setLayout(new BorderLayout());

            JTextArea ta = new JTextArea();
            ta.setText("Hello world Hello world Hello world Hello world " + "Hello world Hello world Hello world Hello world "
                    + "Hello world Hello world Hello world Hello world " + "Hello world Hello world Hello world Hello world ");
            ta.setColumns(20);
            ta.setEditable(false);
            ta.setLineWrap(true);
            ta.setRows(5);
            ta.setWrapStyleWord(true);

            this.add(ta, BorderLayout.CENTER);

        }

    }

    public static class VerticalLayout implements LayoutManager {

        /**
         * The horizontal alignment constant that designates centering. Also used to designate center anchoring.
         */
        public final static int CENTER = 0;
        /**
         * The horizontal alignment constant that designates right justification.
         */
        public final static int RIGHT = 1;
        /**
         * The horizontal alignment constant that designates left justification.
         */
        public final static int LEFT = 2;
        /**
         * The horizontal alignment constant that designates stretching the component horizontally.
         */
        public final static int BOTH = 3;

        /**
         * The anchoring constant that designates anchoring to the top of the display area
         */
        public final static int TOP = 1;
        /**
         * The anchoring constant that designates anchoring to the bottom of the display area
         */
        public final static int BOTTOM = 2;
        private int vgap; // the vertical vgap between components...defaults to 5
        private int alignment; // LEFT, RIGHT, CENTER or BOTH...how the components are justified
        private int anchor; // TOP, BOTTOM or CENTER ...where are the components positioned in an overlarge space
        private Hashtable comps;

        // Constructors
        /**
         * Constructs an instance of VerticalLayout with a vertical vgap of 5 pixels, horizontal centering and anchored to the top of the
         * display area.
         */
        public VerticalLayout() {
            this(5, CENTER, TOP);
        }

        /**
         * Constructs a VerticalLayout instance with horizontal centering, anchored to the top with the specified vgap
         * 
         * @param vgap
         *            An int value indicating the vertical seperation of the components
         */
        public VerticalLayout(int vgap) {
            this(vgap, CENTER, TOP);
        }

        /**
         * Constructs a VerticalLayout instance anchored to the top with the specified vgap and horizontal alignment
         * 
         * @param vgap
         *            An int value indicating the vertical seperation of the components
         * @param alignment
         *            An int value which is one of <code>RIGHT, LEFT, CENTER, BOTH</code> for the horizontal alignment.
         */
        public VerticalLayout(int vgap, int alignment) {
            this(vgap, alignment, TOP);
        }

        /**
         * Constructs a VerticalLayout instance with the specified vgap, horizontal alignment and anchoring
         * 
         * @param vgap
         *            An int value indicating the vertical seperation of the components
         * @param alignment
         *            An int value which is one of <code>RIGHT, LEFT, CENTER, BOTH</code> for the horizontal alignment.
         * @param anchor
         *            An int value which is one of <code>TOP, BOTTOM, CENTER</code> indicating where the components are to appear if the
         *            display area exceeds the minimum necessary.
         */
        public VerticalLayout(int vgap, int alignment, int anchor) {
            this.vgap = vgap;
            this.alignment = alignment;
            this.anchor = anchor;
        }

        // ----------------------------------------------------------------------------
        private Dimension layoutSize(Container parent, boolean minimum) {
            Dimension dim = new Dimension(0, 0);
            Dimension d;
            synchronized (parent.getTreeLock()) {
                int n = parent.getComponentCount();
                for (int i = 0; i < n; i++) {
                    Component c = parent.getComponent(i);
                    if (c.isVisible()) {
                        d = minimum ? c.getMinimumSize() : c.getPreferredSize();
                        dim.width = Math.max(dim.width, d.width);
                        dim.height += d.height;
                        if (i > 0) {
                            dim.height += vgap;
                        }
                    }
                }
            }
            Insets insets = parent.getInsets();
            dim.width += insets.left + insets.right;
            dim.height += insets.top + insets.bottom + vgap + vgap;
            return dim;
        }

        // -----------------------------------------------------------------------------
        /**
         * Lays out the container.
         */
        @Override
        public void layoutContainer(Container parent) {
            Insets insets = parent.getInsets();
            synchronized (parent.getTreeLock()) {
                int n = parent.getComponentCount();
                Dimension pd = parent.getSize();
                int y = 0;
                // work out the total size
                for (int i = 0; i < n; i++) {
                    Component c = parent.getComponent(i);
                    Dimension d = c.getPreferredSize();
                    y += d.height + vgap;
                }
                y -= vgap; // otherwise there's a vgap too many
                // Work out the anchor paint
                if (anchor == TOP) {
                    y = insets.top;
                } else if (anchor == CENTER) {
                    y = (pd.height - y) / 2;
                } else {
                    y = pd.height - y - insets.bottom;
                }
                // do layout
                for (int i = 0; i < n; i++) {
                    Component c = parent.getComponent(i);
                    Dimension d = c.getPreferredSize();
                    int x = insets.left;
                    int wid = d.width;
                    if (alignment == CENTER) {
                        x = (pd.width - d.width) / 2;
                    } else if (alignment == RIGHT) {
                        x = pd.width - d.width - insets.right;
                    } else if (alignment == BOTH) {
                        wid = pd.width - insets.left - insets.right;
                    }
                    c.setBounds(x, y, wid, d.height);
                    y += d.height + vgap;
                }
            }
        }

        // -----------------------------------------------------------------------------
        @Override
        public Dimension minimumLayoutSize(Container parent) {
            return layoutSize(parent, false);
        }

        // -----------------------------------------------------------------------------
        @Override
        public Dimension preferredLayoutSize(Container parent) {
            return layoutSize(parent, false);
        }

        // ----------------------------------------------------------------------------
        /**
         * Not used by this class
         */
        @Override
        public void addLayoutComponent(String name, Component comp) {
        }

        // -----------------------------------------------------------------------------
        /**
         * Not used by this class
         */
        @Override
        public void removeLayoutComponent(Component comp) {
        }

        // -----------------------------------------------------------------------------
        @Override
        public String toString() {
            return getClass().getName() + "[vgap=" + vgap + " align=" + alignment + " anchor=" + anchor + "]";
        }
    }

}
于 2012-07-03T21:18:45.403 回答
1

我不知道为什么不使用JScrollPaneLineWrap并且WordWrap在中正常工作JScrollPane,那么JPanel使用另一个会更好LayoutManager

  • 放到JTextArea_JScrollPane

  • JPanel需要(我完全忽略 used VerticalLayout)将默认LayoutManager( FlowLayout) 更改为BorderLayout

  • 放到JScrollPane(myTextArea)_BorderLayout.CENTER

于 2012-07-03T20:21:06.400 回答