【问题标题】:How to evenly space Strings in String.format that's a DefaultListModel within a JList?如何在 JList 中以 DefaultListModel 的 String.format 均匀分布字符串?
【发布时间】:2017-04-29 18:22:03
【问题描述】:

我已经在这里问过了,所以请仔细阅读这里。此问题已部分解决。 How can I add \t spacing in a String that belongs to a DefaultListModel which belongs to a JLIst?

现在我有另一个问题:

请先看这个例子

// Declarations
String string1 = "Eggs";
String string2 = "Whole Chicken";
int quantity1 = 100;
int quantity2 = 25;

// HTML and PRE tags are added before and after string
StringBuilder builder1 = new Stringbuilder;
builder.append("<html><pre>");
builder.append(String.format("%s \t %d", string1, quantity1));
builder.append("</pre></html>");

StringBuilder builder2 = new Stringbuilder;
builder.append("<html><pre>");
builder.append(String.format("%s \t %d", string2, quantity2));
builder.append("</pre></html>");

// JList is defined, and the builder is added to the list.
JList<String> list = new JList<String>();
list.addElement(builder1.toString());
list.addElement(builder2.toString());

这是显示所有项目的方式

Eggs    100
Whole Chicken    25

我想要发生的是所有数量变量都是对齐的,而不是基于前一个变量的间隔。有什么想法可以实现吗?

谢谢!

===========================

另一个建议是是否可以在 String.format() 中定义字符串的最小长度?

