Stop Text widget from scrolling when content is ch

2019-07-07 03:51发布

问题:

I have a text widget with a scrollbar which looks something like this:

self.myWidget = Text(root) 
self.myWidget.configure(state=DISABLED)
self.myWidget.pack()

self.myWidgetScrollbar = Scrollbar(root, command=self.myWidget.yview)
self.myWidget.configure(yscrollcommand=self.myWidgetScrollbar.set)
self.myWidgetScrollbar.pack(side=LEFT,fill=Y)

The text widget is updated 4 times per second with:

self.myWidget.configure(state=NORMAL)
self.myWidget.delete(1.0, END) 
self.myWidget.insert(END, "\n".join(self.listWithStuff))  
self.myWidget.configure(state=DISABLED)

The problem is that when I try to scroll, it keeps scrolling me back up to the top (4 times per second, probably). I assume this is because all content is removed.

How can I prevent it from scrolling automatically, or possibly scroll "back" when the content has changed?

回答1:

You can safe the position and set it back after an update, like this Tcl code does:

proc update_view {w s data} {
  # store position
  set pos [$s get]
  $w configure -state normal -yscrollcommand {}
  $w delete 1.0 end
  $w insert end $data
  $w configure -state disabled -yscrollcommand [list $s set]
  $s get
  $s set {*}$pos
}

The Tkinter code would look similar, something like:

def update_view(self, data):
    pos = self.myWidgetScrollbar.get()
    self.myWidget.configure(yscrollcommand=None, state=NORMAL)
    self.myWidget.delete(1.0, END)
    self.myWidget.insert(END, data)
    self.myWidget.configure(yscrollcommand=self.myWidgetScrollbar.set, state=DISABLED)
    self.myWidgetScrollbar.get()
    self.myWidgetScrollbar.set(pos)

Not sure why the get() in between is needed, maybe to force some lookup, but it works.



回答2:

You can jump to the bottom of the widget after each update using the yview method of the Text widget. Also, to prevent frustrating users by jumping when they are trying to scroll, you can do a simple check to make sure the scrollbar is already at the bottom (a.k.a the user isn't scrolling).

if self.myWidgetScrollbar.get() == 1.0:
    self.myWidget.yview(END)