Make JTextArea in JList cell renderer in JScrollPane resize to scroll view width, height of content

huangapple go评论79阅读模式
英文:

Make JTextArea in JList cell renderer in JScrollPane resize to scroll view width, height of content

问题

抱歉,标题可能有点混淆。以下是情况:

我在一个JScrollPane中有一个JList。每个列表项(实现为自定义的ListCellRenderer)包含一个带有一些标签和最重要的是一个JTextAreaJFrame。文本区域包含一些需要跨足够多行换行的文本,以便用户不需要在滚动窗格中水平滚动。我不希望文本区域自动滚动,我只希望它展开以占用所需的垂直空间。

如果有助于理解我想要实现的目标,这是IntelliJ Swing UI设计器中的屏幕截图:

我希望body文本区域(以及包含它的面板)能够展开,以占用所需的垂直空间。

Make JTextArea in JList cell renderer in JScrollPane resize to scroll view width, height of content

包含文本的组件不一定非要是文本区域,我尝试过JTextPane,但也不起作用。文本不需要可编辑

我已经将文本区域设置为自动换行(使用setLineWrapsetWrapStyleWord),并在滚动窗格上禁用了水平滚动(使用setHorizontalScrollBarPolicy)。

以下是一个最小的可复现示例:

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

public class TextAreaListTest implements ListCellRenderer<String> {
    // 任意较长的字符串
    private static final String LORUM_IPSUM = """
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sit amet est eget mauris tempus vehicula.
        Nunc aliquet quis mi vitae fringilla. Aliquam laoreet eu metus sit amet iaculis. Curabitur imperdiet eu est
        et lobortis. Mauris eget est id lorem iaculis dictum. Aenean nisi libero, consectetur quis enim sed,
        pulvinar facilisis erat. Aliquam euismod nulla et dictum dictum. Etiam non ullamcorper sem. Nulla efficitur,
        quam cursus molestie euismod, dui lorem congue mi, placerat blandit turpis ex id libero. Nullam sit amet
        porta purus. Mauris scelerisque justo non orci vehicula, sed mattis sapien cursus. Aenean at porttitor
        dolor. Aenean euismod massa et libero egestas, sed lacinia eros aliquet. In tincidunt vehicula ex, a
        sollicitudin justo consequat ac. In in purus ut ligula sollicitudin porta quis eu neque. Aliquam erat volutpat.
        """;

    @Override
    public Component getListCellRendererComponent(JList<? extends String> list, String value, int index, boolean isSelected, boolean cellHasFocus) {
        JTextArea textArea = new JTextArea();
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        textArea.setText(value);

        JPanel panel = new JPanel();
        BoxLayout layout = new BoxLayout(panel, BoxLayout.Y_AXIS);
        panel.setLayout(layout);
        panel.add(new JLabel("Header label"));
        panel.add(textArea);
        return panel;
    }

