ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



19.7 Other Form Elements

Now that you know how to create simple text fields in your form and respond to them, you're probably wondering how to make the other kinds of widgets you've seen, like buttons, checkboxes, and menus.

Here's a more elaborate version of our program. We've thrown in some new widgets: popup menus, a submit button (named "order"), and a button to reset the entire form, erasing all user input. Popup menus are pretty much just what they say they are, but the arguments given to popup_menu may perplex you until you've read the following section on "References." The textfield() function creates a text-input field with the indicated name. We'll give more details about this function when describing the guestbook program later in this chapter.

#!/usr/bin/perl -w
# cgi-bin/ice_cream: program to answer and generate ice cream
# order form (version 4)
use strict; # enforce variable declarations and quoting
use CGI qw(:standard);

print header, start_html("Ice Cream Stand"), h1("Ice Cream Stand");
if (param()) { # the form has already been filled out
    my $who = param("name");
    my $flavor = param("flavor");
 my $scoops = param("scoops");
 my $taxrate = 1.0743;
 my $cost = sprintf("%.2f", $taxrate * (1.00 + $scoops * 0.25));
 print p("Ok, $who, have $scoops scoops of $flavor for \$$cost.");
} else { # first time through, so present clean form
    print hr(); # draw a horizontal rule before the form
    print start_form();
    print p("What's your name? ", textfield("name"));
    # FOR EXPLANATION OF FOLLOWING TWO LINES, SEE NEXT SECTION
    print p("What flavor: ", popup_menu("flavor", 
                                           ['mint','cherry','mocha']));
    print p("How many scoops? ", popup_menu("scoops", [ 1..3 ]));
    print p(submit("order"), reset("clear"));
    print end_form(), hr();
}
print end_html;

Figure 19.4 shows the initial screen it generates.

Figure 19.4: A slightly more elaborate fill-out form

Figure 19.4

As you'll recall, the param() function, when called without arguments, returns the names of all form-input fields that were filled out. That way you can tell whether or not the URL was called from a filled-out form. If you have parameters, then the user filled in some of the fields of an existing form, so respond to them. Otherwise generate a new form, expecting to have this very same program called a second time.

19.7.1 References

You may have noticed that the popup_menu() functions in the previous example both have a strange kind of argument. Just what are ['mint','cherry','mocha'] and [ 1..3 ] doing there? The brackets create something you haven't seen before: a reference to an anonymous array. That's because the popup_menu() function expects an array reference for an argument. Another way to create an array reference is to use a backslash in front of a named array, as in \@choices. So this

@choices = ('mint','cherry','mocha');
print p("What flavor: ", popup_menu("flavor", \@choices));

works just as well as this:

print p("What flavor: ", popup_menu("flavor", ['mint','cherry','mocha']));

References behave somewhat as pointers do in other languages, but with less danger of error. They're values that refer to other values (or variables). Perl references are very strongly typed (and uncastable), and they can never cause core dumps. Even better, the memory storage pointed to by references is automatically reclaimed when it's no longer used. References play a central role in object-oriented programming. They're also used in traditional programming, forming the basis for data structures more complex than simple one-dimensional arrays and hashes. Perl supports references to both named and anonymous scalars, arrays, hashes, and functions.

Just as you can create references to named arrays with \@array and to anonymous arrays with [ list ], you can also create references to named hashes using \%hash and to anonymous ones like this:[8]

{ key1, value1, key2, value2, ... }

[8] Yes, braces now have quite a few meanings in Perl. The context in which you use them determines what they're doing.

You can learn more about references in Chapter 4 of Programming Perl, or the perlref (1) manpage.

19.7.2 Fancier Calling Sequences

We'll round out the discussion of form widgets by creating a really fancy widget - one that allows the user to select any number of its items. The scrolling_list() function of CGI.pm can take an arbitrary number of argument pairs, each of which consists of a named parameter (beginning with -) and a value for the parameter.

To add a scrolling list to a form, here's all you need to do:

 print scrolling_list(
     -NAME => "flavors",
     -VALUES => [ qw(mint chocolate cherry vanilla peach) ],
     -LABELS => {
         mint => "Mighty Mint",
         chocolate => "Cherished Chocolate",
         cherry => "Cheery Cherry",
         vanilla => "Very Vanilla",
         peach => "Perfectly Peachy",
     },
     -SIZE => 3,
     -MULTIPLE => 1, # 1 for true, 0 for false
);

The parameter values have meanings as follows:

-NAME

The name of the widget. You can use the value of this later to retrieve user data from the form with param().

-LABELS

A reference to an anonymous hash. The values of the hash provide the labels (list items) seen by the form user. When a particular label is selected by the user, the corresponding hash key is what gets returned to the CGI program. That is, if the user selects the item given as Perfectly Peachy, the CGI program will receive the argument, peach.

-VALUES

A reference to an anonymous array. The array consists of the keys of the hash referenced by -LABELS.

-SIZE

A number determining how many list items will be visible to the user at one time.

-MULTIPLE

A true or false value (in Perl's sense of true and false) indicating whether the form user will be allowed to choose more than one list item.

When you've set -MULTIPLE to true, you'll want to assign param()'s return list to an array:

@choices = param("flavors");

Here's another way to create the same scrolling list, passing a reference to an existing hash instead of creating one on the fly:

%flavors = (
    mint => "Mighty Mint",
    chocolate => "Cherished Chocolate",
    cherry => "Cheery Cherry",
    vanilla => "Very Vanilla",
    peach => "Perfectly Peachy",
);
print scrolling_list(
    -NAME => "flavors",
    -LABELS => \%flavors,
    -VALUES => [ keys %flavors ],
    -SIZE => 3,
    -MULTIPLE => 1, # 1 for true, 0 for false
);

This time we send in values computed from the keys of the %flavors hash, which is itself passed in by reference using the backslash operator. Notice how the -VALUES parameter is still wrapped in square brackets? It wouldn't work to just pass in the result of keys as a list, because the calling convention for the scrolling_list() function requires an array reference there, which the brackets happily provide. Think of the brackets as a convenient way to treat multiple values as a single value.