Tk Source Code

View Ticket
Login
Ticket UUID: 737abf45230d38c450c031d1c89ea84811d54e3e
Title: text widget has terrible performance with image create
Type: Bug Version: 8.6.6
Submitter: anonymous Created on: 2024-01-06 02:00:14
Subsystem: 18. [text] Assigned To: fvogel
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2024-01-12 20:26:08
Resolution: Fixed Closed By: fvogel
    Closed on: 2024-01-12 20:26:08
Description:
I've been writing an application that uses text widgets to list all files and directories in any given directory (a file manager) and I need to insert one icon per line. I am only working with two icons so far: files and directories. Some of my directories are large, one of them has 12,000 entries and the performance with the text widgets gets very bad past 1,500 to 2,000 lines.

It's interesting to note that the performance is stellar with buttons in place of text. Inserting 12,000 buttons in a text widget is nearly instantaneous. But only if I never specify a font for the buttons. If I do specify any font, the performance gets about 70x slower.

Here is some example code:

------------------------
package require Tk
image create photo IMAGE -file /usr/share/icons/hicolor/32x32/apps/elk.png

pack [text .t]
focus .t
bind .t	<Escape>	{exit 0}
update

set HowMany 12000

proc RunTextMode {} {
	for {set i 1} {$i <= $::HowMany} {incr i} {
		.t insert end "line $i: "
		.t image create end -image IMAGE
		.t insert end " :$i\n"
		.t see end
	}
}
proc RunButtonMode {} {
	for {set x 1} {$x <= $::HowMany} {incr x} {
		button .t.b$x -text "button $x" -width 160 -image IMAGE -compound left
		#button .t.b$x -font {Freesans 12} -text "button $x" -width 160 -image IMAGE -compound left
		pack .t.b$x
		.t window create end -window .t.b$x
		.t insert end "\n"
	}
}

set begin [clock milliseconds]
#Uncomment and run one of these
#RunTextMode
RunButtonMode
update
set end [clock milliseconds]

puts "[expr {$end - $begin}] ms"
focus .t
------------------------
User Comments: fvogel added on 2024-01-12 20:26:08:
Merged.

fvogel added on 2024-01-11 07:26:14:

I have now committed a modified implementation inspired by the revised text widget and a proposal made in the duplicate ticket [56970b5e7c], see [17cf80d8c4].


fvogel added on 2024-01-09 22:09:19:

[56970b5e7c] is a duplicate of this.


fvogel added on 2024-01-09 21:51:18:

The time is spent in EmbImageConfigure() in the for loop scanning the pre-existing names to get the largest #nn number per image name. The instruction spending the time is the sscanf here.

I have proposed a fix, see [55c3b394]. The new approach is enormously quicker: instead of scanning each existing name, one maintains an image count in the shared structure of the text widget. With the attached script, performance improves ~30 times (I get ~7500 ms without the fix, and ~250 ms with the fix).

Note that this fix changes the numbers numbering the images used in the text widget but this is compatible with the documentation in text.n (see section "Embedded images". Test case adapted in [511c7ddd].

Finally, note that the revised text does not have this problem, and already implements an approach with a common counter for all images (i.e. the counter is not specific of an image name).


Attachments: