简体   繁体   English

JTable 单元格中的着色文本

[英]Coloring Text in JTable Cell

I want to color text in a JTable cell.我想为 JTable 单元格中的文本着色。 I'm using a DefaultTableCellRender with HTML Tags to color multible words/text.我正在使用带有 HTML 标签的DefaultTableCellRender来为多个单词/文本着色。 I'm using Regex to find words/text and replacing them by adding HTML Tags.我正在使用正则表达式来查找单词/文本并通过添加 HTML 标签来替换它们。

The problem here is that the HTML tags them selves should not match by the regex.这里的问题是他们自己的 HTML 标签不应该被正则表达式匹配。

example:例子:

Text:文本:

This is a example text background

text to color "a example":为“示例”着色的文本:

This is <font color="FFFFFF" style="background-color: #FFAABB">a example</font> 
text background

next word to color "back":为“back”着色的下一个单词:

This is <font color="FFFFFF" style="background-color: #FFAABB">a example</font> 
text <font color="FFFFFF" style="background-color: #AAAAAA">back</font>ground

the "back" in the HTML tag should not be replaced. HTML 标签中的“back”不应被替换。 Is there a way to exclude this by the Regex?有没有办法通过正则表达式排除这个?

code:代码:

private String color(String val, ArrayList<ColorKeyWord> list) {
        for(ColorKeyWord ckw: list){
            val = val.replaceAll(ckw.getKeyWord(), "<font color=\"" + DecodedDataHTMLTags.color_white + "\" " +"style=\"background-color: #" + ckw.getColor() + "\">" + ckw.getKeyWord() + "</font>");
        }
        return val;
    }

I think a simpler solution would be to us StyledLabel from jidesoft and use StyleRange .我认为,一个简单的解决办法是我们StyledLabel从jidesoft和使用StyleRange But the StyledTableCellRenderer is not included in the free library.但是StyledTableCellRenderer不包含在免费库中。 I'm also using JTable because i need variable cell height.我也在使用JTable因为我需要可变的单元格高度。 This can not be achieved with swt tables.这是使用 swt 表无法实现的。

You need to use more complex regular expression pattern for replacing (and ignoring keywords inside html tags).您需要使用更复杂的正则表达式模式进行替换(并忽略html标签内的关键字)。 The 'quick and dirty' solution: “快速而肮脏”的解决方案:

private static String color(String val, String keyword) {
    String pattern = "[^>].*(" + keyword + ").*[^<]";

    Pattern r = Pattern.compile(pattern);
    Matcher m = r.matcher(val);
    if (m.find()) {
        int startIndex = m.start(1);
        int endIndex = m.end(1);
        String withReplacedKeyword = val.substring(0, startIndex)
                + "<font color=\"FFFFFF\" style=\"background-color: #FFAABB\">"
                + keyword + "</font>" + val.substring(endIndex);
        return withReplacedKeyword;
    }       
    return val;

}

public static void main(String[] args) {
    System.out.println(color("This is a example text background", "back"));
    System.out.println(color("This is a example text <font color=\"FFFFFF\" style=\"background-color: #FFAABB\">back</font>ground", "back"));
    System.out.println(color("This is a example text <font color=\"FFFFFF\" style=\"background-color: #FFAABB\">back</font>ground", "is")); 
}

Thus the 1st replacement:因此,第一次更换:

This is a example text 
<font color="FFFFFF" style="background-color: #FFAABB">
    back
</font>
ground

And the 2nd looks like nested tags (will not broke GUI components):第二个看起来像嵌套标签(不会破坏 GUI 组件):

This is a example text 
<font color="FFFFFF" style="background-color: #FFAABB">
    <font color="FFFFFF" style="background-color: #FFAABB">
        back
    </font>
</font>
ground

The only drawback is that some corner cases (like replacing at the beginning of the original string) can require additional logic.唯一的缺点是某些极端情况(例如在原始字符串的开头替换)可能需要额外的逻辑。 And composing universal regex pattern for all these cases can be laborious.为所有这些情况编写通用正则表达式模式可能很费力。

There's probably a better way, but basically, what this does it sets up a series of optional groups which allows a Pattern and Matcher to break the String down into "ranges"可能有更好的方法,但基本上,它的作用是设置一系列可选组,允许PatternMatcherString分解为“范围”

We then use those ranges to "inject" the rules...然后我们使用这些范围来“注入”规则......

