Prev: get highlighted text
Next: Keybinding hell.
From: eb303 on 10 Feb 2010 10:32 Hello all, I've been trying to do a text editor showing line numbers on the left side of a text, which can also set the initial position of the insertion point. To do this, I pack 2 texts side by side, one for the line numbers and one for the actual text, and configure them to scroll together whenever one of them is scrolling. To see the initial cursor position, I use the 'see' subcommand on the text, but it seems something's wrong, since it doesn't seem to work. Here is a simplified script demonstrating the problem: ----------------- ## Frame for both texts pack [frame .texts] -side top ## Text for line numbers text .texts.lines -width 5 pack .texts.lines -side left -fill y ## Text for actual text text .texts.txt pack .texts.txt -side left -fill both ## Vertical scrollbar scrollbar .texts.vscroll -orient vertical -command { .texts.txt yview } ## Trick to make both texts scroll together, as well as update the scrollbar proc scroll_text { first last } { .texts.vscroll set $first $last .texts.lines yview moveto $first } proc scroll_lines { first last } { .texts.vscroll set $first $last .texts.txt yview moveto $first } ..texts.txt configure -yscrollcommand scroll_text ..texts.lines configure -yscrollcommand scroll_lines ## Fill text and line numbers with dummy lines for { set i 1 } { $i <= 2000 } { incr i } { .texts.lines insert end "$i\n" .texts.txt insert end "This is line number $i\n" } ## Procedure to center the text on a given line and set the insertion point on it proc center_text {} { .texts.txt see 789.0 .texts.txt mark set insert 789.0 } ## Initial positionning <= does not work center_text ## Button to do positionning again <= works button .btn -text Center -command center_text pack .btn focus .texts.txt ----------------- The initial call to center_text doesn't work: the insertion point is actually moved, but the line is not centered in the text. However, after the initial display, clicking on the 'Center' button works: the insertion point moves, and the line is centered. I've tried various tricks to make this work, like calls to 'update' or 'update idletasks' before calling center_text, or triggering it later via an 'after idle', but with no result: I can't get the line to be centered on display. Do I do anything wrong here? Is it the trick I used to scroll both texts at the same time that messes things up? My tcl version is 8.5.5; I've tried this on Linux (Fedora Core 10) and Mac OS X 10.5, and the result is the same. Thanks. - Eric -
From: eb303 on 10 Feb 2010 11:27 On Feb 10, 4:32 pm, eb303 <eric.brunel.pragma...(a)gmail.com> wrote: > Hello all, > > I've been trying to do a text editor showing line numbers on the left > side of a text, which can also set the initial position of the > insertion point. To do this, I pack 2 texts side by side, one for the > line numbers and one for the actual text, and configure them to scroll > together whenever one of them is scrolling. To see the initial cursor > position, I use the 'see' subcommand on the text, but it seems > something's wrong, since it doesn't seem to work. > > Here is a simplified script demonstrating the problem: > ----------------- > ## Frame for both texts > pack [frame .texts] -side top > ## Text for line numbers > text .texts.lines -width 5 > pack .texts.lines -side left -fill y > ## Text for actual text > text .texts.txt > pack .texts.txt -side left -fill both > > ## Vertical scrollbar > scrollbar .texts.vscroll -orient vertical -command { .texts.txt > yview } > > ## Trick to make both texts scroll together, as well as update the > scrollbar > proc scroll_text { first last } { > .texts.vscroll set $first $last > .texts.lines yview moveto $first} > > proc scroll_lines { first last } { > .texts.vscroll set $first $last > .texts.txt yview moveto $first} > > .texts.txt configure -yscrollcommand scroll_text > .texts.lines configure -yscrollcommand scroll_lines > > ## Fill text and line numbers with dummy lines > for { set i 1 } { $i <= 2000 } { incr i } { > .texts.lines insert end "$i\n" > .texts.txt insert end "This is line number $i\n" > > } > > ## Procedure to center the text on a given line and set the insertion > point on it > proc center_text {} { > .texts.txt see 789.0 > .texts.txt mark set insert 789.0 > > } > > ## Initial positionning <= does not work > center_text > > ## Button to do positionning again <= works > button .btn -text Center -command center_text > pack .btn > > focus .texts.txt > ----------------- > > The initial call to center_text doesn't work: the insertion point is > actually moved, but the line is not centered in the text. However, > after the initial display, clicking on the 'Center' button works: the > insertion point moves, and the line is centered. > > I've tried various tricks to make this work, like calls to 'update' or > 'update idletasks' before calling center_text, or triggering it later > via an 'after idle', but with no result: I can't get the line to be > centered on display. > > Do I do anything wrong here? Is it the trick I used to scroll both > texts at the same time that messes things up? > > My tcl version is 8.5.5; I've tried this on Linux (Fedora Core 10) and > Mac OS X 10.5, and the result is the same. > > Thanks. > - Eric - Replying to myself: my problem seems to be related to bug 1739605 (http://sourceforge.net/tracker/? func=detail&aid=1739605&group_id=12997&atid=112997), except in my case, 'update idletasks' does not seem to make things work. I tried everything I could think of ('after idle', 'tkwait visibility', posting custom events and doing the 'see' when they are received and combinations of all of the above), but I only succeeded in making it work with an 'after <delay>'. The problem now is that the delay seems to depend on the number of lines I display: the more lines there is, the bigger the delay must be. Quite unsatisfactory...
From: Alexandre Ferrieux on 10 Feb 2010 12:02 On Feb 10, 5:27 pm, eb303 <eric.brunel.pragma...(a)gmail.com> wrote: > On Feb 10, 4:32 pm, eb303 <eric.brunel.pragma...(a)gmail.com> wrote: > > > > > > > Hello all, > > > I've been trying to do a text editor showing line numbers on the left > > side of a text, which can also set the initial position of the > > insertion point. To do this, I pack 2 texts side by side, one for the > > line numbers and one for the actual text, and configure them to scroll > > together whenever one of them is scrolling. To see the initial cursor > > position, I use the 'see' subcommand on the text, but it seems > > something's wrong, since it doesn't seem to work. > > > Here is a simplified script demonstrating the problem: > > ----------------- > > ## Frame for both texts > > pack [frame .texts] -side top > > ## Text for line numbers > > text .texts.lines -width 5 > > pack .texts.lines -side left -fill y > > ## Text for actual text > > text .texts.txt > > pack .texts.txt -side left -fill both > > > ## Vertical scrollbar > > scrollbar .texts.vscroll -orient vertical -command { .texts.txt > > yview } > > > ## Trick to make both texts scroll together, as well as update the > > scrollbar > > proc scroll_text { first last } { > > .texts.vscroll set $first $last > > .texts.lines yview moveto $first} > > > proc scroll_lines { first last } { > > .texts.vscroll set $first $last > > .texts.txt yview moveto $first} > > > .texts.txt configure -yscrollcommand scroll_text > > .texts.lines configure -yscrollcommand scroll_lines > > > ## Fill text and line numbers with dummy lines > > for { set i 1 } { $i <= 2000 } { incr i } { > > .texts.lines insert end "$i\n" > > .texts.txt insert end "This is line number $i\n" > > > } > > > ## Procedure to center the text on a given line and set the insertion > > point on it > > proc center_text {} { > > .texts.txt see 789.0 > > .texts.txt mark set insert 789.0 > > > } > > > ## Initial positionning <= does not work > > center_text > > > ## Button to do positionning again <= works > > button .btn -text Center -command center_text > > pack .btn > > > focus .texts.txt > > ----------------- > > > The initial call to center_text doesn't work: the insertion point is > > actually moved, but the line is not centered in the text. However, > > after the initial display, clicking on the 'Center' button works: the > > insertion point moves, and the line is centered. > > > I've tried various tricks to make this work, like calls to 'update' or > > 'update idletasks' before calling center_text, or triggering it later > > via an 'after idle', but with no result: I can't get the line to be > > centered on display. > > > Do I do anything wrong here? Is it the trick I used to scroll both > > texts at the same time that messes things up? > > > My tcl version is 8.5.5; I've tried this on Linux (Fedora Core 10) and > > Mac OS X 10.5, and the result is the same. > > > Thanks. > > - Eric - > > Replying to myself: my problem seems to be related to bug 1739605 > (http://sourceforge.net/tracker/? > func=detail&aid=1739605&group_id=12997&atid=112997), except in my > case, 'update idletasks' does not seem to make things work. I tried > everything I could think of ('after idle', 'tkwait visibility', > posting custom events and doing the 'see' when they are received and > combinations of all of the above), but I only succeeded in making it > work with an 'after <delay>'. The problem now is that the delay seems > to depend on the number of lines I display: the more lines there is, > the bigger the delay must be. Quite unsatisfactory... Indeed ! The problem is that idle tasks in Tk do some real work, and we lack a "after really_idle"... Even calling center_text from within a <Configure> binding (which is called many times) doesn't seem to help. Sigh. Please report a fresh bug. If it is the same as an older one, at least that isn't obvious. No shame in marking it as duplicate afterwards ;-) -Alex
From: Peter Spjuth on 10 Feb 2010 18:04 On Feb 10, 4:32 pm, eb303 <eric.brunel.pragma...(a)gmail.com> wrote: > I've been trying to do a text editor showing line numbers on the left > side of a text, which can also set the initial position of the > insertion point. To do this, I pack 2 texts side by side, one for the > line numbers and one for the actual text, and configure them to scroll > together whenever one of them is scrolling. To see the initial cursor > position, I use the 'see' subcommand on the text, but it seems > something's wrong, since it doesn't seem to work. The text widget will do some background calculations that need to settle before the "see" command can do its job. Those are not idle tasks, so update will not help there. It can be considered a bug that "see" does not force those calculations but that's another issue. Let's focus on a workaround. First, the text widget has wrapping on by default which means the calculations become dependent on the widget's geometry. Add "-wrap none" to the text widget to get past that. I'm not sure it helps much with the issue, but you probably want that anyway when you try to keep the texts scrolled in sync. Second, you need to force the background calculations to happen. The only command I know that does that is count -ypixels: proc center_text {} { .texts.txt count -update -ypixels 1.0 end .texts.lines count -update -ypixels 1.0 end .texts.txt see 789.0 .texts.txt mark set insert 789.0 } Third, give events and misc updates a chance to happen: tkwait visibility .texts after idle after 5 center_text With that I got it to work. /Peter
From: eb303 on 11 Feb 2010 03:52
On Feb 11, 12:04 am, Peter Spjuth <peter.spj...(a)gmail.com> wrote: > On Feb 10, 4:32 pm, eb303 <eric.brunel.pragma...(a)gmail.com> wrote: > > > I've been trying to do a text editor showing line numbers on the left > > side of a text, which can also set the initial position of the > > insertion point. To do this, I pack 2 texts side by side, one for the > > line numbers and one for the actual text, and configure them to scroll > > together whenever one of them is scrolling. To see the initial cursor > > position, I use the 'see' subcommand on the text, but it seems > > something's wrong, since it doesn't seem to work. > > The text widget will do some background calculations that > need to settle before the "see" command can do its job. > Those are not idle tasks, so update will not help there. > It can be considered a bug that "see" does not force those > calculations but that's another issue. Let's focus on a > workaround. > > First, the text widget has wrapping on by default which means > the calculations become dependent on the widget's geometry. > Add "-wrap none" to the text widget to get past that. I'm not sure > it helps much with the issue, but you probably want that anyway > when you try to keep the texts scrolled in sync. > > Second, you need to force the background calculations to happen. > The only command I know that does that is count -ypixels: > proc center_text {} { > .texts.txt count -update -ypixels 1.0 end > .texts.lines count -update -ypixels 1.0 end > .texts.txt see 789.0 > .texts.txt mark set insert 789.0 > > } > > Third, give events and misc updates a chance to happen: > tkwait visibility .texts > after idle after 5 center_text > > With that I got it to work. > > /Peter Thanks a lot Peter, it's working. And 'after 5' seems to work whatever number of lines are in the text, so that's great (I usually don't really like relying on after, but it seems OK here). |