Mailing List Archive

Q on Tkinter Scrollbar
Hi everyone,

I want to manually control the scrollbar in a tkinter app, i.e. I don't
want to tie it to another widget as a child. Below is what I have so
far. I can't figure how to make the 'thumb' stay at the returned
position, or the point where the user drags it. Right now it always
pops back to the top.

I want it to behave like a Scale, but look like a scrollbar. Think of a
virtual window on a dataset, where I don't want to load the contents of
the data set into a listbox (not enough memory).

Anyone do this before, know of any similar examples, or give me a clue
where to look next. I don't want to use extensions or another GUI, it
needs to be Tkinter.

Thanks in advance,
Joe Robertson
jmrober1@ingr.com


>----begin code
# a manual scrollbar
#
# Joe Robertson, jmrober1@ingr.com
#
from Tkinter import *

class Manual(Frame):

def __init__(self, master, **kw):
apply(Frame.__init__, (self, master), kw)
vscrollbar = Scrollbar(self, orient=VERTICAL)
self.canvas = Canvas(self)
vscrollbar.config(command=self._vscroll)
vscrollbar.pack(fill=Y, side=RIGHT)
self.canvas.pack(expand=1, fill=BOTH, side=LEFT)

def _vscroll(self, type, *arg):
print type
if type == 'moveto':
for each in arg:
print each

# doit
root = Tk()
f = Manual(root)
f.pack(expand=1, fill=BOTH)
root.mainloop()

>----end code
Q on Tkinter Scrollbar [ In reply to ]
Hi, Joseph,

I can't give you any useful tips on the scrollbar, but if I was writing
this I think I would probably subclass the canvas to create a "meter" or
"thermometer" widget to do what you need. Create a rectangular canvas
(taller than wide), draw the scale (lines and text), then create an
indicator (a triangle?) to point the current value.

In fact, if you're not against using Pmw, there is just such a beast in
the demos or contrib directory. Now that I think of it, you might find
some useful examples of the scrollbar elsewhere in the Pmw code. Take a
look http://www.dscpl.com.au/pmw/.

Doug

Joseph Robertson wrote:
>
> Hi everyone,
>
> I want to manually control the scrollbar in a tkinter app, i.e. I don't
> want to tie it to another widget as a child. Below is what I have so
> far. I can't figure how to make the 'thumb' stay at the returned
> position, or the point where the user drags it. Right now it always
> pops back to the top.
>
> I want it to behave like a Scale, but look like a scrollbar. Think of a
> virtual window on a dataset, where I don't want to load the contents of
> the data set into a listbox (not enough memory).
>
> Anyone do this before, know of any similar examples, or give me a clue
> where to look next. I don't want to use extensions or another GUI, it
> needs to be Tkinter.
>
> Thanks in advance,
> Joe Robertson
> jmrober1@ingr.com
>
> >----begin code
> # a manual scrollbar
> #
> # Joe Robertson, jmrober1@ingr.com
> #
> from Tkinter import *
>
> class Manual(Frame):
>
> def __init__(self, master, **kw):
> apply(Frame.__init__, (self, master), kw)
> vscrollbar = Scrollbar(self, orient=VERTICAL)
> self.canvas = Canvas(self)
> vscrollbar.config(command=self._vscroll)
> vscrollbar.pack(fill=Y, side=RIGHT)
> self.canvas.pack(expand=1, fill=BOTH, side=LEFT)
>
> def _vscroll(self, type, *arg):
> print type
> if type == 'moveto':
> for each in arg:
> print each
>
> # doit
> root = Tk()
> f = Manual(root)
> f.pack(expand=1, fill=BOTH)
> root.mainloop()
>
> >----end code
Q on Tkinter Scrollbar [ In reply to ]
No thats a scale.

