我如何在Java中的JList中包装内容

问题描述:

现在我只有一个显示文件列表(带图标)的JList。我使用DefaultListCellRenderer来完成此操作。但是,我只希望它显示3列,但它显示更多。我不希望用户必须垂直滚动才能滚动。我怎样才能做到这一点?我对Java相当陌生。这是到目前为止我的代码:我如何在Java中的JList中包装内容

import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.Insets; 
import java.io.File; 
import java.io.FileFilter; 

import javax.swing.DefaultListCellRenderer; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JList; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.border.EmptyBorder; 
import javax.swing.filechooser.FileSystemView; 

public class StartMeUpBaby extends JFrame { 

    public StartMeUpBaby() { 

     this.setLocationRelativeTo(null); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     this.setTitle("TESTING"); 

     JPanel mainPanel = new JPanel(); 
     mainPanel.setLayout(new GridBagLayout()); 

     File f = new File(System.getProperty("user.home")); 

     JList<File> results = new JList<File>(f.listFiles(new FileFilter() { 

      public boolean accept(File file) { 

       String name = file.getName().toLowerCase(); 
       return name.length() < 20; 

      } 

     })); 

     results.setCellRenderer(new DefaultListCellRenderer() { 

      public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { 

       Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 
       JLabel label = (JLabel)component; 
       File file = (File)value; 

       label.setText(file.getName()); 
       label.setIcon(FileSystemView.getFileSystemView().getSystemIcon(file)); 
       label.setBorder(new EmptyBorder(3, 3, 3, 3)); 

       return label; 

      } 

     }); 

     results.setLayoutOrientation(JList.HORIZONTAL_WRAP); 

     JScrollPane scrollPane = new JScrollPane(results, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
     scrollPane.setPreferredSize(new Dimension(408, 100)); 

     GridBagConstraints gbc = new GridBagConstraints(); 

     gbc.gridx = 0; 
     gbc.gridy = 0; 

     gbc.gridwidth = 3; 
     gbc.gridheight = 2; 

     gbc.weightx = 100; 
     gbc.weighty = 100; 

     gbc.anchor = GridBagConstraints.WEST; 
     gbc.fill = GridBagConstraints.HORIZONTAL; 

     gbc.insets = new Insets(5, 5, 5, 5); 

     mainPanel.add(scrollPane, gbc); 

     this.add(mainPanel); 
     this.pack(); 
     this.setVisible(true); 

    } 

    public static void main(String[] args) { 

     new StartMeUpBaby(); 

    } 

} 

注:我首选大小设置为只显示3列,但是如果你调整窗口(使它更大),你可以看到,柱继续。

在通过Java文档进行了一些研究之后,我发现了它。

我所要做的就是加入这一行:

results.setVisibleRowCount(-1); 

documentation of JList.setLayoutOrientation

HORIZONTAL_WRAP - 细胞水平布局,包裹在必要时新行。如果visibleRowCount属性小于或等于零,则换行由列表的宽度决定;否则包装会以确保列表中的visibleRowCount行的方式完成。

因此,您可以通过添加这种解决您的问题:

results.setVisibleRowCount(0); 

但是,你JScrollPane的大小(setPreferredSize(new Dimension(488, 100)))是任意的。显示三列所需的大小取决于所显示的文件名以及JList字体等可视属性。如果即使只有一个相当长的文件名,单元格也会变宽,而且你的尺寸可能不够。

要完全健壮,则需要根据每个文件的渲染计算首选大小:

File f = new File(System.getProperty("user.home")); 

File[] files = f.listFiles(new FileFilter() { 

    public boolean accept(File file) { 

     String name = file.getName().toLowerCase(); 
     return name.length() < 20; 

    } 

}); 

JList<File> results = new JList<File>(files) { 
    private Dimension maxCellSize = new Dimension(); 

    @Override 
    public void addNotify() { 
     super.addNotify(); 
     recomputeMaxCellSize(); 
    } 

    private void recomputeMaxCellSize() { 
     ListCellRenderer<? super File> renderer = getCellRenderer(); 
     if (renderer == null) { 
      return; 
     } 

     int fixedWidth = getFixedCellWidth(); 
     int fixedHeight = getFixedCellHeight(); 

     Rectangle maxCellBounds = new Rectangle(); 
     for (int i = getModel().getSize() - 1; i >= 0; i--) { 
      Component c = 
       renderer.getListCellRendererComponent(this, 
        getModel().getElementAt(i), i, false, false); 
      Dimension cellSize = c.getPreferredSize(); 
      maxCellBounds.add(
       fixedWidth >= 0 ? fixedWidth : cellSize.width, 
       fixedHeight >= 0 ? fixedHeight : cellSize.height); 
     } 

     maxCellSize = maxCellBounds.getSize(); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     int count = getModel().getSize(); 
     int rows = count/3 + (count % 3 == 0 ? 0 : 1); 

     return new Dimension(maxCellSize.width * 3, 
          maxCellSize.height * rows); 
    } 

    @Override 
    public Dimension getPreferredScrollableViewportSize() { 
     int rows = getVisibleRowCount(); 
     if (rows <= 0) { 
      rows = 4; 
     } 

     return new Dimension(maxCellSize.width * 3, 
          maxCellSize.height * rows); 
    } 

    private final ListDataListener modelListener = new ListDataListener() { 
     @Override 
     public void intervalAdded(ListDataEvent event) { 
      recomputeMaxCellSize(); 
     } 

     @Override 
     public void intervalRemoved(ListDataEvent event) { 
      recomputeMaxCellSize(); 
     } 

     @Override 
     public void contentsChanged(ListDataEvent event) { 
      recomputeMaxCellSize(); 
     } 
    }; 

    @Override 
    public void setModel(ListModel<File> newModel) { 
     getModel().removeListDataListener(modelListener); 
     newModel.addListDataListener(modelListener); 
     super.setModel(newModel); 
     recomputeMaxCellSize(); 
    } 

    @Override 
    public void setCellRenderer(ListCellRenderer<? super File> renderer) { 
     super.setCellRenderer(renderer); 
     recomputeMaxCellSize(); 
    } 

    @Override 
    public void setFont(Font font) { 
     super.setFont(font); 
     recomputeMaxCellSize(); 
    } 

    @Override 
    public void setFixedCellWidth(int width) { 
     super.setFixedCellWidth(width); 
     recomputeMaxCellSize(); 
    } 

    @Override 
    public void setFixedCellHeight(int height) { 
     super.setFixedCellHeight(height); 
     recomputeMaxCellSize(); 
    } 
}; 

results.setVisibleRowCount(0);