【问题讨论】:

    标签: java string jlist defaultlistmodel


    【解决方案1】:

    最简单的解决方案是使用等宽字体和字符串格式。

    public class Main {
    
      public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setSize(320, 100);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    
        Container contentPane = frame.getContentPane();
    
        DefaultListModel<String> defaultListModel = new DefaultListModel<>();
        defaultListModel.addElement(String.format("%-20s %d", "Eggs", 100));
        defaultListModel.addElement(String.format("%-20s %d", "Whole Chicken", 25));
    
        JList<String> jList = new JList<>(defaultListModel);
        Font defaultListFont = jList.getFont();
        jList.setFont(new Font("monospaced", defaultListFont.getStyle(), defaultListFont.getSize()));
    
        contentPane.add(jList);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    }
    

    这将导致

    不使用等宽字体的解决方案

    如果您想根据ListModel 对齐列宽,我会听取ListModel 的更改,以便计算模型中最长的字符串并使用自定义渲染器。

    public static void main(String[] args) {
      JFrame frame = new JFrame();
      frame.setSize(320, 150);
      frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    
      Container contentPane = frame.getContentPane();
    
      DefaultListModel<String[]> defaultListModel = new DefaultListModel<>();
      defaultListModel.addElement(new String[]{"Eggs", "100"});
      defaultListModel.addElement(new String[]{"The longest Entry in the list", "12125"});
      defaultListModel.addElement(new String[]{"Whole Chicken", "25"});
    
      JList<String[]> jList = new JList<>(defaultListModel);
    
      ListModelAwareColumnWidthProvider listModelAwareColumnWidthProvider = new ListModelAwareColumnWidthProvider();
      listModelAwareColumnWidthProvider.setListModel(defaultListModel);
    
      ColumnCellRenderer columnCellRenderer = new ColumnCellRenderer(listModelAwareColumnWidthProvider);
      jList.setCellRenderer(columnCellRenderer);
    
      contentPane.add(jList);
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
    }
    

    你必须实现类似的东西

    支持列的渲染器

    class ColumnCellRenderer implements ListCellRenderer<String[]> {
    
      private ColumnWidthProvider columnWidthProvider;
    
      public ColumnCellRenderer(ColumnWidthProvider columnWidthProvider) {
        this.columnWidthProvider = columnWidthProvider;
      }
    
    
      @Override
      public Component getListCellRendererComponent(JList<? extends String[]> list, String[] value, int index, boolean isSelected, boolean cellHasFocus) {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
    
        for (int i = 0; i < value.length; i++) {
          String valueElement = value[i];
    
          JLabel label = new JLabel(valueElement);
    
          align(label, i);
          panel.add(label);
        }
    
        applyColors(list, panel, isSelected);
    
        return panel;
      }
    
      private void applyColors(JList<?> list, JComponent component, boolean isSelected) {
        if (isSelected) {
          component.setForeground(list.getSelectionForeground());
          component.setBackground(list.getSelectionBackground());
        } else {
          component.setForeground(list.getForeground());
          component.setBackground(list.getBackground());
        }
      }
    
      private void align(JComponent component, int columnIndex) {
        Font font = component.getFont();
        FontMetrics fontMetrics = component.getFontMetrics(font);
        int fontHeight = fontMetrics.getHeight();
    
        int columnWidth = columnWidthProvider.getColumnWidth(fontMetrics, columnIndex);
        component.setPreferredSize(new Dimension(columnWidth, fontHeight));
      }
    
    }
    

    渲染器获取列宽的接口

    interface ColumnWidthProvider {
      public int getColumnWidth(FontMetrics fontMetrics, int columnIndex);
    }
    

    以及观察 ListModel 内容变化的 ColumnWidthProvider 的实现

    class ListModelAwareColumnWidthProvider implements ColumnWidthProvider {
    
      private class ListModelChangeAdapter implements ListDataListener {
        @Override
        public void intervalAdded(ListDataEvent e) {
          initializeColumnWidths();
        }
    
        @Override
        public void intervalRemoved(ListDataEvent e) {
          initializeColumnWidths();
        }
    
        @Override
        public void contentsChanged(ListDataEvent e) {
          initializeColumnWidths();
        }
      }
    
      private int defaultColumnWidth = 100;
    
      private ListModelChangeAdapter listModelChangeAdapter = new ListModelChangeAdapter();
      private ListModel<String[]> listModel;
      private java.util.List<String> longestColumnStrings = new ArrayList<>();
    
      public void setListModel(ListModel<String[]> listModel) {
        if (this.listModel != null) {
          this.listModel.removeListDataListener(listModelChangeAdapter);
        }
    
        this.listModel = listModel;
        initializeColumnWidths();
    
        if (this.listModel != null) {
          this.listModel.addListDataListener(listModelChangeAdapter);
        }
      }
    
      private void initializeColumnWidths() {
        longestColumnStrings.clear();
    
        if (listModel != null) {
          int size = listModel.getSize();
          for (int i = 0; i < size; i++) {
            String[] elementAt = listModel.getElementAt(i);
    
            for (int columnIndex = 0; columnIndex < elementAt.length; columnIndex++) {
              String columnValue = elementAt[columnIndex];
    
              while (columnIndex >= longestColumnStrings.size()) {
                longestColumnStrings.add(null);
              }
    
              String lastLongestColumnString = longestColumnStrings.get(columnIndex);
              if (lastLongestColumnString == null) {
                longestColumnStrings.set(columnIndex, columnValue);
              } else if (columnValue.length() > lastLongestColumnString.length()) {
                longestColumnStrings.set(columnIndex, columnValue);
              }
            }
          }
        }
      }
    
      public void setDefaultColumnWidth(int defaultColumnWidth) {
        this.defaultColumnWidth = defaultColumnWidth;
      }
    
      @Override
      public int getColumnWidth(FontMetrics fontMetrics, int columnIndex) {
        if (columnIndex < longestColumnStrings.size()) {
          String longestColumnString = longestColumnStrings.get(columnIndex);
          return fontMetrics.stringWidth(longestColumnString);
        }
        return defaultColumnWidth;
      }
    }
    

    这将导致

    【讨论】:

      【解决方案2】:

      你可以简单地使用

      %20s
      

      例如 - 这将在格式化输出中添加 20 个空格。

      所以诀窍基本上是首先扫描列表中的所有字符串,然后计算您在格式化模式中需要的合理数字。换句话说:您首先要确定要显示的字符串的最大长度;例如,然后计算适当的缩进。

      编辑:影响格式的方法有很多种,请参阅questionenter link description here,或者最好研究指定所有存在的格式模式的javadoc

      【讨论】:

      • 效果很好!还有一件事 - 我可以将 string1/string2 对齐到左侧而不是右侧吗?
      【解决方案3】:

      正如@GhostCat 所说,使用格式字符串中的宽度将解决您的问题。

      更多信息,请查看格式字符串的documentation

      但是,您尝试做的事情让我觉得,也许您可​​以使用 JTable,而不是使用 JList?

      import javax.swing.*;
      
      public class ssce{
          public static void main(String... args){
              // Declarations
              String string1 = "Eggs";
              String string2 = "Whole Chicken";
              int quantity1 = 100;
              int quantity2 = 25;
      
              JFrame f = new JFrame("prova");
              f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      
      
              String[] col = {"Ingredient", "Quantity"};
              Object[][] data = {
                  {string1, new Integer(quantity1)},
                  {string2, new Integer(quantity2)}
              };
              JTable tb = new JTable(data, col);
              f.add(tb);
              f.setSize(300, 400);
              f.setVisible(true);
          }
      }
      

      【讨论】:

      • 直接取自教程的示例。只需稍加工作并创建自定义TableModel,您就可以做更多的事情。
      猜你喜欢
      • 2013-04-14
      • 1970-01-01
      • 1970-01-01
      • 2018-05-18
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      • 1970-01-01
      • 2016-07-09
      相关资源
      最近更新 更多