in reply to Perl/Tk while {1} and a responsive UI

I think you're looking for "repeat" in Tk::after. You can schedule your code to execute every "n" milliseconds, and let the event loop dispatch it as needed. Your mouseclicky thing will simply delete the event, so it won't get called any longer.

-- Randal L. Schwartz, Perl hacker
Be sure to read my standard disclaimer if this is a reply.

  • Comment on Re: Perl/Tk while {1} and a responsive UI

Replies are listed 'Best First'.
Re^2: Perl/Tk while {1} and a responsive UI
by ady (Deacon) on Apr 24, 2005 at 15:45 UTC
    So here's the state of the Full Monty, incl. the TK callback solution (as suggested by Randal L. Schwartz) --under the heading of "GUI (TK)".
    The app is a further hack of the code in 443617, all for fun & no profit.
    There's still a lot of polishing left, including a possible refactoring to allow a table driven config (reading Mark Dominus' HOP at the moment...:)

    (Update apr.26: made a couple of regex'es more robust...)
    #!/usr/bin/perl -w # polls what's current playing on radio KOIT in San Francisco, # get the lyrics from lyricsbox.com # TODO: (1) make the title search a little fuzzier # (2) search more sites for lyrics # (3) nicer interface? color, scrolling? # ==================================================================== # Pragmas & Libs use strict; use LWP::Simple; use URI::Escape; use Time::Local; use HTML::Entities; # Main vars my @lyrics = (\&lyrics_matrix, \&lyrics_seeklyrics, \&lyrics_musicsong +); my $rlyrics = \@lyrics; my @channels = ( ["TEST", \&nowplay_TEST], ["KOIT", \&nowplay_KOIT], ["HITZ", \&nowplay_HITZ] ); my $TRACE = 1; # =================================================================== # Text UI (STDOUT) # =================================================================== select((select(STDOUT), $| = 1)[0]); # Autoflush STDOUT my $sleep = 60; # Poll once/min =cut #print play_station(\&nowplay_TEST, $rlyrics); while (1) { print play_station(\&nowplay_KOIT, $rlyrics); print play_station(\&nowplay_HITZ, $rlyrics); sleep $sleep; # Wait & retry } =cut # =================================================================== # GUI (TK) # =================================================================== use Tk; my $mw = MainWindow->new(); $mw->minsize(qw(100 20)); $mw->maxsize(qw(600 700)); my $list; $list= $mw->Scrolled("Listbox", -height=>5, -scrollbars=>"e" +) ->pack(qw/-fill x/); $list->bind("<1>", sub { do_lyrics($list->curselection()) }); $list->bind("<3>", sub { $rlyrics = ($rlyrics ? undef() : \@lyric +s); do_lyrics($list->curselection())} ); for (@channels) { $list->insert("end", $_->[0]); } my $detail; sub detail_add { $detail = $mw->Scrolled("Text", -height=>20, -width => 40, -scrollbars=>"se", -wrap=>'none')->pack(qw/-fill both -expand 1/); } # ------------------------------------------------------------------- MainLoop; sub do_lyrics { my $idx = shift; $detail->destroy if Tk::Exists($detail); detail_add(); reset_station($idx); lyrics($idx); $detail->repeat(60000, sub { lyrics($idx); } ); } sub lyrics { my $lyrics = play_station($channels[$_[0]]->[1], $rlyrics); $detail->insert("end", $lyrics); $detail->see("end"); } # =================================================================== # Play station # =================================================================== my %current; # Map Statiom -> current $artist$title ("class + data") sub play_station { my ($station, $rlyrics) = @_; my ($artist, $title, $tdif) = $station->(); # Now playing on $stat +ion.. unless ($artist and $title) { return "*"; } my $ret; if (!defined($current{$station}) or $current{$station} ne "$artist +$title") { $ret = build_header($artist, $title, $tdif); $current{$station} = "$artist$title"; for (@$rlyrics) { # Probe @lyrics sites +for texts if ( my $ly = $_->($artist,$title) ) { $ret .= "$ly\n"; last unless ($TRACE or $ly =~ /Not Foun +d/i); } } } else { $ret = "." } return $ret; } sub reset_station { delete($current{$channels[shift]->[1]}); } # ------------------------------------------------------------------- sub build_header { my ($artist, $title, $tdif) = @_; my $hdr = "\n" . "-"x50 . "\n"; my $LOC=time(); $tdif ||= 0; my $STA=$LOC+($tdif*60*60); $hdr .= "LocalTm: " . scalar(localtime($LOC)) . "\n"; $tdif and $hdr .= "Station: " . scalar(localtime($STA)) . "\n\n"; $hdr .= "[$artist]: [$title]\n\n"; return $hdr; } # =================================================================== # Stations # =================================================================== sub nowplay_TEST { my @case = ( ["Bryan Adams", "(everything I Do) I Do It For You"], ["Backstreet Boys", "I'll Never Break Your Heart"], ["Roxette", "It Must Have Been Love"], ); my ($artist, $title) = ($case[0][0], $case[0][1]); for (\$artist, \$title) { clean_at($_); } return ($artist, $title); } # ------------------------------------------------------------------- sub nowplay_KOIT { my $url = "http://koit.com/nowplay_data.cfm"; my $tdif = -9; # cf Copenhagen my $data = get($url); my ($artist, $title) = $data =~ m|box=(.+) - (.+)&|; for (\$artist, \$title) { clean_at($_); } return ($artist,$title,$tdif); } # ------------------------------------------------------------------- sub nowplay_HITZ { my $url = "http://hitzradio.com/"; my $data = get($url); my ($artist, $title) = $data =~ m|<span id="nowplaying">(.+) - (.+ +)</span>|; for (\$artist, \$title) { clean_at($_); } #??for ($artist,$title) { s/\(.*?\)+//g; s/\(.*//g; } return ($artist,$title); } # =================================================================== # Lyrics # =================================================================== sub lyrics_lyricsbox { # Pt Broken... my ($artist, $title) = @_; my $lyricsbox = "http://www.lyricsbox.com"; my $lyrics_list = "$lyricsbox/cgi-exe/am.cgi?a=search&p=1&l=artist +&s="; my $list = get($lyrics_list.uri_escape($artist)); my ($song, $ly); my ($url) = $list =~ m|<A href="([^"]+)">\Q$title\E.*?</A></td>|i +; if ($url) { $song = get($lyricsbox.$url); } if ($song) { ($ly) = $song =~ m|<PRE.*?>(.+)</PRE>|si; } return "LyricsBox: " . ($ly ? $ly : "Not Found..."); } # ------------------------------------------------------------------- sub lyrics_matrix { my ($artist, $title) = @_; for ($title) { s/\s/_/g; s/\'//g; } my $t = lc(substr($title,0,1)); my ($url, $ly) = ("http://www.ntl.matrix.com.br", ""); foreach my $try ("html/lyrics/$t", "oldies_list/top/lyrics") { $url .= lc("/pfilho/$try/${title}.txt"); $TRACE and print "[$url]\n"; $ly = get($url); last if $ly; } if ($ly) { $ly = clean_ly($ly); } return "Matrix: " . ($ly ? $ly : "Not Found..."); } # ------------------------------------------------------------------- sub lyrics_musicsong { my ($artist, $title) = @_; my $a = ($artist =~ /^\d+/ ? "0" : uc(substr($artist,0,1))); for ($artist,$title) { s/\s//g; s/ & //g; s/(.*)/\L$1/g; } my ($url, $song, $ly) = ("http://www.musicsonglyrics.com", "", "") +; $url .= "/$a/${artist}lyrics/$artist${title}lyrics.htm"; $TRACE and print "[$url]\n"; $song = get($url); eval { if ($song) { ($ly) = $song =~ m|<span.*?>(.+)</span>|si; } }; $@ and warn $ly = "Parse error: $@ \n"; if ($ly) { $ly = clean_ly($ly); } return "MusicSong: " . ($ly ? $ly : "Not Found..."); } # ------------------------------------------------------------------- sub lyrics_seeklyrics { my ($artist, $title) = @_; for ($artist,$title) { s/^\s+//; s/\s+$//; } my ($a, $t) = ($artist, $title); for ($artist,$title) { s/(['\w]+)/\u\L$1/g; s/('|\s)+/-/g; } my ($url, $song, $ly) = ("http://www.seeklyrics.com", "", ""); for my $try ($artist, uc($artist)) { $url .= "/lyrics/$artist/$title.html"; $song = get($url); $TRACE and print "[$url]\n"; last if $song; } eval { if ($song) { ($ly) = $song =~ m|<b>$a - $t Lyrics</b>\s*<pre>(.*?)</pre|si; + } }; $@ and warn $ly = "Parse error: $@ \n"; if ($ly) { $ly = clean_ly($ly); } return "SeekLyrics: " . ($ly ? $ly : "Not Found..."); } # ------------------------------------------------------------------- sub lyrics_007 { # <To-Be-Done> my $lyrics007 = "http://www.lyrics007.com"; # http://www.lyrics007.com/<artist>%20Lyrics/<title>%20Lyrics.html # where <artist> & <title> spaces & specs are %20 encoded } # ------------------------------------------------------------------- # <To-Be-Done> # http://www.lyricsspot.com/ # ------------------------------------------------------------------- # =================================================================== # Utils # =================================================================== sub clean_at { my $rat = shift; for ($$rat) { s/^\W+//g; s/[()]//g; s/\W+$//g; } } # ------------------------------------------------------------------- sub clean_ly{ my $ly = shift; for ($ly) { s/<.*?>//gi; decode_entities($_); # HTML tags & char enc +oding s/^\s+//; s/\s+$//; # Strip WS s/(\x0D)*\n/\n\t/g; s/\x92/\x27/g; # Handle NL & ' tr/\200-\377/*/s; # Zap 8bit chars } return $ly; } # END