text widget must follow end of text only if associated scrollbar is at bottom 
Author Message
 text widget must follow end of text only if associated scrollbar is at bottom

I've created a text widget using Tcl/Tk 8.3.5 (can't use a different
version) with wrapping enabled.  The text widget has an associated
scrollbar.  Text gets continuously appended to the end.  I'd like to be
able have the text widget keep the last character appended within view
as long as the scroll bar is at the bottom.  If the scroll bar is not
at the bottom (e.g. the bottom of the text is not within view), then
the text widget would not change the visible text until the user
dragged the scrollbar to the bottom of the text (or the bottom of the
text became visible some other way).

I've tried doing the following for every character:
    set scroll_at_bottom \
            [expr { [lindex [.myscrollbar get] 1] == 1 }]
    .mytext insert end $nextchar
    if { $scroll_at_bottom } {
        .mytext see end
    }

The problem lies in the fact that when the text widget wraps a line,
the visible text is no longer at the bottom, so the next time a
character comes in, $scroll_at_bottom is false.

Any suggestions would be greatly appreciated.



Mon, 04 Feb 2008 04:00:43 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom

Quote:

> ...I'd like to be
> able have the text widget keep the last character appended within view
> as long as the scroll bar is at the bottom.  If the scroll bar is not
> at the bottom (e.g. the bottom of the text is not within view), then
> the text widget would not change the visible text until the user
> dragged the scrollbar to the bottom of the text (or the bottom of the
> text became visible some other way).

Try this:

   text .t -yscrollcommand [list .vsb set]
   scrollbar .vsb -orient vertical -command [list .t yview]
   pack .vsb -side left -fill y
   pack .t -side right -fill both -expand y

   proc addText {args} {
     set yview [.t yview]
     if {[lindex $yview 1] >= 1.0} {
       set scroll 1
     } else {
       set scroll 0
     }

     foreach {text tags} $args {
       .t insert end $text $tags
     }
     if {$scroll} {.t see end}
   }



Mon, 04 Feb 2008 04:19:19 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom
I'd also like to avoid doing the ".mytext see end" every time a new
character comes in (assuming the bottom of text is already in view),
since this is a lot of extra processing.  I only was to do the
".mytext.see end" when a line wraps or when an end of line occurs.  Is
there an easy way to determine if a line will wrap if a character gets
added to the end of the last line in the text widget?


Mon, 04 Feb 2008 04:23:15 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom

Quote:

> I'd also like to avoid doing the ".mytext see end" every time a new
> character comes in (assuming the bottom of text is already in view),
> since this is a lot of extra processing.

Why do you think it is a lot of extra processing?

On my laptop, a call to '.text see' takes all of about 250 usec when
scrolling is necessary, about 40 usec when no scrolling is necessary.

Doing an if statement to determine if you should call '.text see' will
probably take about that long so you aren't saving any cycles.

Quote:
> I only was to do the
> ".mytext.see end" when a line wraps or when an end of line occurs.  Is
> there an easy way to determine if a line will wrap if a character gets
> added to the end of the last line in the text widget?

There is probably not an easy way to determine if the text will wrap,
other than to implement the same algorithm that the text widget uses.
That is, you could get the bbox of the last character, determine the
width of the character(s) to be inserted, determine if the new
characters will extend the bbox beyond the margin, find the word
boundary (if word wrapping is on), etc.

*that* sounds like a lot of processing. I'm still a bit puzzled why you
think doing all that in tcl will be less processing than letting the
text widget do all that work in C using its internal knowledge of the
state of the widget.



Mon, 04 Feb 2008 05:00:15 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom

Quote:
> I'd also like to avoid doing the ".mytext see end" every time a new
> character comes in (assuming the bottom of text is already in view),
> since this is a lot of extra processing.  I only was to do the
> ".mytext.see end" when a line wraps or when an end of line occurs.  Is
> there an easy way to determine if a line will wrap if a character gets
> added to the end of the last line in the text widget?

You don't want to do this, as it requires either low-level hackery (to
make [text] generate virtual event <<Wrapped>>) or checking [yview] after
insertion, that is pretty much as fast operation as [see end] would be.

Just [see end] and optimize something more CPU intensive.

