The NoteTutorial Widget

Displaying a lot of information in a small space is often the biggest challenge given to GUI developers. The NoteTutorial widget is designed to help do just this. It allows us to have many pages of text, but lets only one be shown at a time. Each page in the NoteTutorial has a tab associated with it. The tab can display text or an image. Let's look at a simple example:

use Tk; $mw = MainWindow->new( ); # Create the notetutorial and fill the whole window $nb = $mw->NoteBook( )->pack(-expand => 1, -fill => 'both'); # Page 1 on the notetutorial, with button on that page $p1 = $nb->add('page1', -label => 'Page 1'); $p1->Button(-text => 'Click me!')->pack( ); # Empty page 2 $nb->add('page2', -label => 'Page 2'); MainLoop;

It creates a window with a NoteTutorial widget, shown in Figure 23-15. The notetutorial has two pages, named Page 1 and Page 2, respectively. Page 1 has a button on it, so the size of the NoteTutorial is determined by Page 1 (because it is the largest). Figure 23-15

Figure 23-15. Simple NoteTutorial example

Creating Pages

When you create a page in a NoteBook, you assign it a name using the add method. From then on, when calling NoteTutorial methods, you refer to that page by that name. In our example, we used page1 and page2 as the internal page names. The displayed label can either be the same or something completely different. It is important that you use different internal names for every single page in the NoteBook, or you'll get an error. Here are some examples using the add method:

$p = $notetutorial->add('internalname', -label => 'Displayed Name'); $p2 = $notetutorial->add('internalname2', -bitmap => 'bitmapname');

The first argument passed to add is the internal storage name of the page. There are several options that will determine how the tab information is displayed:

  • -anchor => anchordir
  • Anchors the text or image within the notetutorial tab. Values are: 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', or 'center'.
  • -bitmap => bitmap
  • A bitmap to use on the tab, instead of a label.
  • -image => imageptr
  • An image to display instead of a label. Overrides both -bitmap and -label.
  • -label => string
  • A string with which to label the tab.
  • -justify => 'left' | 'right' | 'center'
  • Direction for the text to justify within the tab.
  • -createcmd => callback
  • A callback that is invoked the first time the page is shown. This is useful if you have a lot of processing that can be delayed.
  • -raisecmd => callback
  • Invoked every time the page is shown to the user.
  • -state => 'normal' | 'disabled'
  • The state of the page.
  • -underline => index
  • Which character to underline in the tab. Starts at 0.
  • -wraplength => length
  • The maximum length of a line of text on the tab.

Once the page is created, you still need to put something on it. Use the reference returned by the add method and create widgets using that reference as the parent widget.

There are three ways to put something on a page:

  • Using MainLoop when you create the page, before the window is displayed.
  • Using the -createcmd option, which creates the page the first time the user clicks on that tab.
  • Using the -raisecmd, which can change what is displayed on the page every time the user raises that page.

To delete a page, use the delete method and pass it the internal name of the page:

$notetutorial->delete("page1");

There are two methods used to get and set information associated with a page: pagecget and pageconfigure. Both methods will work only with the same options that can be used with the add method.

To get the value of an individual option, use pagecget:

$state = $notetutorial->pagecget("pagename", -state);

To change the value of one or more options, use pageconfigure:

$notetutorial->pageconfigure('pagename', -label => 'new label'); $notetutorial->pageconfigure('pagename', -label => 'new label', -underline => 3);

You can cause a page to be displayed (or raised) by using the raise method:

$notetutorial->raise("page4"); ## OR check to see if that page is already showing: $page = $notetutorial->raised( ); if ($page ne "page4") $notetutorial->raise("page4");

WordCount Example Using a NoteBook

A NoteTutorial allows us to display data in an organized fashion. In this example, we are going to parse through some files (passed in as command-line parameters) and index out all the words contained within the files. The resulting window is shown in Figure 23-16; the code follows. Figure 23-16

Figure 23-16. WordCount results displayed using a NoteBook

Half of the following code preps the list of words to display and the other half does the work of displaying it. To sort the words, we use a hash based on the first character in each word.

use Tk; require Tk::NoteBook; $mw = MainWindow->new( ); # Show the user the names of files we are parsing # This might end up too long to see it all $mw->title('Word Count:' . join (',', @ARGV)); # Use a courier font to display the tab text $nb = $mw->NoteBook(-font => 'Courier 10 bold')->pack; my %textWidgets; %seen = ( ); while (<>) {
 while ( /(\w['\w-]*)/g) {
 $seen{lc $1}++;
}
} # go through the index in order and create the tabs and text widgets. foreach my $word (sort (keys %seen)) {
 if ($word =~ /^(.)/) {
 $letter = $1; $t = $textWidgets{$letter};
 # Create the text widget if it doesn't already exist if (! defined $t) {
 my $p = $nb->add($letter, -label => $letter); $t = $p->Scrolled("Text")->pack(-expand => 1, -fill => 'both'); $textWidgets{$letter} = $t;
}
$t->insert("end", $seen{$word} . " " . $word . "\n");
}
} MainLoop;

NoteTutorial Limitations

You can't have the tabs for a NoteTutorial automatically wrap around and make more than one line of tabs. Consequently, you might make so many tabs that your window will be too big to be displayed properly. In that case, you might consider having a page contain another NoteTutorial widget, which will essentially give you two rows of tabs.

In order to disable a tab page, the recommended solution is to use an InputO widget, which covers everything on that tab page. However, InputO isn't supported on Win32 systems.