突出显示画布中的部分文本项

时间:2018-04-18 13:10:55

标签: canvas tcl tk

我想用一些文本项填充画布小部件并突出显示这些文本的部分内容(想想在画布的所有文本项中突出显示搜索短语)。

当然,可以将单个文本拆分为突出显示和非突出显示的部分,并为这些部分添加单独的文本项,例如

#!/usr/bin/env wish

proc _drawText {canvas x y text highlighted} {
    if {$text != {}} {
        set cmd [list $canvas create text $x $y -anchor nw -text $text]
        if {$highlighted == "1"} {
            lappend cmd -fill red
        }
        set t [{*}$cmd]
        # advance x to the bbox' right side
        set x [lindex [$canvas bbox $t] 2]
        # adjust x, because the bbox seems to be 1 pixel too wide :(
        incr x -1
    }
    return $x
}

proc addText {canvas x y text {highlightedChars {}}} {
    set highlighted "0"
    set chars ""
    foreach c [split $text {}] h [split $highlightedChars {}] {
        if {$h != $highlighted} {           
            set x [_drawText $canvas $x $y $chars $highlighted]
            set highlighted $h
            set chars ""
        }
        append chars $c
    }
    _drawText $canvas $x $y $chars $highlighted
}

canvas .c
pack .c -expand 1 -fill both

# add "some example text" and highlight the two occurrences of "ex"
addText .c 0 0 \
    "some example text" \
    "00000110000000110"

这是一种非常有限的方法( - >仅适用于nw锚定文本,必须手动执行换行等等),所以我想知道是否有更好的方法可以做那。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

首先,文本窗口小部件可能更适合您所描述的问题 ,因为它支持更复杂的文本标记。画布仅支持单个项目的单个选定范围,听起来它们不会为您正在进行的更复杂的事情提供大量支持。画布对于文本小部件同样复杂,但是将其复杂性集中在其他地方;要对它们进行复杂的文本显示,你必须做相当多的脚本编写。

但是,您可以相当容易地找出文本的位置。首先,(只要文本没有旋转),您可以忽略锚点和锚定控件,只使用整个边界框。其次,要处理多行文本,你需要知道对齐规则,但实际上只是说如何将每一行水平放置在边界框的子部分中。

第三,由于画布文本项目只有一种字体,因此您可以在font measurefont metrics的帮助下轻松完成文本计算。使用font measure命令可以确定文本在特定字体中的宽度,而不在屏幕上显示(如果文本中没有换行符)。 font metrics命令可让您找出-linespace对字体的影响,即行之间应有多少空间,以及-ascent-descent是什么(线的顶部和底部相对于文本的基线)。这些命令调用与Tk用于实际显示文本的完全相同的字体引擎;您不需要对您正在使用的字体的大小和形状进行硬编码。

令人惊讶的是,没有简单的机制将项目索引转换为画布坐标对。