15

私はすでにこれらの投稿を読んだり試したりしましたが、役に立ちませんでした:

私が必要としてListCellRendererいるのは、左側にアイコンがあり、右側に動的な長さのテキストがあるパネルを返す です (他のフォーラムのように: 左側にユーザ​​ー アバター、右側に投稿テキスト)。テキストは私にはわからないので、セルの高さを固定することはできませんさらに、テキストの長さは、リスト セルごとに異なります。したがって、すべてのリスト セルには、テキストの長さに応じて独自の高さが必要です。実際には非常に一般的なレイアウトですが、Swing ではそうではありません。セルの高さは、テキストの長さに応じて拡張されません。

の動的なセルの高さと複数行のテキストに関するほとんどすべての投稿を既に読みましたがJList、解決策が見つかりませんでした。だから私は小さなSSCCEを与えることにしました。私が説明したことを達成する方法についてのヒントを教えてください。または、簡単だと思う場合はコードを修正してください。

ありがとう

SSCCE は次のとおりです。

public class MultiLineList extends JFrame
{

    private static final long serialVersionUID = 1L;

    public static void main(final String[] args)
    {
        new MultiLineList();
    }

    private MultiLineList()
    {
        setTitle("MultiLineList");
        setSize(800, 450);
        setResizable(true);
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.getContentPane().setLayout(new BorderLayout());

        final DefaultListModel model = new DefaultListModel();
        model.addElement("This is a short text");
        model.addElement("This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. ");
        model.addElement("This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. ");

        final JList list = new JList(model);
        list.setCellRenderer(new MyCellRenderer());

        this.add(list);

        this.getContentPane().invalidate();
        this.getContentPane().validate();

    }

    public class MyCellRenderer extends DefaultListCellRenderer
    {
        @Override
        public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean hasFocus)
        {

            final String text = (String) value;

            //create panel
            final JPanel p = new JPanel();
            p.setLayout(new BorderLayout());

            //icon
            final JPanel IconPanel = new JPanel(new BorderLayout());
            final JLabel l = new JLabel("icon"); //<-- this will be an icon instead of a text
            IconPanel.add(l, BorderLayout.NORTH);
            p.add(IconPanel, BorderLayout.WEST);

            //text
            final JTextArea ta = new JTextArea();
            ta.setText(text);
            ta.setLineWrap(true);
            ta.setWrapStyleWord(true);
            p.add(ta, BorderLayout.CENTER);

            return p;

        }
    }

}
4

2 に答える 2

18

編集1:おっと-@Andrewのスクリーンショットを見て、これが期待どおりに機能していないことに気付きました.テキストは実際にはこれで表示されているよりも長いです(内部コメント「保留中: JScrollPaneのJListで機能していません」を見落としました;-)すぐに機能させられない場合は、この回答を少し削除してください。

編集 2 : わかりました - 以下に示すレンダラーの実装は問題ありません。原因は JList であり、最適なサイズよりも小さいキャッシュが時々発生します。それには2つの部分があります

  • BasicListUI は、リストのサイズを変更するために内部サイズ (実際には行の高さ) のキャッシュをクリアする必要があることを考慮していません。アプリケーション コードで強制的にそうする必要があります。
  • リストの TracksViewportWidth の Scrollable 実装には、邪魔になるロジックが含まれており (単一行になるまで、領域のストレッチアウトのループにつながります)、サブクラスが true を返します。

以下のレンダラーを使用するコード:

    final JList list = new JList(model) {

        /** 
         * @inherited <p>
         */
        @Override
        public boolean getScrollableTracksViewportWidth() {
            return true;
        }


    };
    list.setCellRenderer(new MyCellRenderer());

    ComponentListener l = new ComponentAdapter() {

        @Override
        public void componentResized(ComponentEvent e) {
            // next line possible if list is of type JXList
            // list.invalidateCellSizeCache();
            // for core: force cache invalidation by temporarily setting fixed height
            list.setFixedCellHeight(10);
            list.setFixedCellHeight(-1);
        }

    };

    list.addComponentListener(l);
    add(new JScrollPane(list));

最初の回答(レンダリング コンポーネントとして JTextArea を使用するレンダラーの実装)

TextArea はサイジングが少し難しいです: 妥当なものに初期化する必要があります:

public class MyCellRenderer implements ListCellRenderer {

    private JPanel p;
    private JPanel iconPanel;
    private JLabel l;
    private JTextArea ta;

    public MyCellRenderer() {
        p = new JPanel();
        p.setLayout(new BorderLayout());

        // icon
        iconPanel = new JPanel(new BorderLayout());
        l = new JLabel("icon"); // <-- this will be an icon instead of a
                                // text
        iconPanel.add(l, BorderLayout.NORTH);
        p.add(iconPanel, BorderLayout.WEST);

        // text
        ta = new JTextArea();
        ta.setLineWrap(true);
        ta.setWrapStyleWord(true);
        p.add(ta, BorderLayout.CENTER);
    }

    @Override
    public Component getListCellRendererComponent(final JList list,
            final Object value, final int index, final boolean isSelected,
            final boolean hasFocus) {

        ta.setText((String) value);
        int width = list.getWidth();
        // this is just to lure the ta's internal sizing mechanism into action
        if (width > 0)
            ta.setSize(width, Short.MAX_VALUE);
        return p;

    }
}
于 2011-09-05T10:09:24.663 に答える
14

複数行リスト

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

public class MultiLineList
{
    private static final long serialVersionUID = 1L;

    public static void main(final String[] args)
    {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new MultiLineList();
            }
        });
    }

    private MultiLineList()
    {
        JFrame f = new JFrame("MultiLineList");
        f.setResizable(true);
        f.setVisible(true);
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        f.getContentPane().setLayout(new BorderLayout());

        final DefaultListModel model = new DefaultListModel();
        model.addElement("This is a short text");
        model.addElement("This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. This is a long text. ");
        model.addElement("This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. This is an even longer text. ");

        final JList list = new JList(model);
        list.setCellRenderer(new MyCellRenderer());

        f.add(list);

        f.pack();
    }

    public class MyCellRenderer extends DefaultListCellRenderer
    {
        final JPanel p = new JPanel(new BorderLayout());
        final JPanel IconPanel = new JPanel(new BorderLayout());
        final JLabel l = new JLabel("icon"); //<-- this will be an icon instead of a text
        final JLabel lt = new JLabel();
        String pre = "<html><body style='width: 200px;'>";

        MyCellRenderer() {
            //icon
            IconPanel.add(l, BorderLayout.NORTH);
            p.add(IconPanel, BorderLayout.WEST);

            p.add(lt, BorderLayout.CENTER);
            //text
        }

        @Override
        public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean hasFocus)
        {
            final String text = (String) value;
            lt.setText(pre + text);

            return p;
        }
    }
}
于 2011-09-05T10:06:27.583 に答える