Picture a scrollable canvas spreadsheet table of 58 cols and 90,000+ rows.
Now picture tkinter trying to create that grid, if it doesn't bomb from the
strain it would still take it literally hours to create it. But since you
can't 'see' anything outside the scrollwindow of at most 60 rows, why try to
create it? A thermometer or scale looks out of place. A scrollbar is
expected. Now let the vertical scrollbar track the 'dataset' and simply show
the 60 rows that the scrollbar points to. I've done all this in VB, using
Python-Com as the underlying dataset. Now I am trying to ditch the vb gui
(and its horrible overhead).

Thanks,
Joe Robertson
jmrober1@ingr.com


Doug Hellmann wrote:

> Hi, Joseph,
>
> I can't give you any useful tips on the scrollbar, but if I was writing
> this I think I would probably subclass the canvas to create a "meter" or
> "thermometer" widget to do what you need. Create a rectangular canvas
> (taller than wide), draw the scale (lines and text), then create an
> indicator (a triangle?) to point the current value.
>
> In fact, if you're not against using Pmw, there is just such a beast in
> the demos or contrib directory. Now that I think of it, you might find
> some useful examples of the scrollbar elsewhere in the Pmw code. Take a
> look http://www.dscpl.com.au/pmw/.
>
> Doug
>
> Joseph Robertson wrote:
> >
> > Hi everyone,
> >
> > I want to manually control the scrollbar in a tkinter app, i.e. I don't
> > want to tie it to another widget as a child. Below is what I have so
> > far. I can't figure how to make the 'thumb' stay at the returned
> > position, or the point where the user drags it. Right now it always
> > pops back to the top.
> >
> > I want it to behave like a Scale, but look like a scrollbar. Think of a
> > virtual window on a dataset, where I don't want to load the contents of
> > the data set into a listbox (not enough memory).
> >
> > Anyone do this before, know of any similar examples, or give me a clue
> > where to look next. I don't want to use extensions or another GUI, it
> > needs to be Tkinter.
> >
> > Thanks in advance,
> > Joe Robertson
> > jmrober1@ingr.com
> >
> > >----begin code
> > # a manual scrollbar
> > #
> > # Joe Robertson, jmrober1@ingr.com
> > #
> > from Tkinter import *
> >
> > class Manual(Frame):
> >
> > def __init__(self, master, **kw):
> > apply(Frame.__init__, (self, master), kw)
> > vscrollbar = Scrollbar(self, orient=VERTICAL)
> > self.canvas = Canvas(self)
> > vscrollbar.config(command=self._vscroll)
> > vscrollbar.pack(fill=Y, side=RIGHT)
> > self.canvas.pack(expand=1, fill=BOTH, side=LEFT)
> >
> > def _vscroll(self, type, *arg):
> > print type
> > if type == 'moveto':
> > for each in arg:
> > print each
> >
> > # doit
> > root = Tk()
> > f = Manual(root)
> > f.pack(expand=1, fill=BOTH)
> > root.mainloop()
> >
> > >----end code
Q on Tkinter Scrollbar [ In reply to ]
Joseph Robertson <jmrober1@ingr.com> wrote:
> I want to manually control the scrollbar in a tkinter app, i.e. I don't
> want to tie it to another widget as a child. Below is what I have so
> far. I can't figure how to make the 'thumb' stay at the returned
> position, or the point where the user drags it. Right now it always
> pops back to the top.
>
> I want it to behave like a Scale, but look like a scrollbar. Think of a
> virtual window on a dataset, where I don't want to load the contents of
> the data set into a listbox (not enough memory).
>
> Anyone do this before, know of any similar examples, or give me a clue
> where to look next. I don't want to use extensions or another GUI, it
> needs to be Tkinter.

you're halfways there. as you've seen, the callback given to the scrollbar's
"command" option (your _vscroll callback) is called with "moveto" or "scroll"
events, as described on:
http://www.pythonware.com/library/tkinter/introduction/scrollbar.htm

