JTextArea 不会使用布局管理器收缩到 JPanel 内

发布于 2024-12-13 06:39:08 字数 7050 浏览 3 评论 0原文

我有一个自定义布局,其中主要行为是当 JScrollPane 宽度发生变化时增大和缩小子 JTextArea 。滚动窗格禁用水平滚动条,并且文本区域应该扩展和收缩以避免需要水平滚动条。几个月来,我使用一个标准布局管理器解决了这个问题,但现在我需要一些不同的功能。

发生的情况是,当用户水平展开滚动窗格时,将调用布局管理器的layoutContainer 方法。它会调整文本区域的大小并且文本会正确重排。但是,当您缩小滚动窗格时,不会调用layoutContainer,并且文本区域保持固定。我在layoutContainer方法中放置了一些println,以使其在工作和不工作时显而易见。

需要注意的重要一点是,当调用 JTextArea.setColumns() 时会出现问题。我可以将其注释掉,并且在调整大小期间调用layoutContainer(当然,然后文本区域不会调整大小。)我也尝试过使用JTextArea.setSize(),得到相同的结果。

这是代码:

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
@SuppressWarnings("serial")
class XTextArea extends JTextArea
{
    XTextArea (String text)
    {
        super (text);
    }

    public int getColumnWidth()
    {
        return super.getColumnWidth();
    }
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
class PackLeftLayout implements LayoutManager
{
    Component viewPort;
    Component flexWidthComponent;

    int preferredWidth = 0;
    int preferredHeight = 0;

    //----------------------------------------------------------------------------
    // viewPort - if null, compute width as sum of component's preferred width;
    //  otherwise width will be the viewPort's width.
    // flexWidthComponent - if not null, this component width will be sized to right
    //   justify rightmost component.
    public PackLeftLayout (Component viewPort, Component flexWidthComponent)
    {
        super ();
        this.viewPort = viewPort;
        this.flexWidthComponent = flexWidthComponent;
    }

    //----------------------------------------------------------------------------
    public void addLayoutComponent(String name, Component comp)
    {
    }

    //----------------------------------------------------------------------------
    public void removeLayoutComponent(Component comp)
    {
    }

    //----------------------------------------------------------------------------
    // Calculates the preferred size dimensions for the specified container, given the
    // components it contains.
    // parent - the container to be laid out
    // Components layed out left-to-right with no additional spacing.
    public Dimension preferredLayoutSize (Container parent)
    {
        Insets insets = parent.getInsets();
        int width = 0;
        int height = 0; // will become max of all component's preferred height

        // calculate sum of fixed width components - skip the flexwidth component
        width = insets.left + insets.right;
        for (int i = 0, limit = parent.getComponentCount();  i < limit;  i++)
        {
            Component c = parent.getComponent(i);
            if (c.isVisible())
            {
                if (c != flexWidthComponent)
                {
                    Dimension size = c.getPreferredSize();
                    if (size.height > height)
                    height = size.height;
                    width += size.width;
                }
            }
        }

        // determine width of flex width component
        if (flexWidthComponent != null)
        {
            int flexWidth = viewPort.getWidth() - width;
            if (flexWidth < 1)
                flexWidth = 1;

            if (flexWidthComponent instanceof XTextArea)
            {
                // some trickery here to get the xtextarea to tell us its preferred height
                // given a specific width.
                int colWidth = ((XTextArea)flexWidthComponent).getColumnWidth();

                // the following line causes the failure:
                ((XTextArea)flexWidthComponent).setColumns (flexWidth / colWidth);

                Dimension taSize = flexWidthComponent.getPreferredSize();
                width += taSize.width;

                if (taSize.height > height)
                    height = taSize.height;
            }
            else
            {
                Dimension size = flexWidthComponent.getPreferredSize();
                width += flexWidth;
                if (size.height > height)
                    height = size.height;
            }
        }

        preferredWidth = width; // already include insets
        preferredHeight = height + insets.top + insets.bottom;

        return new Dimension (preferredWidth, preferredHeight);
    }

    //----------------------------------------------------------------------------
    // Calculates the minimum size dimensions for the specified container, given the
    // components it contains.
    // parent - the component to be laid out
    public Dimension minimumLayoutSize(Container parent)
    {
      return new Dimension (10, 10); //???
    }

