Discussion:
Example of scrollbar available?
Josef Wolf
2013-12-12 11:59:32 UTC
Permalink
Hello folks,

are there any examples of scrollbar usage available? I have a hard time to
grasp how to use them, and I can't find any examples in the documentation.

Thanks!
--
Josef Wolf
***@raven.inka.de
Josef Wolf
2013-12-12 17:39:15 UTC
Permalink
Post by Josef Wolf
are there any examples of scrollbar usage available? I have a hard time to
grasp how to use them, and I can't find any examples in the documentation.
With this code:

(defun test-scrolled-frame ()
(with-ltk (:debug 3)
(let* ((root (make-instance 'frame))
(scrolled (make-instance 'scrolled-frame :master root))
(quit-button (make-instance
'button
:master root
:text "Quit"
:command (lambda ()
(setf *exit-mainloop* t)))))

(pack root :side :top)
(pack scrolled :side :top)
(pack quit-button :side :top)

(dolist (number '(1 2 3 4 5 6 7 8 9))
(let ((btn (make-instance 'button
:master scrolled
:text number
:command (lambda ()
(format t "~a~%" number)))))
(pack btn :side :top :anchor :w))))

(do-msg "huhu")))

I get an empty root window and the wish process hangs eating CPU.

If I change the code to use FRAME instead of SCROLLED-FRAME, the code works
fine (but obviously without a scrollbar)

Any suggestions?
--
Josef Wolf
***@raven.inka.de
Jason Miller
2013-12-12 20:27:59 UTC
Permalink
Post by Josef Wolf
are there any examples of scrollbar usage available? I have a hard time to
grasp how to use them, and I can't find any examples in the documentation.
...
I haven't had much success with the wrapper classes for scrolled
widgets, so I do it manually. For a more full treatment, see the tk
documentation, but here's enough to get you started:

;First make a textbox and a scrollbar to go with it:
(let ((tb (make-instance 'text :width 78 :height 20))
(tbsb (make-instance 'scrollbar :orientation :vertical)))
;Now put them where you want them; I'm using pack as it's the least code:
(pack tb :side :left)
(pack tbsb :side :left :fill :y)
;Now you need to tell the two widgets about each other
(configure tbsb "command" (format nil "~a yview" (widget-path tb)))
(configure tb :yscrollcommand (format nil "~a set" (widget-path
tbsb))))

-Jason
Josef Wolf
2013-12-12 23:13:27 UTC
Permalink
Post by Jason Miller
(let ((tb (make-instance 'text :width 78 :height 20))
(tbsb (make-instance 'scrollbar :orientation :vertical)))
(pack tb :side :left)
(pack tbsb :side :left :fill :y)
;Now you need to tell the two widgets about each other
(configure tbsb "command" (format nil "~a yview" (widget-path tb)))
(configure tb :yscrollcommand (format nil "~a set" (widget-path
tbsb))))
Thanks for the hint, Jason! But I am still struggling.

Your example works fine. But it covers only a single text widget. I am trying
to scroll a collection of widgets, like this:

(defun scrolltest ()
(with-ltk ()
(let* ((root (make-instance 'frame))
(button-list (make-instance 'listbox :master root))
(scrollbar (make-instance 'scrollbar :master root
:orientation :vertical))
(quit-button (make-instance 'button :master root
:text "Quit"
:command (lambda ()
(setf *exit-mainloop* t)))))

(pack root :side :top)
(pack quit-button :side :bottom :pady 10)
(pack button-list :side :left)
(pack scrollbar :side :left :expand t :fill :y)

(configure scrollbar "command"
(format nil "~a yview" (widget-path button-list)))

(configure button-list :yscrollcommand
(format nil "~a set" (widget-path scrollbar)))

(dolist (button-number '(1 2 3 4 5 6 7 8 9 0))
(let ((b (make-instance 'button
:master button-list
:text button-number
:command (lambda ()
(format t "~a~%" button-number)))))
(pack b :side :top :anchor :w))))))

The widgets simply don't seem to be connected :-(

I have also tried with a frame instead of a listbox, but frames don't seem to
support the yscrollcommand.
--
Josef Wolf
***@raven.inka.de
edgar
2013-12-12 23:43:12 UTC
Permalink
Am Fri, 13 Dec 2013 00:13:27 +0100
Post by Josef Wolf
Post by Jason Miller
(let ((tb (make-instance 'text :width 78 :height 20))
(tbsb (make-instance 'scrollbar :orientation :vertical)))
;Now put them where you want them; I'm using pack as it's the least
code: (pack tb :side :left)
(pack tbsb :side :left :fill :y)
;Now you need to tell the two widgets about each other
(configure tbsb "command" (format nil "~a yview" (widget-path
tb))) (configure tb :yscrollcommand (format nil "~a
set" (widget-path tbsb))))
Thanks for the hint, Jason! But I am still struggling.
Your example works fine. But it covers only a single text widget. I
(defun scrolltest ()
(with-ltk ()
(let* ((root (make-instance 'frame))
(button-list (make-instance 'listbox :master root))
(scrollbar (make-instance 'scrollbar :master root
:orientation :vertical))
(quit-button (make-instance 'button :master root
:text "Quit"
:command (lambda ()
(setf
*exit-mainloop* t)))))
(pack root :side :top)
(pack quit-button :side :bottom :pady 10)
(pack button-list :side :left)
(pack scrollbar :side :left :expand t :fill :y)
(configure scrollbar "command"
(format nil "~a yview" (widget-path button-list)))
(configure button-list :yscrollcommand
(format nil "~a set" (widget-path scrollbar)))
(dolist (button-number '(1 2 3 4 5 6 7 8 9 0))
(let ((b (make-instance 'button
:master button-list
:text button-number
:command (lambda ()
(format t "~a~%"
button-number))))) (pack b :side :top :anchor :w))))))
The widgets simply don't seem to be connected :-(
I have also tried with a frame instead of a listbox, but frames don't
seem to support the yscrollcommand.
The Tcl/Tk code to scroll multiple wigets by a single scrollbar is:

# called by the widget
proc yset {args} {
eval [linsert $args 0 .f.sb set]
yview moveto [lindex [.f.sb get] 0]
}

# called by the scroll bar
proc yview {args} {
eval [linsert $args 0 .f.lb1 yview]
eval [linsert $args 0 .f.lb2 yview]
}

See the Tcl/Tk wiki "multi scrolling" http://wiki.tcl.tk/9254

But it still must be fiddled out how this works with LTK...

- edgar
Jason Miller
2013-12-13 00:30:47 UTC
Permalink
Post by Josef Wolf
Post by Jason Miller
(let ((tb (make-instance 'text :width 78 :height 20))
(tbsb (make-instance 'scrollbar :orientation :vertical)))
(pack tb :side :left)
...
Thanks for the hint, Jason! But I am still struggling.
Your example works fine. But it covers only a single text
widget. I am trying
to scroll a collection of widgets...
Well, strangely enough, tk doesn't have this as a widget. There are
variouls hacks to get it, and it looks like scrolled-frame implements it.
However, when setting the master of widgets that go in it, you'll need to
use the INTERIOR accessor like so:

(ltk:with-ltk ()
(let ((sf (make-instance 'ltk:scrolled-frame)))
(ltk:pack sf)
(loop for i from 1 to 20
for label = (make-instance 'ltk:label :master (ltk:interior sf) :text
"Hello, World!")
do (ltk:pack label))))

HTH,
Jason
Josef Wolf
2013-12-13 07:10:54 UTC
Permalink
Post by Jason Miller
Post by Josef Wolf
Your example works fine. But it covers only a single text widget.
I am trying to scroll a collection of widgets...
Well, strangely enough, tk doesn't have this as a widget. There are
variouls hacks to get it, and it looks like scrolled-frame
implements it. However, when setting the master of widgets that go
(ltk:with-ltk ()
(let ((sf (make-instance 'ltk:scrolled-frame)))
(ltk:pack sf)
(loop for i from 1 to 20
for label = (make-instance 'ltk:label :master (ltk:interior sf)
:text "Hello, World!")
do (ltk:pack label))))
This works great! Thanks Jason!

What is this INTERIOR thing? I've never seen such a thing in Perl/Tk. And the
Tk doc's seem to suggest every non-mainwindow is an interior window. But this
is about windows, not widgets.

There seems to be still one problem, though: When the root window is resized,
the size of the scrolled-frame is not adopted. :expand t :fill :both don't
seem to have an effect. The scrolled-frame seems to have a maximum
size. Increasing this with the :height and :wide options don't seem to have an
effect.

Here's the current code:

(with-ltk ()
(let* ((root (make-instance 'frame))
(branches (make-instance 'scrolled-frame :master root
:height 1000 :width 1000))
(quit-button (make-instance 'button :master root
:text "Quit"
:command (lambda ()
(setf *exit-mainloop* t)))))
(pack root :side :top)
(pack branches :side :top :expand t :fill :both)
(pack quit-button :side :top :pady 10)

(loop for i from 1 to 20
for label = (make-instance 'ltk:label :master (ltk:interior branches)
:text (format nil "Hello, World ~d!" i))
do (ltk:pack label))

(bind root "<KeyPress-q>" (lambda (ev) (declare (ignore ev))
(exit-wish)))

(do-msg "huhu")))
--
Josef Wolf
***@raven.inka.de
bl0
2013-12-15 18:58:13 UTC
Permalink
Post by Josef Wolf
There seems to be still one problem, though: When the root window is
resized, the size of the scrolled-frame is not adopted. :expand t :fill
:both don't seem to have an effect. The scrolled-frame seems to have a
maximum size. Increasing this with the :height and :wide options don't
seem to have an effect.
[...]
Post by Josef Wolf
(pack root :side :top)
(pack branches :side :top :expand t :fill :both)
Can you add :expand t :fill :both to the outer frame too?

edgar
2013-12-13 00:31:10 UTC
Permalink
Am Fri, 13 Dec 2013 00:13:27 +0100
Post by Josef Wolf
Post by Jason Miller
(let ((tb (make-instance 'text :width 78 :height 20))
(tbsb (make-instance 'scrollbar :orientation :vertical)))
;Now put them where you want them; I'm using pack as it's the least
code: (pack tb :side :left)
(pack tbsb :side :left :fill :y)
;Now you need to tell the two widgets about each other
(configure tbsb "command" (format nil "~a yview" (widget-path
tb))) (configure tb :yscrollcommand (format nil "~a
set" (widget-path tbsb))))
Thanks for the hint, Jason! But I am still struggling.
Your example works fine. But it covers only a single text widget. I
(defun scrolltest ()
(with-ltk ()
(let* ((root (make-instance 'frame))
(button-list (make-instance 'listbox :master root))
(scrollbar (make-instance 'scrollbar :master root
:orientation :vertical))
(quit-button (make-instance 'button :master root
:text "Quit"
:command (lambda ()
(setf
*exit-mainloop* t)))))
(pack root :side :top)
(pack quit-button :side :bottom :pady 10)
(pack button-list :side :left)
(pack scrollbar :side :left :expand t :fill :y)
(configure scrollbar "command"
(format nil "~a yview" (widget-path button-list)))
(configure button-list :yscrollcommand
(format nil "~a set" (widget-path scrollbar)))
(dolist (button-number '(1 2 3 4 5 6 7 8 9 0))
(let ((b (make-instance 'button
:master button-list
:text button-number
:command (lambda ()
(format t "~a~%"
button-number))))) (pack b :side :top :anchor :w))))))
The widgets simply don't seem to be connected :-(
I have also tried with a frame instead of a listbox, but frames don't
seem to support the yscrollcommand.
After having a closer look at your code it appears to me that
this is pretty much nonsense what you're trying there.

A listbox widget is meant to manage _text_ items that are
displayed as a vertical list inside the widget.

A listbox widget is *not* meant to contain buttons.
A listbox widget *cannot* scroll buttons.

What exactly are you trying to achive with this code?

Probably we can find a different solution, but I haven't
understood what exactly is the desired purpose.

- edgar
Josef Wolf
2013-12-13 06:41:07 UTC
Permalink
Post by edgar
After having a closer look at your code it appears to me that
this is pretty much nonsense what you're trying there.
Well, if you try about everything and nothing works, eventually you arrive at
a point where you even try nonsense :-)
Post by edgar
A listbox widget is meant to manage _text_ items that are
displayed as a vertical list inside the widget.
Originally, I had a frame with a load of widgets. But as I wrote in my
previous mail, the frame don't seem to support the yscrollcommand option.

Then I tried scrolled-frame, but this just hangs.
Post by edgar
What exactly are you trying to achive with this code?
I have a frame of widgets, which are created dynamically (branches and files
of a git repository), so chances are they won't fit on the screen. So I tried
to scroll the frame, but the frame won't support the yscrollcommand.
--
Josef Wolf
***@raven.inka.de
edgar
2013-12-13 07:25:47 UTC
Permalink
Am Fri, 13 Dec 2013 07:41:07 +0100
Post by Josef Wolf
Post by edgar
After having a closer look at your code it appears to me that
this is pretty much nonsense what you're trying there.
Well, if you try about everything and nothing works, eventually you
arrive at a point where you even try nonsense :-)
Yes ... I remember ... that's exactly how I learned Tcl/Tk :-)
Post by Josef Wolf
Post by edgar
A listbox widget is meant to manage _text_ items that are
displayed as a vertical list inside the widget.
Originally, I had a frame with a load of widgets. But as I wrote in my
previous mail, the frame don't seem to support the yscrollcommand option.
Then I tried scrolled-frame, but this just hangs.
Post by edgar
What exactly are you trying to achive with this code?
I have a frame of widgets, which are created dynamically (branches
and files of a git repository), so chances are they won't fit on the
screen. So I tried to scroll the frame, but the frame won't support
the yscrollcommand.
Hierarchical browsers containing text (like file names and git branches)
together with nodes (e.g. little graphics symbols) that can be expanded
and collapsed are usually implemented by text widgets and text markers.

An example how this works can be found in the book
"Effective Tcl/Tk Programming" by Mark Harrison and Michael McLennan:
http://www.amazon.com/Effective-Tcl-Tk-Programming-Programs/dp/0201634740

A picture how this looks like can be found here:
Loading Image...

The text browser on the left side contains small black triangles
to expanded and/or collapse the text under the headlines.

Is that what you want?

I have a copy of "Effective Tcl/Tk Programming" and we could try
to re-implement the browser widget in LTK.

- edgar
Josef Wolf
2013-12-13 10:12:15 UTC
Permalink
Post by edgar
Am Fri, 13 Dec 2013 07:41:07 +0100
Post by Josef Wolf
Well, if you try about everything and nothing works, eventually you
arrive at a point where you even try nonsense :-)
Yes ... I remember ... that's exactly how I learned Tcl/Tk :-)
:-)

Do I really need to learn tcl when I want to use ltk? =8-O
Post by edgar
Hierarchical browsers containing text (like file names and git branches)
together with nodes (e.g. little graphics symbols) that can be expanded
and collapsed are usually implemented by text widgets and text markers.
An example how this works can be found in the book
http://www.amazon.com/Effective-Tcl-Tk-Programming-Programs/dp/0201634740
http://incrtcl.sourceforge.net/itcl/mmc/full/catalog.gif
The text browser on the left side contains small black triangles
to expanded and/or collapse the text under the headlines.
Is that what you want?
That's pretty close. Things that I need which might be missing in such a
browser are:

- preview/rename/move/remove files within a branch (possibly modifying file
hierarchy)
- move files from one branch to another
- rename branches
- merge branches
Post by edgar
I have a copy of "Effective Tcl/Tk Programming" and we could try
to re-implement the browser widget in LTK.
That would be great!
--
Josef Wolf
***@raven.inka.de
edgar
2013-12-13 22:46:11 UTC
Permalink
Fri, 13 Dec 2013 11:12:15 +0100
Post by Josef Wolf
Do I really need to learn tcl when I want to use ltk? =8-O
You do not necessarily *need* to learn Tcl/Tk to use LTK, but if you
don't know what you are doing you are doomed to write shitty programs.
That is true for every programming language.
Post by Josef Wolf
Post by edgar
http://incrtcl.sourceforge.net/itcl/mmc/full/catalog.gif
The text browser on the left side contains small black triangles
to expanded and/or collapse the text under the headlines.
Is that what you want?
That's pretty close. Things that I need which might be missing
- preview/rename/move/remove files within a branch (possibly modifying
file hierarchy)
- move files from one branch to another
- rename branches
- merge branches
Such things are provided by *no* GUI toolkit I know, so it will be
your task to add this functionality e.g. by binding Lisp functions
to mouse-clicks or other GUI events.
Post by Josef Wolf
Post by edgar
I have a copy of "Effective Tcl/Tk Programming" and we could try
to re-implement the browser widget in LTK.
That would be great!
I just realized that Tcl/Tk 8.6 has a ttk::treeview widget

man page http://www.tcl.tk/man/tcl/TkCmd/ttk_treeview.htm
examples http://wiki.tcl.tk/20065

LTK supports the ttk::treeview widget by:

#:treeview
#:treeview-delete
#:treeview-focus
#:treeview-exists
#:treeview-insert
#:treeview-item
#:treeview-column
#:treeview-heading
#:treeview-move
#:scrolled-treeview
#:treeview-get-selection
#:treeview-identify
#:treeview-identify-item
#:treeview-set-selection

The advantage of using the ttk::treeview widget would be that
the LTK classes and methods already exist, the advantage of
porting the "Effective Tclk/Tk" browser would be that it can
be easily extended, it is implemented in Tcl/Tk (not in C).

The disadvantage of the ttk::treeview widget would be that it
doesn't exist in Tcl/Tk version before Tcl/Tk 8.6.

I already have downloaded the "Effective Tclk/Tk" code and will
try to make a LTK megawidget out of it over the weekend, but
I will promise nothing until the code really works...

- edgar
edgar
2013-12-13 07:33:42 UTC
Permalink
Sorry, I'm an idiot, most important link forgotten...

The Tcl/Tk code from the book "Effective Tcl/Tk Programming"
can be found here:

http://sourceforge.net/projects/efftcl/

- edgar
Loading...