9

在任何人建议 HTML 之前,我稍后会解释为什么这不是一个选项。我有一个表,其中包含一个包含文本单元格的列。我需要能够突出显示每个单元格中的一些文本。因此,例如,如果单元格包含“cat foo dog”......我可能想突出显示 foo。

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

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

4

3 回答 3

9

好吧,这是一个解决方案。

简而言之,您可以子类JLabel化以手动绘制突出显示。覆盖该paintComponent方法以进行实际绘图并用于FontMetrics计算应在何处绘制突出显示的区域。

这是极其详细的答案:

基本上,您可以创建一个JLabel可以突出显示内容的子类。我会这样做;您可能想以不同的方式进行操作:

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

public void highlightRegion(int start, int end) {
     // Set some field to tell you where the highlight starts and ends...
}

如果您需要多个区域,只需一个 ArrayList 而不是一个简单的字段。一种取消突出显示的方法可能也很有用。

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

@Override
protected void paintComponent(Graphics g) {
  ...

首先,您需要确定高光的物理尺寸,您可以使用 niceFontMetrics类来完成。FontMetricsFont您正在使用的类创建类。

  FontMetrics metrics = new FontMetrics(getFont());

现在,您可以获得创建将成为突出显示的矩形所需的所有信息。您将需要起始位置、高度和宽度。为此,您需要JLabel's 文本的两个子字符串,如下所示:

  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);
}

当然,如果您希望突出显示跨越多行,那将需要更多的工作。

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

于 2010-08-21T08:55:25.487 回答
2

这是一个很好的答案,可能是最好的解决方案。但是有些人可能会发现更简单的替代方法是使用 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。

于 2010-10-27T13:58:02.860 回答
2

忍不住将 SwingX 渲染器装饰机制扔进了环:它解决需求的方法是实现一个 Highlighter 来做它。这实际上已经完成(尽管尚未得到官方支持),但隐藏在名为X/MatchingTextHighlighter的 SwingLabs-Demos 项目中(您将需要两者)并且最近修复了以应对图标、RToL-ComponentOrientation、对齐、省略号。 .

于 2011-10-27T08:02:06.767 回答