however, the scrollbar target (your dataset) should respond to this by calling
the scrollbar's "set" method with two floating point values (first and last),
which gives the thumb's position as 0.0 (upper/left) and 1.0 (lower/right).
the target should of course also update the scrollbar if the view changes
by any other reason (e.g. if you load a new dataset).

scrollable widgets like Listbox and Text provide "xscrollcommand" and
"yscrollcommand" options for this purpose.

Cheers /F
fredrik@pythonware.com
http://www.pythonware.com
Q on Tkinter Scrollbar [ In reply to ]
In article <370CFAC8.32EB0B29@ingr.com>,
Joseph Robertson <jmrober1@ingr.com> wrote:
>Hi everyone,
>
>I want to manually control the scrollbar in a tkinter app, i.e. I don't
>want to tie it to another widget as a child. Below is what I have so
>far. I can't figure how to make the 'thumb' stay at the returned
>position, or the point where the user drags it. Right now it always
>pops back to the top.

I think you need to, in _vscroll, set the position of the scrollbar.
I did this exact thing in a tcl app once, so I know it's possible.
It's a bit of work to figure out where things are supposed to be, but
you're going to have to tell it what being halfway down means anyway.

Michael
Q on Tkinter Scrollbar [ In reply to ]
> I think you need to, in _vscroll, set the position of the scrollbar.
> I did this exact thing in a tcl app once, so I know it's possible.
> It's a bit of work to figure out where things are supposed to be, but
> you're going to have to tell it what being halfway down means anyway.
>
> Michael

Is it possible to find out the location of the top and bottom character
of a tkinter text object currently showing? I want to be able to seardch
for a tag on the currently viewable portion, but I can find out the
start and end positions of the text.

Thanks,


Bradley
Q on Tkinter Scrollbar [ In reply to ]
Bradley Baetz wrote:
> Is it possible to find out the location of the top and bottom character
> of a tkinter text object currently showing? I want to be able to seardch
> for a tag on the currently viewable portion, but I can find out the
> start and end positions of the text.

you can use the "@x,y" index syntax for this; the
start of the visible text is "@0,0", the end is "@x,y"
where x and y is the window size (or anything
larger, like "@10000,10000").

also see the attached example.

</F>


#
# tk053.py -- find visible region of a text widget
#
# fredrik lundh, may 1999
#
# fredrik@pythonware.com
# http://www.pythonware.com
#

from Tkinter import *

root = Tk()

# create a scrolled text widget

frame = Frame(root, bd=2, relief=SUNKEN)

scrollbar = Scrollbar(frame, orient=VERTICAL)
scrollbar.pack(fill=Y, side=RIGHT)

text = Text(frame, bd=0)
text.pack()

for i in range(1, 1000):
text.insert(END, "line %s\n" % i)

# attach scrollbar
text.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=text.yview)

frame.pack()

label = Label(root)
label.pack()

def report_position():

# get (beginning of) first visible line
top = text.index("@0,0")

# get (end of) last visible line
bottom = text.index("@0,%d" % text.winfo_height())

# update the label
label.config(text="top: %s\nbottom: %s" % (top, bottom))
root.after(100, report_position) # update 10 times a second

report_position()

mainloop()
Q on Tkinter Scrollbar [ In reply to ]
you can use the "@x,y" index syntax for this; the
start of the visible text is "@0,0", the end is "@x,y"
where x and y is the window size (or anything
larger, like "@10000,10000").

also see the attached example.

....

def report_position():

# get (beginning of) first visible line
top = text.index("@0,0")

# get (end of) last visible line
bottom = text.index("@0,%d" % text.winfo_height())

Thanks a lot for your help. The only thing I don't understand is why the above line returns the position of the _end_ of the line. I know it does (I tried it), but wouldn't the "@0,%d" mean that text.index returns the absolute index to the position where x=0 (ie the beginning of the line), not the end? Now looking at your comments :), I would have got the absolute line number, and then used lineno.end as the index. What did I miss?

Thanks a lot,


Bradley