, just means insert a few returns We also have to flush out any text prior to it: sub line_break { &flush_text(@_); $text->insert('end', "\n"); } Similar to
, the also just inserts a return: sub draw_line { &flush_text(@_); $text->insert('end', "\n -\n"); } The tag inserts a much nicer looking line in our normal web browser, but for our purposes, this set of dashes will accomplish pretty much the same thing: sub flush_text { $text->insert('end', $_[1]); } This function just inserts the text it's handed, as is: sub end_link { ## Don't want to add links to mailto refs if ($extra =~ /HREF\s*=\s*"(.+)"/ && $extra !~ /mailto/) { my $site = $1; ## The tags must have unique names to allow for a different ## binding to each one (Otherwise we'd just be changing that same ## tag binding over and over again.) my $newtag = "LINK" $cnt++; $text->tag('configure', $newtag, -underline => 'true', -foreground => 'blue'); $text->tag('bind', $newtag, '', sub { $text->configure(-cursor => 'hand2'); $INFORMATION = $site; }); $text->tag('bind', $newtag, '', sub { $text->configure(-cursor => 'top_left_arrow'); $INFORMATION = "";}); $text->tag('bind', $newtag, '', sub { &do_search($site); }); $text->insert('end', $_[1], $newtag); } else { &flush_text(@_); } } Our end_link( ) function is the most complicated, simply because we want to handle links If you look at the output from our dictionary server on your normal web browser, you'll notice that almost every single piece of text it returns is a link to look up another word I thought it would be easier to just click on those words and the lookup than to type in the word again and possibly spell it wrong We accomplish this by utilizing the text widget tags If you want the specific word to something different when you click on it, you have to create a new tag so we are creating tags on-the-fly (unlike our heading tags, which remained the same no matter where they were in the document, or what text they surrounded) We use a regexp to extract the URL from our $extra variable We create a new name for our tag (We never have to know what the name is again, so it's merely a place holder for the text widget.) We create our tag to change the text to be underlined and blue, much as a link would look in a full-blown web browser We also bind that tag to change the cursor into a little hand when we enter the tag, and to change it back to the standard pointer when we leave that section of text This gives the users some good feedback on the fact that they can something with it We also one other simple thing: we display the URL in our information area so that users will know what will happen when they click The last bind we perform is one that tells the application to call our function, do_search( ), with the URL we extracted from the HTML tag Then we insert the text for the link into the text widget, and associate it with the tag we just built Figure 7-2 xword window There are a few other things that could be added to xword to make it even nicer A Back button would be useful, so that after you looked up 10 or so words, you could click on Back to take you backwards through your selections And how about a list of optional dictionary web servers, in case one is sometimes slow or doesn't respond? These will be left as exercises for the reader Some limitations of the HTML parsing: We don't worry about nested HTML tags at all, and we don't worry about fancy things like tables or graphics Remember, we wanted to keep this simple Check on Package Delivery: Track Web browsers are great at what they do, but what if we want to query the same page for the same information several times in a row? We could just leave our browser up, and keep hitting "reload" n times, but we'd have to remember to it A better way would be to write a small application that automatically does our query for us every few minutes For this example, we'll interact with the Federal Express tracking page When you ship a package via FedEx, they keep track of it with a shipping number (also called an airbill number) and they have been kind enough to make available via the Web a place for us to check up on our packages If we look at their web page, they have a place to enter the airbill number, a place to select the destination country, and then a place to enter the date In order to mimic their form, we'll want to have all of these elements in our application FedEx has a specific way they want you to specify the country (in all caps, and spelled a particular way), so we just looked at their document source for the list of countries We will put them all in a listbox, to make it easier to select (instead of trying to guess at the spelling and/or punctuation) The tracking number is fairly easy it's just a bunch of numbers so a normal entry widget will For the date, another entry widget Their setup is designed to tell us if we enter an invalid date, so we'll let them handle the error checking on that one Now that we know the inputs, we have to decide what to with them Basically we want our program to keep looping and re-querying the site We really don't want our program to loop unless we tell it to, and we also want to be able to stop it from looping at any point Here's how we accomplish this with Perl/Tk: #!/usr/bin/perl -w use strict; use HTML::FormatText; use HTML::Parse; use Tk; my $query_interval = 30; # in minutes my $email = ""; my $url = "http://www.fedex.com/cgi-bin/track_it"; This is the basic beginning of a Perl/Tk script We recognize that we want to utilize some of the HTML modules, and of course, the Tk module We set up some basic globals in our program The $query_interval is in minutes you can change it to 60 minutes, or 15 minutes Try not to query too often, though; the status of your package is not likely to change every five minutes $email is your email address You need to put a "\" in front of the @ sign, so that it won't be interpreted by Perl to be something it's not This will inform the FedEx web site of who you are Finally, the $url is the destination where we'll be sending our request For this program, we are setting the amount of time it waits between loops in a variable In our next example, we'll show a way to allow the user to change it from the GUI my $mw = MainWindow->new; $mw->title("Package Tracker"); $mw->CmdLine; We created a window, gave it a title, and allowed the Tk portion to process any command-line options my @destinations = ("U.S.A.", "ALBANIA", "ALGERIA", "AMERICAN SAMOA ", "ANDORRA", "ANGOLA", "ANGUILLA", "ANTIGUA", "ARGENTINA", "ARMENIA", "ARUBA", "AUSTRALIA", "AUSTRIA", "AZERBAIJAN", "BAHAMAS", "BAHRAIN", "BANGLADESH", "BARBADOS", "BELARUS", "BELGIUM", "BELIZE", "BENIN", "BERMUDA", "BHUTAN", "BOLIVIA", "BOTSWANA", "BRAZIL", "BRITISH VIRGIN IS.", "BRUNEI", "BULGARIA", "BURKINO FASO", "BURUNDI", "CAMBODIA", "CAMEROON", "CANADA", "CAPE VERDE", "CAYMAN ISLANDS", "CENTRAL AFRICAN REP.", "CHAD", "CHILE", "CHINA", "COLOMBIA", "CONGO", "COOK ISLANDS", "COSTA RICA", "COTE D'IVOIRE", "CROATIA", "CYPRUS", "CZECH REPUBLIC", "DENMARK", "DJIBOUTI", "DOMINICA", "DOMINICAN REPUBLIC", "ECUADOR", "EGYPT", "EL SALVADOR", "EQUATORIAL GUINEA", "ERITREA", "ESTONIA", "ETHIOPIA", "FAEROE ISLANDS", "FIJI", "FINLAND", "FRANCE", "FRENCH GUIANA", "FRENCH POLYNESIA", "GABON", "GAMBIA", "GEORGIA, REPUBLIC OF", "GERMANY", "GHANA", "GIBRALTAR", "GREECE", "GREENLAND", "GRENADA", "GUADELOUPE", "GUAM", "GUATEMALA", "GUINEA", "GUINEA-BISSAU", "GUYANA", "HAITI", "HONDURAS", "HONG KONG", "HUNGARY", "ICELAND", "INDIA", "INDONESIA", "IRELAND", "ISRAEL", "ITALY", "JAMAICA", "JAPAN", "JORDAN", "KAZAKHSTAN", "KENYA", "KUWAIT", "KYRGYZSTAN", "LATVIA", "LEBANON", "LESOTHO", "LIBERIA", "LIECHTENSTEIN", "LITHUANIA", "LUXEMBOURG", "MACAU", "MACEDONIA", "MADAGASCAR", "MALAWI", "MALAYSIA", "MALDIVES", "MALI", "MALTA", "MARSHALL ISLANDS", "MARTINIQUE", "MAURITANIA", "MAURITIUS", "MEXICO", "MICRONESIA", "MOLDOVA", "MONACO", "MONGOLIA", "MONTSERRAT", "MOROCCO", "MOZAMBIQUE", "NAMIBIA", "NEPAL", "NETHERLANDS", "NEW CALEDONIA", "NEW ZEALAND", "NICARAGUA", "NIGER", "NIGERIA", "NETHERLANDS ANTILLES", "NORWAY", "OMAN", "PAKISTAN", "PALAU", "PANAMA", "PAPUA NEW GUINEA", "PARAGUAY", "PERU", "PHILIPPINES", "POLAND", "PORTUGAL", "QATAR", "REUNION ISLAND", "ROMANIA", "RUSSIA", "RWANDA", "SAIPAN", "SAN MARINO", "SAUDI ARABIA", "SENEGAL", "SEYCHELLES", "SIERRA LEONE", "SINGAPORE", "SLOVAK REPUBLIC", "SLOVENIA", "SOUTH AFRICA", "SOUTH KOREA", "SPAIN", "SRI LANKA", "ST KITTS & NEVIS", "ST LUCIA", "ST VINCENT", "SUDAN", "SURINAME", "SWEDEN", "SWAZILAND", "SWITZERLAND", "SYRIA", "TAIWAN", "TANZANIA", "THAILAND", "TOGO", "TRINIDAD & TOBAGO", "TUNISIA", "TURKEY", "TURKMENISTAN, REPUBLIC OF", "TURKS & CAICOS IS.", "U.A.E.", "UGANDA", "UKRAINE", "UNITED KINGDOM", "URUGUAY", "U.S VIRGIN ISLANDS","UZBEKISTAN", "VANUATU", "VATICAN CITY", "VENEZUELA", "VIETNAM", "WALLIS & FUTUNA ISLANDS", "YEMEN", "ZAIRE", "ZAMBIA", "ZIMBABWE"); ... standard web browser) sub start_heading { &flush_text(@_); $text->insert(''end'', "\n\n"); } When we start a heading, we need to delimit it from the prior text (which we insert into our text widget with. .. to call our function, do_search( ), with the URL we extracted from the HTML tag Then we insert the text for the link into the text widget, and associate it with the tag we just built Figure 7-2... every few minutes For this example, we''ll interact with the Federal Express tracking page When you ship a package via FedEx, they keep track of it with a shipping number (also called an airbill number)