String text = "This is a example text background and bunnies are red";
Pattern p = Pattern.compile("(example text)|(back)|(bunnies)|(red)", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(text);

List<MatchRange> ranges = new ArrayList<>(25);
while (m.find()) {
    ranges.add(new MatchRange(m.start(), m.end()));
}

StringBuilder sb = new StringBuilder(64);
sb.append("<html>");
int anchor = 0;
for (MatchRange range : ranges) {
    String before = "";
    if (anchor < range.getStart()) {
        before = text.substring(anchor, range.getStart());
    }
    sb.append(before);
    System.out.println(range.getStart() + " - " + range.getEnd());
    String match = text.substring(range.getStart(), range.getEnd());
    // This is where I would have a rule formatter
    if (match.equals("example text")) {
        sb.append("<font color=\"FFFFFF\" style=\"background-color: #FFAABB\">");
        sb.append(match);
        sb.append("</font>");
    } else if (match.equals("back")) {
        sb.append("<font color=\"FFFFFF\" style=\"background-color: #AAAAAA\">");
        sb.append(match);
        sb.append("</font>");
    } else if (match.equals("bunnies")) {
        sb.append("<font color=\"FF0000\" style=\"background-color: #FFFFFF\">");
        sb.append(match);
        sb.append("</font>");
    } else if (match.equals("red")) {
        sb.append("<font color=\"FF0000\" style=\"background-color: #000000\">");
        sb.append(match);
        sb.append("</font>");
    } else {
        sb.append(match);
    }
    anchor = range.getEnd();
}

System.out.println(sb.toString());

And the MatchRange ...MatchRange ...

public class MatchRange {
    private final int start;
    private final int end;

    public MatchRange(int start, int end) {
        this.start = start;
        this.end = end;
    }

    public int getEnd() {
        return end;
    }

    public int getStart() {
        return start;
    }

}

And this basically outputs这基本上输出

<html>This is a <font color="FFFFFF" style="background-color: #FFAABB">example text</font> <font color="FFFFFF" style="background-color: #AAAAAA">back</font>ground and <font color="FF0000" style="background-color: #FFFFFF">bunnies</font> are <font color="FF0000" style="background-color: #000000">red</font>

I added some additional conditions for testing.我添加了一些额外的测试条件。

What I would do, is create a class which could carry a condition ( "example text" ) and which could format the value (wrapping the HTML around it for example) and simply iterate over these to create the expression and apply the format我要做的是创建一个类,它可以携带一个条件( "example text" )并且可以格式化值(例如将 HTML 包裹在它周围)并简单地迭代这些以创建表达式并应用格式

Maybe something like...也许像...

public interface ConditionFormatter {
    public String getCondition();
    public String applyFormatTo(String text);
    public boolean matches(String text);
}

public class DefaultConditionFormatter implements ConditionFormatter {

    private final String condition;
    private final String preFormat;
    private final String postFormat;

    public DefaultConditionFormatter(String condition, String preFormat, String postFormat) {
        this.condition = condition;
        this.preFormat = preFormat;
        this.postFormat = postFormat;
    }

    @Override
    public String getCondition() {
        return condition;
    }

    @Override
    public String applyFormatTo(String text) {
        return new StringBuilder(preFormat).append(text).append(postFormat).toString();
    }

    @Override
    public boolean matches(String text) {
        return condition.equalsIgnoreCase(text);
    }

}

Which contains the "condition" or "rule" and the format to apply.其中包含“条件”或“规则”以及要应用的格式。 Normally, I might be tempted to separate the "rule" and the "formatter", but I think you can get the basic idea...通常,我可能很想将“规则”和“格式化程序”分开,但我认为您可以了解基本思想......

Then you could do something like...然后你可以做一些像......

List<ConditionFormatter> formatters = new ArrayList<>(25);
formatters.add(new DefaultConditionFormatter("example text", "<font color=\"FFFFFF\" style=\"background-color: #FFAABB\">", "</font>"));
formatters.add(new DefaultConditionFormatter("back", "<font color=\"FFFFFF\" style=\"background-color: #AAAAAA\">", "</font>"));
formatters.add(new DefaultConditionFormatter("bunnies", "<font color=\"FF0000\" style=\"background-color: #FFFFFF\">", "</font>"));
formatters.add(new DefaultConditionFormatter("red", "<font color=\"FF0000\" style=\"background-color: #000000\">", "</font>"));

String text = "This is a example text background and bunnies are red";
StringJoiner sj = new StringJoiner(")|(", "(", ")");
for (ConditionFormatter formatter : formatters) {
    sj.add(formatter.getCondition());
}

Pattern p = Pattern.compile(sj.toString(), Pattern.CASE_INSENSITIVE);
//...

And...和...

for (MatchRange range : ranges) {
    //...
    // This is where I would have a rule formatter
    String match = text.substring(range.getStart(), range.getEnd());
    for (ConditionFormatter formatter : formatters) {
        if (formatter.matches(match)) {
            sb.append(formatter.applyFormatTo(match));
            break;
        }
    }
    //...
}

Try setColor(BLACK);试试 setColor(BLACK); on the onject.在对象上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM