Java 如何突出显示JLabel的一部分?

Java 如何突出显示JLabel的一部分?,java,swing,jtable,jlabel,Java,Swing,Jtable,Jlabel,在任何人建议使用HTML之前,我会在后面解释为什么这不是一个选项。我有一个表,其中包含一列,其中包含文本单元格。我需要能够突出显示每个单元格中的一些文本。例如,如果细胞中含有“猫-福-狗”。。。我可能想强调foo 我目前的方法是使用一个定制的TableCellRenderer,它将html放入一个JLabel组件中进行渲染,并且在一段时间内效果良好。然后我注意到,当单元格中的文本变得太长,无法容纳列宽时,它只是截断了文本,而没有正常的“…”在本例中通常会发生这种情况。因此,用户不知道还有更多他们

在任何人建议使用HTML之前,我会在后面解释为什么这不是一个选项。我有一个表,其中包含一列,其中包含文本单元格。我需要能够突出显示每个单元格中的一些文本。例如,如果细胞中含有“猫-福-狗”。。。我可能想强调foo

我目前的方法是使用一个定制的TableCellRenderer,它将html放入一个JLabel组件中进行渲染,并且在一段时间内效果良好。然后我注意到,当单元格中的文本变得太长,无法容纳列宽时,它只是截断了文本,而没有正常的“…”在本例中通常会发生这种情况。因此,用户不知道还有更多他们看不到的文本。另一个问题是,如果原始文本本身包含HTML(在我的例子中,它有时包含HTML),单元格将无法正确呈现。我知道我可以逃避html,但我仍然有前面的问题


如果使用jlabel以外的组件,则会使表的单元格看起来很奇怪。有人有什么建议吗?谢谢

好吧,这里有一个解决方案

简而言之,您可以使用子类
JLabel
手动绘制高亮显示。覆盖
paintComponent
方法以进行实际绘制,并用于计算高亮显示区域应绘制的位置

这是一个极其详细的答案:

基本上,您可以创建一个子类
JLabel
,它可以突出显示内容。我会这样做;您可能希望做一些不同的事情:

添加告诉标签要高亮显示哪个零件的方法。假设您只需要一个突出显示的区域,则可能是这样的:

public void highlightRegion(int start, int end) {
     // Set some field to tell you where the highlight starts and ends...
}
如果需要多个区域,只需使用ArrayList而不是简单的字段。一种去亮度的方法也可能有用

现在,您需要覆盖
JLabel
paintComponent
方法。在这里,您需要执行几个离散的步骤,您可能希望以不同的方法或其他方式组织这些步骤。为了简单起见,我将把它全部放在绘画方法中

@Override
protected void paintComponent(Graphics g) {
  ...
首先,您需要计算高亮显示的物理尺寸,这可以使用nice
FontMetrics
类来完成。为正在使用的
Font
创建
FontMetrics

  FontMetrics metrics = new FontMetrics(getFont());
现在,您可以获得创建将成为高亮显示的矩形所需的所有信息。您需要起始位置、高度和宽度。要实现这一点,您需要
JLabel
文本的两个子字符串,如下所示:

  String start = getText().substring(0, startOfHighlight);
  String text = getText().substring(startOfHighlight, endOfHighlight);
  //You may also need to account for some offsets here:
  int startX = metrics.stringWidth(start);
  int startY = 0; //You probably have some vertical offset to add here.
  int length = metrics.stringWidth(text);
  int height = metrics.getHeight();
现在,可以在绘制标签的其余部分之前绘制高亮显示的区域:

  g.fillRect(startX, startY, length, height);
  super.paintComponent(g);
}
当然,如果希望高亮显示跨越多行,则需要进行更多的工作


如果你想知道,我以前确实写过这样的东西。一时兴起,我决定从
JPanel
编写自己的文本区域类型组件,这基本上就是我处理突出显示的方式。在实际项目中,重新发明轮子可能很愚蠢,但它确实会教给你一些可能有用的随机东西……

这是一个很好的答案,可能是最好的解决方案。但有些人可能会发现更简单的替代方法是使用JTextfield而不是JLabel进行渲染,然后可以使用JTextfields突出显示功能,即

void highlightWhitespaceText(JTextField text)
    {
        text.setHighlighter(AbstractTableCellRenderer.defaultHighlighter);
        try
        {
            Matcher m = AbstractTableCellRenderer.whitespaceStartPattern.matcher(text.getText());
            if (m.matches())
            {
                text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter);
            }
            m = AbstractTableCellRenderer.whitespaceEndPattern.matcher(text.getText());
            if (m.matches())
            {
                text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter);
            }
        }
        catch (BadLocationException ble)
        {
            //
        }
    }

您可以更改JTextfield的属性,使其在其他方面看起来像jLabel。

忍不住要将SwingX渲染器装饰机制扔进环中:其解决需求的方法是实现高亮显示。事实上,它已经完成了(虽然还没有正式支持),但隐藏在SwingLabs Demos项目中,命名为(您需要两者),并且最近已修复,用于处理图标、RToL组件方向、对齐和省略号

哇,谢谢你的回复。这对JLabels几乎是完美的。然而,我遇到了一个问题。如果在我的情况下标签设置为不透明(true),则会导致高亮显示不显示。我认为,这是在完成自定义绘图后调用super.paintComponent(g)造成的。我试着先做高亮显示的自定义绘制,然后高亮显示的矩形绘制在要高亮显示的文本上。这是一个很长的故事,但要在我的例子中显示表条带和其他一些东西,如行高亮显示,我必须将标签设置为不透明。感谢您的回复。首先尝试调用
super.paintComponent(g)
,然后使用
g.setColor
将颜色设置为部分透明的颜色(例如
新颜色(0x33、0x66、0xFF、0x66)
是一种漂亮的蓝色)在调用
fillRect
之前,我最终基本上重新实现了我自己的绘制组件方法,使之符合我的目的。并放弃调用父绘制组件方法。你的回答是一个非常好的解决方案,非常擅长回答这篇文章的标题,尽管与jlabel有关,所以我会将其标记为已接受。谢谢你,提康。