问题
I have a loop that generates some Titles and Description which are String values and I made Labels to contains theses two strings, I want to add these to a JScrollPane
, but for some reason my code isn't working, I'm not getting any error now, no item is being added to the scroll pane, here's my code:
package testa;
import java.awt.Color;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class test extends JFrame {
JLabel[] titles;
JLabel[] descriptions;
JPanel[] panels;
JScrollPane jScrollPane1 = new JScrollPane();
JPanel bigPanel = new JPanel();
public test() {
this.setLocationRelativeTo(null);
this.setSize(1000, 500);
this.jScrollPane1.setSize(1000, 500);
this.getContentPane().add(this.jScrollPane1);
this.setVisible(true);
requetezQuery();
}
public void requetezQuery() {
int resultsList = 10;
this.titles = new JLabel[resultsList];
this.descriptions = new JLabel[resultsList];
this.panels = new JPanel[resultsList];
for (int i = 0; i < resultsList; i++) {
String title = "Test Title " + i;
String resume = "Test Resume " + i;
this.titles[i] = new JLabel();
this.descriptions[i] = new JLabel();
this.panels[i] = new JPanel();
this.panels[i].setLayout(new FlowLayout());
this.titles[i].setText(title);
this.descriptions[i].setText(resume);
this.titles[i].setForeground(Color.red);
this.descriptions[i].setForeground(Color.red);
this.panels[i].add(this.titles[i]);
this.panels[i].add(this.descriptions[i]);
this.bigPanel.add(panels[i]);
}
this.jScrollPane1.add(this.bigPanel);
}
public static void main(String args[]) {
test a = new test();
}
}
I tried to System.out.println
the titles and resume variables and its working, so the problem isn't from them.
回答1:
I made some corrections to make you code work, and added comments to explain what needs to be done:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Test extends JFrame{ //see https://www.javatpoint.com/java-naming-conventions
private JLabel[] titles;
private JLabel[] descriptions;
private JPanel [] panels;
private JScrollPane jScrollPane1;
private JPanel bigPanel;
private final static int NUM_OF_RESULTS =10;
public Test() {
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//this.setSize(1000,500); no need to set size. use preferred sizes
//jScrollPane1.setSize(1000, 500); and layouts. see following comments
bigPanel = new JPanel();
//set layout to
GridLayout layout = new GridLayout(NUM_OF_RESULTS, 0);
bigPanel.setLayout(layout);
jScrollPane1 = new JScrollPane(bigPanel);
getContentPane().add(jScrollPane1);
requetezQuery();
pack(); //see https://stackoverflow.com/questions/22982295/what-does-pack-do
setVisible(true); //set visible typically comes last
}
public void requetezQuery(){
titles = new JLabel[NUM_OF_RESULTS];
descriptions = new JLabel[NUM_OF_RESULTS];
panels = new JPanel[NUM_OF_RESULTS];
for(int i = 0; i<NUM_OF_RESULTS; i++){
String title="Test Title "+i;
String resume="Test Resume "+i;
titles[i]= new JLabel();
descriptions[i]= new JLabel();
panels[i]= new JPanel();
panels[i].setPreferredSize(new Dimension(250, 50));
panels[i].setLayout(new FlowLayout()); //FlowLayout is default for JPanel
titles[i].setText(title);
descriptions[i].setText(resume);
titles[i].setForeground(Color.red);
descriptions[i].setForeground(Color.red);
panels[i].add(titles[i]);
panels[i].add(descriptions[i]);
bigPanel.add(panels[i],i, 0);
}
}
public static void main(String args[]){
new Test();
}
}
The code can be further improved. I tried to minimize changes hoping that it makes it easier for you to see the changes.
Don't hesitate to ask for clarifications as needed.
回答2:
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());
}
}
来源:https://stackoverflow.com/questions/50421190/add-labels-inside-jscrollpane-inside-loop