One problem is that you're trying to add components directly to the JScrollPane which is not where the components are supposed to go. Instead these components belong within the viewport's view, the component that the JScrollPane is displaying.
Suggestions:
- create a JPanel that represents this view, and add this to the JScrollPane's viewport.
- Give this JPanel a decent layout so that it will be able to display components added to it correctly
- In your code above, add your components to this JPanel, then revalidate and repaint it so that its layout managers layout the components and paint them correctly.
- Or perhaps better still and much cleaner, add your tabular data to a JTable that is held by the JScrollPane
For example, the code below adds a pair of JLabels to an innerPanel JPanel, one which uses a BorderLayout to place one label to the left and the other center.
It then places this innerPanel into another JPanel, viewportViewPanel, which uses a GridLayout to place the innerPanel in a single column multiple row grid. The viewportViewPanel is placed within a JScrollPane's viewport by passing it into the JScrollPane's constructor. Note that we never call .add(...)
on the JScrollPane:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
public class MyTest extends JPanel {
private static final int COUNT = 400;
private JPanel viewportViewPanel = new JPanel();
private JScrollPane scrollPane = new JScrollPane(viewportViewPanel);
public MyTest() {
setPreferredSize(new Dimension(800, 500));
viewportViewPanel.setLayout(new GridLayout(0, 1));
for (int i = 0; i < COUNT; i++) {
String text = "abcd efgh ijkl mnop qrst uvwx";
text = String.format("%s %s %s", text, text, text);
JPanel innerPanel = new JPanel();
innerPanel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
innerPanel.setLayout(new BorderLayout());
innerPanel.add(new JLabel("Test Title:"), BorderLayout.LINE_START);
innerPanel.add(new JLabel(text, SwingConstants.CENTER));
viewportViewPanel.add(innerPanel);
}
setLayout(new BorderLayout());
add(scrollPane);
}
private static void createAndShowGui() {
MyTest mainPanel = new MyTest();
JFrame frame = new JFrame("MyTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Better still, if your desire is to show a title and description, consider showing only the titles in a JList, and showing the selected JList item's description within a JTextArea. Something like so:
import java.awt.BorderLayout;
import javax.swing.*;
@SuppressWarnings("serial")
public class ShowTitleDescriptions extends JPanel {
private static final int COUNT = 500;
// nonsense text as a demo filler
private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur "
+ "adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore "
+ "magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco "
+ "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor "
+ "in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla "
+ "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa "
+ "qui officia deserunt mollit anim id est laborum.";
private DefaultListModel<TitleDescription> listModel = new DefaultListModel<>();
private JList<TitleDescription> titlesList = new JList<>(listModel);
private JTextArea descriptionArea = new JTextArea(20, 60);
public ShowTitleDescriptions() {
titlesList.setVisibleRowCount(20);
JScrollPane titleScroll = new JScrollPane(titlesList);
descriptionArea.setLineWrap(true);
descriptionArea.setWrapStyleWord(true);
descriptionArea.setEditable(false);
JScrollPane descriptionScroll = new JScrollPane(descriptionArea);
for (int i = 0; i < COUNT; i++) {
String title = "Title " + i;
StringBuilder descriptionSb = new StringBuilder();
// fill description with random text
for (int j = 0; j < 40; j++) {
descriptionSb.append(title + "\n");
descriptionSb.append(LOREM_IPSUM + " ");
descriptionSb.append(LOREM_IPSUM + " ");
descriptionSb.append(LOREM_IPSUM);
descriptionSb.append("\n\n");
}
TitleDescription titleDescr = new TitleDescription(title, descriptionSb.toString());
listModel.addElement(titleDescr);
}
titlesList.addListSelectionListener(l -> {
TitleDescription selection = titlesList.getSelectedValue();
descriptionArea.setText(selection.getDescription());
});
titlesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
titlesList.setSelectedIndex(0);
setLayout(new BorderLayout());
add(descriptionScroll);
add(titleScroll, BorderLayout.LINE_END);
}
// class to hold title and description together
private static class TitleDescription {
private String title;
private String description;
public TitleDescription(String title, String description) {
this.title = title;
this.description = description;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
// JList uses this to decide what to display
@Override
public String toString() {
return title;
}
}
private static void createAndShowGui() {
ShowTitleDescriptions mainPanel = new ShowTitleDescriptions();
JFrame frame = new JFrame("ShowTitleDescriptions");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}