    static int k = 0;
    //----------------------------------------------------------------------------
    public void layoutContainer(Container parent)
    {
        System.out.println ("layout" + (k++));
        Insets insets = parent.getInsets();
        int left = insets.left;

        if (preferredWidth == 0 || preferredHeight == 0)
            preferredLayoutSize (parent);

        for (int i = 0, limit = parent.getComponentCount();  i < limit;  i++)
        {
            Component c = parent.getComponent(i);
            Dimension size = c.getPreferredSize();

            c.setBounds (left, insets.top, size.width, preferredHeight);

            left += size.width;
        }

        // force another layout calc
        preferredWidth = 0;
    }
}

public class ResizablePane extends JFrame
{

    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(
            new Runnable() {public void run()
            {
                new ResizablePane();
            }});
    }

    ResizablePane ()
    {
        super ("ResizableDemo");

        // put a button and text area into a panel, then into a scroll pane
        JButton button = new JButton ("button");
        XTextArea text = new XTextArea (
            "For three years I ran as fast as I could, trying to live and love and learn at " +
            "double speed to make up for what Anne-Marie lost.  Trying to anesthetize myself " +
            "from what Id lost.  When I decided to read a book a day and write about it, Id " +
            "finally stopped running away.");

        text.setLineWrap (true);
        text.setWrapStyleWord (true);

        JScrollPane scroll = new JScrollPane();
        JPanel panel = new JPanel();
        panel.setLayout (new PackLeftLayout(scroll.getViewport(), text));
        panel.add (button);
        panel.add (text);

        scroll.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scroll.setViewportView (panel);

        getContentPane().add(scroll);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
}

I have a custom layout where the principal behavior is to grow and shrink a child JTextArea when the JScrollPane it's in changes in width. The scroll pane has the horizontal scroll bar disabled and the text area is supposed to expand and contract so as to avoid needing a horizontal scroll bar. For a number of months, I worked around this using one of the standard layout managers, but now I need some different functionality.

What's happening is that when the user expands horizontally the scroll pane, the layout manager layoutContainer method is called. It resizes the text area and the text reflows properly. However, when you shrink the scroll pane, layoutContainer is not called and the text area stays fixed. I've put some printlns in the layoutContainer method to make it obvious when it's working and not.

The essential thing to note is that the problem happens when JTextArea.setColumns() is called. I can comment it out and the layoutContainer gets called during resizing (of course, then the text area doesn't get resized.) I've tried also using JTextArea.setSize(), with the same results.

Here's the code:

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
@SuppressWarnings("serial")
class XTextArea extends JTextArea
{
    XTextArea (String text)
    {
        super (text);
    }

    public int getColumnWidth()
    {
        return super.getColumnWidth();
    }
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
class PackLeftLayout implements LayoutManager
{
    Component viewPort;
    Component flexWidthComponent;

    int preferredWidth = 0;
    int preferredHeight = 0;

    //----------------------------------------------------------------------------
    // viewPort - if null, compute width as sum of component's preferred width;
    //  otherwise width will be the viewPort's width.
    // flexWidthComponent - if not null, this component width will be sized to right
    //   justify rightmost component.
    public PackLeftLayout (Component viewPort, Component flexWidthComponent)
    {
        super ();
        this.viewPort = viewPort;
        this.flexWidthComponent = flexWidthComponent;
    }

    //----------------------------------------------------------------------------
    public void addLayoutComponent(String name, Component comp)
    {
    }

    //----------------------------------------------------------------------------
    public void removeLayoutComponent(Component comp)
    {
    }

    //----------------------------------------------------------------------------
    // Calculates the preferred size dimensions for the specified container, given the
    // components it contains.
    // parent - the container to be laid out
    // Components layed out left-to-right with no additional spacing.
    public Dimension preferredLayoutSize (Container parent)
    {
        Insets insets = parent.getInsets();
        int width = 0;
        int height = 0; // will become max of all component's preferred height

        // calculate sum of fixed width components - skip the flexwidth component
        width = insets.left + insets.right;
        for (int i = 0, limit = parent.getComponentCount();  i < limit;  i++)
        {
            Component c = parent.getComponent(i);
            if (c.isVisible())
            {
                if (c != flexWidthComponent)
                {
                    Dimension size = c.getPreferredSize();
                    if (size.height > height)
                    height = size.height;
                    width += size.width;
                }
            }
        }

        // determine width of flex width component
        if (flexWidthComponent != null)
        {
            int flexWidth = viewPort.getWidth() - width;
            if (flexWidth < 1)
                flexWidth = 1;

            if (flexWidthComponent instanceof XTextArea)
            {
                // some trickery here to get the xtextarea to tell us its preferred height
                // given a specific width.
                int colWidth = ((XTextArea)flexWidthComponent).getColumnWidth();

                // the following line causes the failure:
                ((XTextArea)flexWidthComponent).setColumns (flexWidth / colWidth);

                Dimension taSize = flexWidthComponent.getPreferredSize();
                width += taSize.width;

                if (taSize.height > height)
                    height = taSize.height;
            }
            else
            {
                Dimension size = flexWidthComponent.getPreferredSize();
                width += flexWidth;
                if (size.height > height)
                    height = size.height;
            }
        }

        preferredWidth = width; // already include insets
        preferredHeight = height + insets.top + insets.bottom;

        return new Dimension (preferredWidth, preferredHeight);
    }

    //----------------------------------------------------------------------------
    // Calculates the minimum size dimensions for the specified container, given the
    // components it contains.
    // parent - the component to be laid out
    public Dimension minimumLayoutSize(Container parent)
    {
      return new Dimension (10, 10); //???
    }

    static int k = 0;
    //----------------------------------------------------------------------------
    public void layoutContainer(Container parent)
    {
        System.out.println ("layout" + (k++));
        Insets insets = parent.getInsets();
        int left = insets.left;

        if (preferredWidth == 0 || preferredHeight == 0)
            preferredLayoutSize (parent);

        for (int i = 0, limit = parent.getComponentCount();  i < limit;  i++)
        {
            Component c = parent.getComponent(i);
            Dimension size = c.getPreferredSize();

            c.setBounds (left, insets.top, size.width, preferredHeight);

            left += size.width;
        }

        // force another layout calc
        preferredWidth = 0;
    }
}

public class ResizablePane extends JFrame
{

    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(
            new Runnable() {public void run()
            {
                new ResizablePane();
            }});
    }

    ResizablePane ()
    {
        super ("ResizableDemo");

        // put a button and text area into a panel, then into a scroll pane
        JButton button = new JButton ("button");
        XTextArea text = new XTextArea (
            "For three years I ran as fast as I could, trying to live and love and learn at " +
            "double speed to make up for what Anne-Marie lost.  Trying to anesthetize myself " +
            "from what Id lost.  When I decided to read a book a day and write about it, Id " +
            "finally stopped running away.");

        text.setLineWrap (true);
        text.setWrapStyleWord (true);

        JScrollPane scroll = new JScrollPane();
        JPanel panel = new JPanel();
        panel.setLayout (new PackLeftLayout(scroll.getViewport(), text));
        panel.add (button);
        panel.add (text);

        scroll.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scroll.setViewportView (panel);

        getContentPane().add(scroll);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

久光 2024-12-20 06:39:08

JTextArea 不会在 JPanel 内缩小

您需要设置文本区域的最小大小:

textArea.SetMinimumSize(new Dimension(100,100));

ps。我在面板中使用 GridLayout,仅使用一个组件。

JTextArea wont shrink inside JPanel

You need to set the minimum size of the text area:

textArea.SetMinimumSize(new Dimension(100,100));

ps. I'm Using GridLayout in my panel with just the one component.

北笙凉宸 2024-12-20 06:39:08

这是老问题,但我希望它对某人有用。
对我来说工作:

jScrollPane = new JScrollPane(textArea);
jScrollPane.setPreferredSize(jScrollPane.getPreferredSize());

This is old question, but i hope that it will be usefull to someone.
For me worked:

jScrollPane = new JScrollPane(textArea);
jScrollPane.setPreferredSize(jScrollPane.getPreferredSize());

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文