如何在 String.format 中均匀地 space 字符串,这是 JList 中的 DefaultListModel?
How to evenly space Strings in String.format that's a DefaultListModel within 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()?
中定义字符串的最小长度
您可以简单地使用
%20s
例如 - 这将在格式化输出中放入 20 个空格。
所以诀窍基本上是首先扫描列表中的所有字符串,然后计算格式化模式中所需的合理数量。换句话说:您首先要确定要显示的字符串的最大长度;然后计算适当的缩进,例如。
编辑:有许多不同的方法可以影响格式,请参阅此 question, or enter link description here, or best, study the javadoc,它指定了所有存在的格式模式!
正如@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);
}
}
最简单的解决方案是使用等宽字体和字符串格式。
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;
}
}
这将导致
我已经在这里问过了,所以请仔细阅读这里。此问题已部分 解决。
现在我有另一个问题:
请先看这个例子
// 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()?
中定义字符串的最小长度您可以简单地使用
%20s
例如 - 这将在格式化输出中放入 20 个空格。
所以诀窍基本上是首先扫描列表中的所有字符串,然后计算格式化模式中所需的合理数量。换句话说:您首先要确定要显示的字符串的最大长度;然后计算适当的缩进,例如。
编辑:有许多不同的方法可以影响格式,请参阅此 question, or enter link description here, or best, study the javadoc,它指定了所有存在的格式模式!
正如@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);
}
}
最简单的解决方案是使用等宽字体和字符串格式。
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;
}
}
这将导致