当我将HTML标记组合到JLabel文本中时,我忽略了当空间太小而无法显示完整文本时显示的省略号行为。在我的特定情况下,它是一个TableCellRenderer,它扩展了JLabel(swing的默认值或其他)。现在,当列宽太小而文本无法完全显示时,它不会显示省略号。
例如,见下图:
对于左列,我使用HTML将文本包装在渲染器中:setText("<html>" + "<strong>" + value.toString() + "</strong>" + "</html>");
。正如您所看到的,当列宽太小而无法包含文本时,它只是被剪切。但是,显示日期和时间并使用DefaultTableCellRenderer
的右列在未能包含完整文本时显示省略号。
所以我的问题是,我可以同时拥有两个吗?意思是,用HTML包装文本并仍然得到省略号?
更新
我发现在使用HTML时没有获得省略号的原因。我按照JComponent#paintComponent(Graphics g)
的代码一直到BasicLabelUI#layoutCL(...)
。请参阅从上一个中获取的以下代码段。如果它没有html属性,它只剪裁字符串(当标签文本用html包装时为true)。但我不知道如何解决它:
v = (c != null) ? (View) c.getClientProperty("html") : null;
if (v != null) {
textR.width = Math.min(availTextWidth,
(int) v.getPreferredSpan(View.X_AXIS));
textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
} else {
textR.width = SwingUtilities2.stringWidth(c, fm, text);
lsb = SwingUtilities2.getLeftSideBearing(c, fm, text);
if (lsb < 0) {
// If lsb is negative, add it to the width and later
// adjust the x location. This gives more space than is
// actually needed.
// This is done like this for two reasons:
// 1. If we set the width to the actual bounds all
// callers would have to account for negative lsb
// (pref size calculations ONLY look at width of
// textR)
// 2. You can do a drawString at the returned location
// and the text won't be clipped.
textR.width -= lsb;
}
if (textR.width > availTextWidth) {
text = SwingUtilities2.clipString(c, fm, text,
availTextWidth);
textR.width = SwingUtilities2.stringWidth(c, fm, text);
}
textR.height = fm.getHeight();
}
答案 0 :(得分:1)
只要您的问题中的HTML内容简单,使用定制的JLabel即可完成省略号显示。这是一个工作示例。 只需调整窗口的大小,您会看到省略号出现和消失,并且随着标签随窗口调整大小而适当地剪切了文本。
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JLabel;
import javax.swing.border.Border;
public class SimpleHTMLJLabel extends JLabel
{
private static final long serialVersionUID = -1799635451172963826L;
private String textproper;
private String ellipsis = "...";
private int textproperwidth;
private FontMetrics fontMetrics;
private int ellipsisWidth;
private int insetsHorizontal;
private int borderHorizontal;
public SimpleHTMLJLabel(String textstart, String textproper, String textend)
{
super(textstart + textproper + textend);
this.textproper = textproper;
insetsHorizontal = getInsets().left + getInsets().right;
fontMetrics = getFontMetrics(getFont());
calculateWidths();
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e)
{
int availablewidth = getWidth();
if (textproperwidth > availablewidth - (insetsHorizontal + borderHorizontal))
{
String clippedtextproper = textproper;
while (clippedtextproper.length() > 0
&& fontMetrics.stringWidth(clippedtextproper) + ellipsisWidth > availablewidth - (insetsHorizontal + borderHorizontal))
{
clippedtextproper = clipText(clippedtextproper);
}
setText(textstart + clippedtextproper + ellipsis + textend);
} else
{
setText(textstart + textproper + textend);
}
}
});
}
private void calculateWidths()
{
if (textproper != null)
{
textproperwidth = fontMetrics.stringWidth(textproper);
}
if (ellipsis != null)
{
ellipsisWidth = fontMetrics.stringWidth(ellipsis);
}
}
@Override
public void setFont(Font font)
{
super.setFont(font);
fontMetrics = getFontMetrics(getFont());
calculateWidths();
}
private String clipText(String clippedtextproper)
{
return clippedtextproper.substring(0, clippedtextproper.length() - 1);
}
@Override
public void setBorder(Border border)
{
super.setBorder(border);
borderHorizontal = border.getBorderInsets(this).left + border.getBorderInsets(this).right;
}
}
主要
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Main
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run()
{
JFrame window = new JFrame();
window.setResizable(true);
window.setTitle("Label Test");
window.getContentPane().add(getContent());
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400, 200);
window.setLocationRelativeTo(null);
window.setVisible(true);
}
});
}
protected static Component getContent()
{
JPanel panel = new JPanel(new BorderLayout());
SimpleHTMLJLabel label = new SimpleHTMLJLabel("<html><strong>", "TEST1test2TEST3test4TEST5test6TEST7test8TEST", "</strong></html>");
label.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.BLUE, 5),
BorderFactory.createEmptyBorder(10, 10, 10, 10)));
label.setFont(label.getFont().deriveFont(20F));
panel.add(label, BorderLayout.CENTER);
return panel;
}
}
答案 1 :(得分:0)
我要说:不,你不能同时拥有。
我认为如果你想要自定义样式和省略号,你必须自己不用HTML和使用自定义TableCellRenderer。
如果你想尝试吃蛋糕并吃掉它,你可以通过创建自己的View对象并使用c.putClientProperty(&#34; html&#34;,value)来设置它,但是我怀疑HTML呈现代码没有ellipsing的概念(文本溢出是HTML 5ish特性)所以你必须弄清楚如何教它做这件事。我怀疑这比编写自己的TableCellRenderer要困难得多。
答案 2 :(得分:0)
这里是SimpleHTMLJLabel的修改版,正在使用上面的代码
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.IOException;
import java.io.StringReader;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import javax.swing.JLabel;
import javax.swing.border.Border;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML.Tag;
import javax.swing.text.html.HTMLEditorKit.ParserCallback;
public class SimpleHTMLJLabel extends JLabel {
private static final String ellipsis = "...";
private static final String Set = null;
private int textproperwidth;
private FontMetrics fontMetrics;
private int ellipsisWidth;
private int insetsHorizontal;
private int borderHorizontal;
private List<Entry<String, String>> lines;
static String HTML = "<HTML>";
public SimpleHTMLJLabel() {
insetsHorizontal = getInsets().left + getInsets().right;
fontMetrics = getFontMetrics(getFont());
calculateWidths();
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
int availablewidth = getWidth();
renderHtml(availablewidth);
}
});
}
public SimpleHTMLJLabel(String text) {
this();
setText(text);
}
public SimpleHTMLJLabel(List<Entry<String, String>> lines) {
this();
this.lines = lines;
calculateWidths();
super.setText(HTML + toHtml(lines));
}
@Override
public void setText(String text) {
if (text.toUpperCase().startsWith(HTML)) {
this.lines = parseHtml(text);
calculateWidths();
super.setText(HTML + toHtml(lines));
return;
}
super.setText(text);
}
private List<Entry<String, String>> parseHtml(String text) {
List<Entry<String, String>> ret = new ArrayList<>();
java.util.Map<Tag, MutableAttributeSet> tags = new HashMap<>();
try {
(new javax.swing.text.html.parser.ParserDelegator()).parse(new StringReader(text), new ParserCallback() {
@Override
public void handleEndTag(Tag t, int pos) {
//TODO clean handle MutableAttributeSet a
tags.remove(t);
}
@Override
public void handleStartTag(javax.swing.text.html.HTML.Tag t, MutableAttributeSet a, int pos) {
if (t == Tag.HTML) return;
if (t == Tag.P) return;
if (t == Tag.BR) return;
if (t == Tag.BODY) return;
tags.put(t,a);
}
@Override
public void handleText(char[] data, int pos) {
String formats = tags.entrySet().stream().map(t -> "<" + t.getKey() + getAttrib(t.getValue) + ">").collect(Collectors.joining());
ret.add(new AbstractMap.SimpleEntry<>(formats, new String(data)));
}
private String getAttrib(MutableAttributeSet t) {
// TODO Auto-generated method stub
//return " style='color:red'";
return " " + t;
}
}, false);
} catch (IOException e) {
e.printStackTrace();
}
return ret;
}
private static String toEndTag(String s) {
return s.replace("<", "</");
}
private static String toHtml(List<Entry<String, String>> lines) {
return lines.stream().map(s -> s.getKey() + s.getValue() + toEndTag(s.getKey())).collect(Collectors.joining());
}
private static String toPlain(List<Entry<String, String>> lines) {
return lines.stream().map(s -> s.getValue()).collect(Collectors.joining(" "));
}
static private List<Entry<String, String>> clipText(List<Entry<String, String>> properList) {
Entry<String, String> last = properList.get(properList.size() - 1);
List<Entry<String, String>> ret = properList.subList(0, properList.size() - 1);
String newlastValue = truncate(last.getValue());
if (newlastValue.isEmpty()) {
return ret;
}
List<Entry<String, String>> retNew = new ArrayList<>();
retNew.addAll(ret);
retNew.add(new AbstractMap.SimpleEntry<>(last.getKey(), newlastValue));
return retNew;
}
static private String truncate(String newlastValue) {
newlastValue = newlastValue.substring(0, newlastValue.length() - 1);
while (newlastValue.endsWith(" ")) {
newlastValue = newlastValue.substring(0, newlastValue.length() - 1);
}
return newlastValue;
}
private void calculateWidths() {
if (lines != null) {
textproperwidth = fontMetrics.stringWidth(toPlain(lines));
}
ellipsisWidth = fontMetrics.stringWidth(ellipsis);
}
@Override
public void setFont(Font font) {
super.setFont(font);
fontMetrics = getFontMetrics(getFont());
calculateWidths();
}
@Override
public void setBorder(Border border) {
super.setBorder(border);
borderHorizontal = border.getBorderInsets(this).left + border.getBorderInsets(this).right;
}
}
在TableCellRenderer中使用我的代码时,您需要在构造函数中立即调整大小,但是在没有列大小的情况下:
public SimpleHTMLJLabel() {
...
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
int availablewidth = getWidth();
renderHtml(availablewidth);
}
});
}
protected void renderHtml(int availablewidth) {
if (lines == null || availablewidth == 0) return;
System.out.println("renderHtml " + textproperwidth + ">" + availablewidth);
if (textproperwidth > availablewidth - (insetsHorizontal + borderHorizontal)) {
List<Entry<String, String>> properList = clipText(lines);
while (properList.size() > 0 && fontMetrics.stringWidth(toPlain(properList)) + ellipsisWidth > availablewidth - (insetsHorizontal + borderHorizontal)) {
properList = clipText(properList);
}
SimpleHTMLJLabel.super.setText(HTML + toHtml(properList) + ellipsis);
} else {
SimpleHTMLJLabel.super.setText(HTML + toHtml(lines));
}
}
@Override
public void reshape(int x, int y, int w, int h) {
if (w > 0) renderHtml(w - 5);
super.reshape(x, y, w, h);
}
和在JTable中
table = new JTable(model) {
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
TableColumn col = table.getColumnModel().getColumn(column);
javax.swing.table.DefaultTableCellRenderer.UIResource csss;
SimpleHTMLJLabel lab = new SimpleHTMLJLabel(((JLabel)
//lab.setXXX( c.getXXX)); for font bcolor, color, border, etc
lab.setText(c.getText());
lab.renderHtml(col.getWidth() - 5);
return lab;
}
};
一个人可以重用html-labell组件来保存GC