JTextArea 不会使用布局管理器收缩到 JPanel 内
我有一个自定义布局,其中主要行为是当 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
JTextArea 不会在 JPanel 内缩小
您需要设置文本区域的最小大小:
ps。我在面板中使用 GridLayout,仅使用一个组件。
JTextArea wont shrink inside JPanel
You need to set the minimum size of the text area:
ps. I'm Using GridLayout in my panel with just the one component.
这是老问题,但我希望它对某人有用。
对我来说工作:
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());