0

I created a JList inside a JScrollPane that uses a custom ListCellRenderer. The ListCellRenderer contains a Jlabel that wraps its contents with HTML so the text automatically wraps. Without using the the JScrollPane the wrapping works, but when I use the JScrollPane the text is not wrapped and a horizontal scrollbar appears.

Excerpt of my ListCellRenderer:

public class WorkableCellRenderer implements ListCellRenderer<Workable> {

    @Override
    public final Component getListCellRendererComponent(final JList<? extends Workable> list, final Workable value,
            final int index, final boolean isSelected, final boolean isFocused) {
        JPanel cell = new JPanel();
        cell.setLayout(new BoxLayout(cell, BoxLayout.Y_AXIS));

        // ...

        JPanel pnlDescription = new JPanel();
        cell.add(pnlDescription);
        pnlDescription.setLayout(new BorderLayout());

        JLabel lblDescription =
                new JLabel("<html><p style=\"margin: 0; padding: 0;\">" + value.getDescription() + "</p></html>");
        lblDescription.setFont(lblDescription.getFont().deriveFont(Font.PLAIN));
        pnlDescription.add(lblDescription, BorderLayout.CENTER);

        // ...

        return cell;
    }

}

The method that adds my list to the JFrame:

private void addLoadedModulesPanel() {
    pnlLoadedModulesWrapper = new JPanel();
    pnlBottom.add(pnlLoadedModulesWrapper, BorderLayout.CENTER);
    pnlLoadedModulesWrapper.setLayout(new MigLayout("insets 0 5 5 5", "[grow]", "[grow]"));

    pnlLoadedModulesBox = new JPanel();
    pnlLoadedModulesWrapper.add(pnlLoadedModulesBox, "cell 0 0,grow");
    pnlLoadedModulesBox.setLayout(new MigLayout("insets 3", "[grow]", "[grow]"));
    pnlLoadedModulesBox.setBorder(BorderFactory.createTitledBorder("Geladene Module"));

    lstLoadedModules = new JList<Workable>(DefaultWorkableManager.getInstance());
    lstLoadedModules.setCellRenderer(new WorkableCellRenderer());

    final JScrollPane listScroller = new JScrollPane(lstLoadedModules);

    pnlLoadedModulesBox.add(listScroller, "cell 0 0,grow");
}

I think that the problem is the viewport of the JScrollPane because it is bigger than the JScrollPane itself. How can I adjust the viewports width so that it has always the same width as the JScrollPane?

Here is a MCVE which shows my problem:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;

import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.border.EmptyBorder;

public class TestFrame extends JFrame {

    private static final long serialVersionUID = -5281126214046039839L;

    public static void main(final String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    final TestFrame frame = new TestFrame();
                    frame.setVisible(true);
                } catch (final Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public TestFrame() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(200, 500);
        getContentPane().setLayout(new BorderLayout());

        final JPanel mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout());
        mainPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
        getContentPane().add(mainPanel);

        final DefaultListModel<String> lm = new DefaultListModel<>();
        final JList<String> list = new JList<>(lm);
        list.setCellRenderer(new MyListCellRenderer());

        final JScrollPane scrollPane = new JScrollPane(list);
        mainPanel.add(scrollPane);

        for (int i = 1; i < 21; i++) {
            lm.addElement(String.valueOf(i));
        }
    }

    private class MyListCellRenderer implements ListCellRenderer<String> {

        private final JPanel panel = new JPanel();
        private final JLabel label = new JLabel();

        public MyListCellRenderer() {
            panel.setLayout(new BorderLayout());
            panel.setBackground(new Color(16777215));
            panel.add(label);
        }

        @Override
        public Component getListCellRendererComponent(final JList<? extends String> list, final String val,
                final int index, final boolean isSelected, final boolean hasFocus) {
            label.setText("<html><p>Item number " + val
                    + " contains some very long text, that ideally should wrap.</p></html>");

            if (isSelected) {
                panel.setBackground(new Color(5323));
            } else {
                panel.setBackground(new Color(16777215));
            }

            return panel;
        }
    }

}
stevecross
  • 5,588
  • 7
  • 47
  • 85
  • 2
    For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete and Verifiable Example). You'll need to factor out the `MigLayout` (use standard JSE layouts) to make it an MCVE that most people can try quickly. – Andrew Thompson Apr 30 '14 at 08:25
  • 4
    unrelated: never-ever create a new component on each call to getXXRenderer, instead create it once and configure it as needed (that's the whole point of the rendering mechanism) – kleopatra Apr 30 '14 at 08:48

2 Answers2

2

everything depends ..., then JList in JScrollPane can returns proper getPreferredSize (or directly by using JList.setPrototypeCellValue) for used LayoutManager

  1. whats is value for getPreferredSize returns ListCellRenderer, is this PreferredSize the same for all Items or not

  2. how is set for JList.setLayoutOrientation()

  3. is there used limits for visible row or not JList.setVisibleRowCount()

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • I don't call `JList.setVisibleRowCount()` or `JList.setLayoutOrientation()`. The `ListCellRenderer` has no method `getPreferredSize()`. – stevecross Apr 30 '14 at 09:21
  • 1. getPreferredSize (that by default returns all JComponents to LayoutManager) is concentrations of my 3 points shortcut is setPrototypeCellValue, 2. don't recreate an JComponents in ListCellRenderer (in comment by kleopatra) 3. for why reason is there JPanel with JLabes, 4. nothing there indicating your goal, all there (possible answer) is about guessing, 5. as aside your model could be wrongly designed (guessing by seeing woodoo in Renderer) – mKorbel Apr 30 '14 at 10:22
  • [maybe will help you](http://stackoverflow.com/a/6355910/714968), [idea without side effects](http://stackoverflow.com/a/12867849/714968) – mKorbel Apr 30 '14 at 10:59
  • I added an MCVE which does the same as my original program. – stevecross Apr 30 '14 at 11:17
  • issue is in used LayoutManager, to try to change to another LayoutManager, again is there any reasons tho paiting JPanel with Jlabel in the Renderer – mKorbel Apr 30 '14 at 11:36
  • The original panel contains some other labels, but they are not wrapping. – stevecross Apr 30 '14 at 11:38
  • whats happends with GridBagLayout/BoxLayout, see (in contrast with) linked code in one of my comments here – mKorbel Apr 30 '14 at 11:57
1

think that the problem is the viewport of the JScrollPane because it is bigger than the JScrollPane itself. How can I adjust the viewports width so that it has always the same width as the JScrollPane?

You need to implement the Scrollable interface on your panel to limit the width of the panel to the width of the scroll pane.

Or you can use the Scrollable Panel which provides a couple of methods that allow you to control this behaviour.

camickr
  • 321,443
  • 19
  • 166
  • 288