--
-Kaitzschu
s="TCL ";while true;do echo -en "\r$s";s=${s:1:${#s}}${s:0:1};sleep .1;done



Mon, 04 Feb 2008 05:05:28 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom
The reason I asked for help was that wish uses more than 90% of my CPU
when my application is getting continuous data.  If I take out the
".text see" and ".myscrollbar get", the amount of CPU wish takes is
very small.  In order to make my application less of a hog, I've had to
turn off wrapping so that I only need to call ".text see" after I
insert a newline character.

I'm wondering if the following might work:

   proc addChar {char} {
     set yview [.t yview]
     if {[lindex $yview 1] >= 1.0} {
       set scroll 1
     } else {
       set scroll 0
     }

       .t insert end $char
       # only "see" end if we were previously
       # at the bottom, but we aren't now
       set yview [.t yview]
       if {$scroll && [lindex $yview 1] < 1.0} {
           .t see end
       }
   }



Mon, 04 Feb 2008 05:40:12 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom

Quote:

> The reason I asked for help was that wish uses more than 90% of my CPU
> when my application is getting continuous data.  If I take out the
> ".text see" and ".myscrollbar get", the amount of CPU wish takes is
> very small.  In order to make my application less of a hog, I've had to
> turn off wrapping so that I only need to call ".text see" after I
> insert a newline character.

> I'm wondering if the following might work:
> [snip]

Only you can tell us... :-)

How are you reading data? one byte at a time? Is it possible to read a
line at a time instead?



Mon, 04 Feb 2008 06:20:57 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom
I'm reading the date a character at a time from a 115200 serial
connection.  I can't read a line at a time because there are times
where the data for a single line comes in very slowly (e.g. a character
based progress bar), and the user needs to see the characters as they
arrive.
I tried running using the addChar function from above, and when the
data is pouring in, my CPU still goes up above 90% (on an Intel P4 2.8
GHz with Linux).  As an experiment, I tried just doing a .text yview on
every incoming character (no ".text see"), and the CPU was still above
90%.  The only way my CPU isn't struggling is when I remove both the
".text see" and ".text yview", so I think I'm out of luck until there's
a "-stayatendwhenatbottom" option for the text widget.


Mon, 04 Feb 2008 06:32:33 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom

Quote:

> I tried running using the addChar function from above, and when the
> data is pouring in, my CPU still goes up above 90% (on an Intel P4 2.8
> GHz with Linux).  As an experiment, I tried just doing a .text yview on
> every incoming character (no ".text see"), and the CPU was still above
> 90%.  

So, do we assume it's the yview command that is causing grief? There are
other ways to skin that cat. For instance, change the scrollbar command
to call a proc, and have it set a global flag when it scrolls to the
bottom. Then, just check the global flag rather than calling yview all
the time.

Another solution might be to only do the see/yview command every Nth
character and each time a \n is received. I agree that doing yview/see
on every byte is a bit much.



Mon, 04 Feb 2008 07:06:04 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom
     If I had a global flag set by a scrollbar change, I'd still need
to check the text widget's yview after I inserted the character to see
if the line wrapped and I need to "see end"
     If I do the see/yview command every Nth character, but the (N-1)th
character caused the line to wrap, then when I got to the Nth
character, my yview would no longer be at the bottom.

I still think I'm out of luck.



Mon, 04 Feb 2008 07:56:34 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom
In case I didn't make it clear, if I call either the yview or see on
every character, the CPU chokes.


Mon, 04 Feb 2008 08:00:11 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom

Quote:

> The reason I asked for help was that wish uses more than 90% of my CPU
> when my application is getting continuous data.  If I take out the
> ".text see" and ".myscrollbar get", the amount of CPU wish takes is
> very small.  In order to make my application less of a hog, I've had to
> turn off wrapping so that I only need to call ".text see" after I
> insert a newline character.

Are you putting a large amount of data (1000s of lines) in the text
widget?  The text widget doesn't scale very well to unlimited rollback.
Most people who do terminal applications also do periodic

     .path.to.text delete 1.0 end-500l

(change 500 to a number reasonable in your application) and see much,
much better performance.

--
73 de ke9tv/2, Kevin



Mon, 04 Feb 2008 21:28:17 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom
I'm currently limiting the number of lines to 20000, doing the deleting
every time I encounter a '\n'.  I tried backing it off to 500 lines,
and making the line deletion occur periodically (every 0.5 sec), but my
CPU is still {*filter*} on wish because of the ".text yview" and/or ".text
see".


Mon, 04 Feb 2008 23:27:19 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom

Quote:

> Most people who do terminal applications also do periodic
>     .path.to.text delete 1.0 end-500l

Oh wow. That's much easier than the calculations I did to accomplish
that. I wish I'd thought of the "end-..." syntax. :-)

--
   Darren New / San Diego, CA, USA (PST)
"You're going to be late for your meeting."
      "That's OK. I can be late."
"What's it about?"
      "Someone else's problems."



Tue, 05 Feb 2008 00:03:00 GMT  
 text widget must follow end of text only if associated scrollbar is at bottom

Quote:


>> Most people who do terminal applications also do periodic
>>     .path.to.text delete 1.0 end-500l

> Oh wow. That's much easier than the calculations I did to accomplish
> that. I wish I'd thought of the "end-..." syntax. :-)

This is how I do it...
My receive event handler plugs received characters
into the global rxbuf.

This has the advantage of only deleting whole lines
from the text box. (note: the text box is
normally disable so you can't edit the
received data).

proc update_display {  } {
    global rxBuf
    global status

    if { [ string length $rxBuf ] > 0 } {
       if {  $status(logToDisk) } {
          catch {
             puts $status(realTimeLogFile) $rxBuf nonewline
          }
       }

       .text config -state normal
       .text insert end $rxBuf rxTag
       set rxBuf ""

       scan [ .text index end ] "%d." lineCount

       # Limit buffer to 10000 lines to stop it consuming
       # all available memory

       if { $lineCount > 100000 } {
          # Remove the start of the buff
          set del [ expr { $lineCount - 100000 } ]
          .text delete 1.0 $del.0
       }
       .text config -state disabled
    }

Quote:
}

Regards

Palu



Tue, 05 Feb 2008 11:50:26 GMT  
 
 [ 18 post ]  Go to page: [1] [2]

 Relevant Pages 

1. Some questions on elided text in the text widget (and a few other text widget questions)

2. Jumping to end of text in text widget?

3. scrolling text window when adding text at bottom.

4. How to get text widget to scroll to the bottom on insert

5. text widget bottom

6. embedding text widgets in other text widgets

7. Following new text in a text window

8. tabnotebook, text and scrollbar widget problem

9. How to use one scrollbar to control two text widgets

10. One Scrollbar, Multilpe Text/Canvas Widgets

11. Synchronizing two text- widgets to one scrollbar ?

12. scrollbar at text widget

 

 
Powered by phpBB® Forum Software