Mkn
Mkn

Reputation: 648

ttk::label multiline formatting

I would like to display my lines like this :

Nombre de seq(s)     = 10
Nombre de page(s)    = 12
Fichier word         = c:/temp/word.docx
Fichier simulation   = c:/temp/word.tmp

but in my label my lines are displayed like this

enter image description here

How can I make my lines alligned to the equal sign

Below my code :

package require Tk

lappend info [format "%-20s = %-1s" "Nombre de seq(s)" 10]
lappend info [format "%-20s = %-1s" "Nombre de page(s)" 1]
lappend info [format "%-20s = %-1s" "Fichier word" {c:/temp/word.docx}]
lappend info [format "%-20s = %-1s" "Fichier simulation" {c:/temp/word.tmp}]

grid [ttk::label .l -text [join $info "\n"]] -row 0 -column 0 -padx 2 -pady 2 -sticky nw 

Upvotes: 0

Views: 335

Answers (2)

Donal Fellows
Donal Fellows

Reputation: 137707

The label widgets are not really designed for this sort of thing. You could use a fixed width font, or you could try inserting tabs:

pack [ttk::label .l -textvariable foo]

# Doing this directly rather than computing it
set foo "Nombre de seq(s)\t\t= 10
Nombre de page(s)\t= 12
Fichier word\t\t= c:/temp/word.docx
Fichier simulation\t\t= c:/temp/word.tmp"

Tabs are a bit tricky here because the disparity between line lengths is a bit too much for them to automatically hide.

The best alternative though is probably to use a read-only text widget, as that widget lets you have exact control over layout.

pack [text .t -font TkDefaultFont]

.t insert 1.0 "Nombre de seq(s)\t= 10
Nombre de page(s)\t= 12
Fichier word\t= c:/temp/word.docx
Fichier simulation\t= c:/temp/word.tmp"

.t configure -tabs [font measure TkDefaultFont "Nombre de page(s) "] -state disabled
# You MUST insert the text before disabling the widget.

(You'll need to experiment with how to get the overall widget width right. And with what colour to set the background to.)

Upvotes: 1

Schelte Bron
Schelte Bron

Reputation: 4813

The easiest method is to configure the label to use a fixed font.

If you want a proportional font, then you could split things up into 8 separate labels and put those in a grid.

To use a proportional font and only one label, you can play with the different with spaces available in unicode:

set data {
    "Nombre de seq(s)" 10
    "Nombre de page(s)" 12
    "Fichier word" "c:/temp/word.docx"
    "Fichier simulation" "c:/temp/word.tmp"
}

# Put the different size spaces in a dict
set spaces [dict create [font measure TkDefaultFont " "] " "]
for {set i 0x2000} {$i <= 0x200a} {incr i} {
    set s [format %c $i]
    dict set spaces [font measure TkDefaultFont $s] $s
}
# A 0-width space could cause an endless loop
dict unset spaces 0
# Sort the dict to be able to use a bisect lsearch
set spaces [lsort -integer -index 0 -stride 2 $spaces]

# Calculate the sizes of the lefthand terms and find the longest
set sizes [lmap n [dict keys $data] {font measure TkDefaultFont $n}]
set max [tcl::mathfunc::max {*}$sizes]

set txt [lmap s [dict keys $data] l $sizes {
    set v [dict get $data $s]
    # Keep adding the biggest space that will fit
    # until the string is the same length as the longest one
    while {$l < $max} {
        set w [expr {$max - $l}]
        set key [lsearch -inline -integer -bisect [dict keys $spaces] $w]
        append s [dict get $spaces $key]
        incr l $key
    }
    # Append the value
    append s " = " $v
}]

# Combine the lines and show them on a label
ttk::label .l -text [join $txt \n]
grid .l

Additional checks or a more intelligent algorithm may be needed if the font doesn't have any 1-pixel space.

Upvotes: 1

Related Questions