    public static JComponent getRootComponent() {
        DefaultListModel<String> listModel = new DefaultListModel<>();
        listModel.addAll(Arrays.asList("a short string", LORUM_IPSUM));

        JList<String> list = new JList<>();
        list.setModel(listModel);
        list.setCellRenderer(new TextAreaListTest());

        JScrollPane scrollPane = new JScrollPane(list);
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        return scrollPane;
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setContentPane(getRootComponent());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

该示例显示了问题:文本区域的行确实换行,但实际的文本区域高度(以及父面板)不会更改,因此如果未换行,则不适合文本区域的文本在换行时会被截断。

明确地说,我希望每个列表项在窗口调整大小时(并强制文本区域弯曲)增加高度,以适应整个文本。

提前感谢您的帮助。我已经被这个问题困扰了几天。

英文:

Sorry if the title is a bit confusing. Here is the situation:

I have a JList in a JScrollPane. Each list item (implemented as a custom ListCellRenderer) contains a JFrame with some labels and most importantly, a JTextArea. The text area contains some text that needs to wrap across many lines so that the user does not need to scroll horizontally in the scroll pane. I do not want the text area to scroll by itself, I just want it to expand to take as much vertical space as it needs.

If it helps understand what I am trying to achieve, here is a screenshot from the IntelliJ swing UI designer:

I would like the body text area (and the panel with it) to expand to as much vertical space as it needs.

Make JTextArea in JList cell renderer in JScrollPane resize to scroll view width, height of content

The component holding the text does not have to be a text area, I tried a JTextPane and that did not work either. The text does not need to be editable.

I have already set the text area to wrap (with setLineWrap and setWrapStyleWord), and disabled horizontal scrolling on the scroll pane with setHorizontalScrollBarPolicy.

Here is a minimal reproducible example:

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

public class TextAreaListTest implements ListCellRenderer&lt;String&gt; {
    // Arbitrary long string
    private static final String LORUM_IPSUM = &quot;&quot;&quot;
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sit amet est eget mauris tempus vehicula.
            Nunc aliquet quis mi vitae fringilla. Aliquam laoreet eu metus sit amet iaculis. Curabitur imperdiet eu est
            et lobortis. Mauris eget est id lorem iaculis dictum. Aenean nisi libero, consectetur quis enim sed,
            pulvinar facilisis erat. Aliquam euismod nulla et dictum dictum. Etiam non ullamcorper sem. Nulla efficitur,
            quam cursus molestie euismod, dui lorem congue mi, placerat blandit turpis ex id libero. Nullam sit amet
            porta purus. Mauris scelerisque justo non orci vehicula, sed mattis sapien cursus. Aenean at porttitor
            dolor. Aenean euismod massa et libero egestas, sed lacinia eros aliquet. In tincidunt vehicula ex, a
            sollicitudin justo consequat ac. In in purus ut ligula sollicitudin porta quis eu neque. Aliquam erat volutpat.
            &quot;&quot;&quot;;

    @Override
    public Component getListCellRendererComponent(JList&lt;? extends String&gt; list, String value, int index, boolean isSelected, boolean cellHasFocus) {
        JTextArea textArea = new JTextArea();
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        textArea.setText(value);

        JPanel panel = new JPanel();
        BoxLayout layout = new BoxLayout(panel, BoxLayout.Y_AXIS);
        panel.setLayout(layout);
        panel.add(new JLabel(&quot;Header label&quot;));
        panel.add(textArea);
        return panel;
    }

    public static JComponent getRootComponent() {
        DefaultListModel&lt;String&gt; listModel = new DefaultListModel&lt;&gt;();
        listModel.addAll(Arrays.asList(&quot;a short string&quot;, LORUM_IPSUM));

        JList&lt;String&gt; list = new JList&lt;&gt;();
        list.setModel(listModel);
        list.setCellRenderer(new TextAreaListTest());

        JScrollPane scrollPane = new JScrollPane(list);
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        return scrollPane;
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setContentPane(getRootComponent());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

This example shows the issue: Lines of the text area do wrap, however the actual height of the text area (and the parent panel) does not change, so the text that does not fit in the text area if it was was not wrapped gets cut off when it wraps.

To be clear, I would like each list item to grow in height when the window is resized (and the text area is forced to war) to fit the whole text.

Thanks in advance for any help. I've been stumped with this for a few days.

答案1

得分: 1

以下是您提供的代码的中文翻译部分:

这里有一个几乎有效的 hack。我编译到了 Java 8 标准。

Make JTextArea in JList cell renderer in JScrollPane resize to scroll view width, height of content

我计算了每个值的 JTextArea 的大小。计算有点不精确,取决于我在 getRootComponent 方法中设置的 JPanel 的首选大小以及JTextArea 中文本的字体。

以下是我测试的代码。

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.util.Arrays;

import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;

public class TextAreaListTest implements ListCellRenderer<String> {
    // 任意长的字符串
    private static final String LORUM_IPSUM = "Lorem ipsum dolor sit amet, consectetur "
            + "adipiscing elit. Sed sit amet est eget mauris tempus vehicula. "
            + "Nunc aliquet quis mi vitae fringilla. Aliquam laoreet eu metus "
            + "sit amet iaculis. Curabitur imperdiet eu est et lobortis. Mauris "
            + "eget est id lorem iaculis dictum. Aenean nisi libero, consectetur "
            + "quis enim sed, pulvinar facilisis erat. Aliquam euismod nulla et "
            + "dictum dictum. Etiam non ullamcorper sem. Nulla efficitur, quam "
            + "cursus molestie euismod, dui lorem congue mi, placerat blandit "
            + "turpis ex id libero. Nullam sit amet porta purus. Mauris scelerisque "
            + "justo non orci vehicula, sed mattis sapien cursus. Aenean at porttitor "
            + "dolor. Aenean euismod massa et libero egestas, sed lacinia eros aliquet. "
            + "In tincidunt vehicula ex, a sollicitudin justo consequat ac. In in "
            + "purus ut ligula sollicitudin porta quis eu neque. Aliquam erat volutpat.";

    private static JPanel rootPanel;
    
    @Override
    public Component getListCellRendererComponent(JList<? extends String> list, 
            String value, int index, boolean isSelected, boolean cellHasFocus) {
        int width = rootPanel.getWidth() / 6;
        int lines = value.length() / width + 1;
        
        JTextArea textArea = new JTextArea(lines, width / 2);
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        textArea.setText(value);

        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(new JLabel("Header label"), BorderLayout.BEFORE_FIRST_LINE);
        panel.add(textArea, BorderLayout.CENTER);
        return panel;
    }

    public static JComponent getRootComponent() {
        DefaultListModel<String> listModel = new DefaultListModel<>();
        listModel.addAll(Arrays.asList("A short string", LORUM_IPSUM, 
                "A second short string", LORUM_IPSUM));

        JList<String> list = new JList<>();
        list.setModel(listModel);
        list.setCellRenderer(new TextAreaListTest());

        JScrollPane scrollPane = new JScrollPane(list);
        
        rootPanel = new JPanel(new BorderLayout());
        rootPanel.setPreferredSize(new Dimension(400, 400));
        rootPanel.add(scrollPane, BorderLayout.CENTER);
        return rootPanel;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("TextArea List Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(getRootComponent(), BorderLayout.CENTER);
                frame.pack();
                frame.setLocationByPlatform(true);
                frame.setVisible(true);
            }
        });
    }
}

注意:由于您要求只翻译代码部分,我已经省略了注释和代码中的HTML转义字符。如果您需要完整的代码,包括注释和特殊字符的处理,请告诉我,我可以提供完整的代码。

英文:

Here's a hack that almost works. I compile to the Java 8 standard.

Make JTextArea in JList cell renderer in JScrollPane resize to scroll view width, height of content

I calculate the size of the JTextArea for each value. The calculation is a bit imprecise and depends on the preferred size of the JPanel I set in the getRootComponent method, and the font used for the text in the JTextArea.

Here's the code I tested with.

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.util.Arrays;
import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
public class TextAreaListTest implements ListCellRenderer&lt;String&gt; {
// Arbitrary long string
private static final String LORUM_IPSUM = &quot;Lorem ipsum dolor sit amet, consectetur &quot;
+ &quot;adipiscing elit. Sed sit amet est eget mauris tempus vehicula. &quot;
+ &quot;Nunc aliquet quis mi vitae fringilla. Aliquam laoreet eu metus &quot;
+ &quot;sit amet iaculis. Curabitur imperdiet eu est et lobortis. Mauris &quot;
+ &quot;eget est id lorem iaculis dictum. Aenean nisi libero, consectetur &quot;
+ &quot;quis enim sed, pulvinar facilisis erat. Aliquam euismod nulla et &quot;
+ &quot;dictum dictum. Etiam non ullamcorper sem. Nulla efficitur, quam &quot;
+ &quot;cursus molestie euismod, dui lorem congue mi, placerat blandit &quot;
+ &quot;turpis ex id libero. Nullam sit amet porta purus. Mauris scelerisque &quot;
+ &quot;justo non orci vehicula, sed mattis sapien cursus. Aenean at porttitor &quot;
+ &quot;dolor. Aenean euismod massa et libero egestas, sed lacinia eros aliquet. &quot;
+ &quot;In tincidunt vehicula ex, a sollicitudin justo consequat ac. In in &quot;
+ &quot;purus ut ligula sollicitudin porta quis eu neque. Aliquam erat volutpat.&quot;;
private static JPanel rootPanel;
@Override
public Component getListCellRendererComponent(JList&lt;? extends String&gt; list, 
String value, int index, boolean isSelected, boolean cellHasFocus) {
int width = rootPanel.getWidth() / 6;
int lines = value.length() / width + 1;
JTextArea textArea = new JTextArea(lines, width / 2);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setText(value);
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JLabel(&quot;Header label&quot;), BorderLayout.BEFORE_FIRST_LINE);
panel.add(textArea, BorderLayout.CENTER);
return panel;
}
public static JComponent getRootComponent() {
DefaultListModel&lt;String&gt; listModel = new DefaultListModel&lt;&gt;();
listModel.addAll(Arrays.asList(&quot;A short string&quot;, LORUM_IPSUM, 
&quot;A second short string&quot;, LORUM_IPSUM));
JList&lt;String&gt; list = new JList&lt;&gt;();
list.setModel(listModel);
list.setCellRenderer(new TextAreaListTest());
JScrollPane scrollPane = new JScrollPane(list);
rootPanel = new JPanel(new BorderLayout());
rootPanel.setPreferredSize(new Dimension(400, 400));
rootPanel.add(scrollPane, BorderLayout.CENTER);
return rootPanel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame(&quot;TextArea List Test&quot;);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(getRootComponent(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}

huangapple
  • 本文由 发表于 2020年10月20日 12:04:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/64438305.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定