Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A good menu tutorial?

9 views
Skip to first unread message

Robert Hicks

unread,
Aug 30, 2006, 12:36:38 PM8/30/06
to
I would like to create a dynamic menu when the application starts. I
have a directory structure like:

Courses/Name1
Courses/Name2

I would like Name1 and Name2 (and so on) to become sub-menus of the
Courses top level menu.

Courses
Name1
Name2

That way a user can create another directory and it will automatically
be added. Eventually I will have files in those directories that will
sub-menu names etc. So if you create a directory name of "Test" and add
files called "test1.txt" and "text2.txt" then the menu would look like:

Courses
Name1
Name2
Test
test1 # this will open the file into the application
test2 # ditto

I have the home of the script set like:

set home [file dirname [info script]]

So I guess I can do a foreach on "$home/Courses/" to get the dir names
and file names? I am not sure how to build a menu with that though.

Anyone done something like this?

Robert

suchenwi

unread,
Aug 30, 2006, 12:43:42 PM8/30/06
to

Robert Hicks schrieb:

> So I guess I can do a foreach on "$home/Courses/" to get the dir names
> and file names? I am not sure how to build a menu with that though.
>
> Anyone done something like this?

>From http://en.wikibooks.org/wiki/Programming:Tcl_Tk#menu

To add a menu to a GUI application, take steps of three kinds:

Create the toplevel horizontal menu (needed only once):
. configure -menu [menu .m]

For each item in the top menu, create a cascaded submenu, e.g.
.m add cascade -label File -menu [menu .m.mFile]

For each entry in a submenu, add it like this:
.m.mFile add command -label Open -command {openFile ...}
or
.m.mFile add separator

In your case, add a cascade for each directory, and a command for each
file that [glob] brings you.

Robert Hicks

unread,
Aug 30, 2006, 12:53:33 PM8/30/06
to

Great! I did it and it works. : D

Robert

suchenwi

unread,
Aug 30, 2006, 12:58:01 PM8/30/06
to

Robert Hicks schrieb:

> Great! I did it and it works. : D

That was a cool development cycle - from question asked to solution
confirmed, 17 minutes :D

Robert Hicks

unread,
Aug 30, 2006, 1:14:37 PM8/30/06
to

I got the directories down:

foreach cDir [lsort -dictionary [glob $home/Courses/*]] {
.m.mLessons add cascade -label [file tail $cDir]
}

That does what I want it to do, so thanks for that suggestion. What do
those cascade names become assuming the foreach brings back directory
names of dir1, dir2, dir3. Do they become: .m.mLessons.dir1
.m.mLessons.dir2 and .m.mLessons.dir3

Robert

Robert Hicks

unread,
Aug 30, 2006, 1:15:14 PM8/30/06
to

Oops! I am not that smart. : D

suchenwi

unread,
Aug 30, 2006, 3:16:43 PM8/30/06
to
Robert Hicks schrieb:

> That does what I want it to do, so thanks for that suggestion. What do
> those cascade names become assuming the foreach brings back directory
> names of dir1, dir2, dir3. Do they become: .m.mLessons.dir1
> .m.mLessons.dir2 and .m.mLessons.dir3

Hmm..
Tcl/Tk is very simple. But some reading man pages (in this case, menu)
still helps.

As my (maybe too brief) explanation showed, to add a cascade you'd best
specify a new menu. How to call this is up to you - just make sure its
name doesn't start with an uppercase letter (that's why I put a "m" in
front).

You can call [glob] separately for subdirectories (-type d) and files
(-type f). I'd suggest first to do the directories, create a cascade
for each,

.m.whatever.m$dir create cascade -label $subdir -menu [menu
.m.whatever.m$dir.m$subdir]

and recurse into them (call the same procedure for each again). Then do
the files, adding a simple command to the current menu.

Robert Hicks

unread,
Aug 30, 2006, 5:14:14 PM8/30/06
to

Thank you very much!

Robert

Bruce Hartweg

unread,
Aug 31, 2006, 12:51:34 AM8/31/06
to
general approach is dead on, but be *very* careful using externally
generated names (like filenames) directly as component of widget names,
if they contain a . you will blow up as the . is the widget seperator.
so I would either keep a simple 1-up counter to make the menu widget
name itself (keeping the displayed label the actual directory) or else
use string map to map any "." to "_" or something (and mayber spaces
too which don't necessarily break you but can cause headaches occasionally.

Bruce

Robert Hicks

unread,
Aug 31, 2006, 10:11:47 AM8/31/06
to

Yes, I am not sure what I want to do here. The file format is going to
be a set one. I may create a simple ini file with something like
title=blah as the key/value then a user would just have to drop in the
file and update the ini file and I only have to parse that. Come to
think of it that is what i will do. It saves me from having to do
globbing and such to get directory and file names. I can use the
key/value to get the file name and title of the lesson and I can use
the section to denote the directory it resides in. I could even build a
wizard in the app to help create the ini section itself.

Hmmm, I will try that.

Robert

Bryan Oakley

unread,
Aug 31, 2006, 11:48:21 AM8/31/06
to
Robert Hicks wrote:

> Yes, I am not sure what I want to do here. The file format is going to
> be a set one. I may create a simple ini file with something like
> title=blah as the key/value then a user would just have to drop in the
> file and update the ini file and I only have to parse that. Come to
> think of it that is what i will do. It saves me from having to do
> globbing and such to get directory and file names. I can use the
> key/value to get the file name and title of the lesson and I can use
> the section to denote the directory it resides in. I could even build a
> wizard in the app to help create the ini section itself.
>
> Hmmm, I will try that.
>
> Robert
>

That seems like a more troublesome implementation. You are forcing the
user to a) create an ini file, b) create some files on disk, and c) keep
the two in sync. Or am I reading something wrong?

If you just build your menu straight from the disk, all the user has to
do is b) create some files on disk.

I think I missed part of the thread -- why is doing the globbing so
difficult?

Here's a quick example of how to create a menu based on a folder
hierarchy and a file spec. It needs some error checking and perhaps some
sanity checking (eg: don't create cascade menus for directories with no
*.txt files), but it shows the general idea.

proc makeMenu {dir menu} {
set count 0
# create cascade menus for subfolders, and recurse
foreach subfolder [lsort [glob -nocomplain \
-directory $dir -type d *]] {
if {$subfolder eq "." || $subfolder eq ".."} continue
set name [file tail $subfolder]
set submenu [menu $menu.menu[incr count]]
$menu add cascade -label [string totitle $name] -menu $submenu
makeMenu $subfolder $submenu
}

# create commands for each .txt file
foreach file [lsort [glob -nocomplain \
-directory $dir -type f *.txt]] {
set name [file tail $file]
$menu add command -label [string totitle $name] \
-command [list showFile $file]
}
}

menu .menubar
. configure -menu .menubar
menu .menubar.courses
.menubar add cascade -label Courses -menu .menubar.courses
makeMenu [pwd]/Courses .menubar.courses

0 new messages