首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在包含JLabel的中获得省略号?

如何在包含JLabel的中获得省略号?
EN

Stack Overflow用户
提问于 2015-06-30 14:58:56
回答 3查看 1.5K关注 0票数 7

当我将HTML标记组合到JLabel文本中时,我会放松当空格太小而无法显示完整文本时所显示的省略行为。在我的具体情况下,它是一个扩展TableCellRenderer (swing的默认或其他)的JLabel。现在,当列的宽度太小而不能完全显示文本时,它就不会显示省略号。

例如,请参见下面的图像:对于左边的列,我用HTML:setText("<html>" + "<strong>" + value.toString() + "</strong>" + "</html>");将文本包装在呈现器处。正如您所看到的,当列的宽度太小而不能包含文本时,它就被剪切了。然而,右边的列显示日期和时间,并使用DefaultTableCellRenderer显示省略号,当它不能包含完整的文本时。

所以我的问题是,我能两者兼得吗?意思是,用HTML包装文本,仍然得到省略号?

更新:

我发现了在使用HTML时没有得到省略号的原因。我一直遵循从JComponent#paintComponent(Graphics g)BasicLabelUI#layoutCL(...)的代码。请参阅下面从最后一个代码片段中获取的代码片段。只有当字符串没有html属性(当标签文本用html包装时是正确的),它才会裁剪字符串。然而,我不知道如何解决这个问题:

代码语言:javascript
运行
复制
    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();
    }
EN

回答 3

Stack Overflow用户

发布于 2019-08-17 18:26:35

只要HTML是简单的,就像在您的问题中一样,可以通过定制的JLabel来完成省略显示。下面是一个有用的例子。只要调整窗口的大小,您就会看到省略号出现并消失,并且随着标签与窗口的大小调整,文本将被适当地剪切。

代码语言:javascript
运行
复制
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;
    }
}

MAIN

代码语言:javascript
运行
复制
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;
    }
}
票数 2
EN

Stack Overflow用户

发布于 2018-05-07 21:18:25

我要说:不,你不能两者兼得。

我认为,如果您想要定制样式和省略,您将不得不自己做它没有HTML和自定义TableCellRenderer。

如果你想尝试吃蛋糕,你也可以通过创建自己的视图对象并使用c.putClientProperty(" HTML ",value)来设置它,但我怀疑HTML呈现代码没有省略的概念(文本溢出是HTML5ish特性),所以您必须想出如何教它这样做。我怀疑这将是非常困难的,而且比仅仅编写自己的TableCellRenderer要困难得多。

票数 1
EN

Stack Overflow用户

发布于 2020-05-27 20:24:37

下面是SimpleHTMLJLabel的修改版本,它使用上面的代码

代码语言:javascript
运行
复制
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中使用我的代码时,需要在构造函数时间内立即调整大小,但是当您没有列的大小时:

代码语言:javascript
运行
复制
    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中

代码语言:javascript
运行
复制
    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。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31141803

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档