padawan_linuxero has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks
I have being working on a project and one of the things is that I need to constantly check a folder or directory and see is there was any change like if theres a new file or if a file is delete it, I show the actual files on the directory, everything was cool, the program run great in DOS, but the thing is that my boss want it in a window form, so what I did its another program using Perl/Tk where it has 3 Listbox to show the contents of 3 diferent folders, the thing is that both programs run ok alone, when I try to join them into one, the program goes to "neverland". can you help me ? this is the code:
#!Perl $^W = 1; use strict; use File::Copy; use Date::Parse; use Date::Format; use Tk::DialogBox; use Tk::BrowseEntry; use Tk::ResizeButton; use Tk::ProgressBar; use Tk::LabFrame; use Tk::LabEntry; use Tk::ROText; use Tk::HList; use Cwd; use Tk; #Optional Modules# if ($^O eq 'MSWin32') { eval { require Win32::Console; Win32::Console::Free() }; if ($@) { warn "Win32::Console is not installed.\n$@"; } } #Declarations# my $VERSION = 2.7; my $loadhistory = 0; my $sort_cnt = 3; my ($ftp, $port, $after_id,); my $cwd = cwd; #Main# open STDERR, ">PFTPc.log" or warn "Cannot create PFTPc.log\a\n$!"; my $mw = MainWindow->new(-relief => 'raised', -bd => 2,); $mw->title("Asociacion de Agentes Aduanales de Matamoros --- Valida +cion Automatica"); $mw->geometry("1024x764+4+25"); &list_dir_enviar($mw); &list_dir_enviados($mw); &list_dir_respuesta($mw); $mw->Button(-text => "Salir", -command => sub { exit })->pack(-side => 'bottom'); &Tk::MainLoop(); ############################################################## sub list_dir_enviar { # my $mw = MainWindow->new; my $box = $mw->Listbox( -relief => 'sunken', -height => 5, -setgrid => 0, ); ########## Inicio de Directory Listen ############################ my $pollingInterval = 1; my $directoryToMonitor = "C:/test"; my %oldFileList = (); my %currentFileList = (); # we start by getting the file list, considered to be the "old" list # getFileList($directoryToMonitor, \%oldFileList); for (;;) { sleep($pollingInterval); # get the current file list and compare it to the old file list # if the lists differ, the current file list becomes the old file +list # and we FTP the files # getFileList($directoryToMonitor, \%currentFileList); if ( fileListsDiffer(\%oldFileList, \%currentFileList) ) { copyFileList(\%oldFileList, \%currentFileList); #dumpFileList(\%oldFileList); my @items = glob "c:/test/m*.*"; foreach (@items) { $box->insert('end', $_); } my $scroll = $mw->Scrollbar(-command => ['yview', $box]); $box->configure(-yscrollcommand => ['set', $scroll]); $box->pack(-side => 'left', -fill => 'both', -expand => 1); $scroll->pack(-side => 'right', -fill => 'y'); } # the FTP commands should go here instead of the dumpFileList() +function above } } # Basically prints the contents of a hash. # sub dumpFileList { my $list = shift; my @k = sort(keys(%$list)); for (my $i=0; $i<=$#k; $i++) { print $k[$i] . " " . $list->{$k[$i]} . "\n"; } print "\n"; } # Get a list of the files along with there modification times # from the specified directory. The results are place in the # specified hash where the key is the file name and the value # is that file's modification time. # sub getFileList { my $directory = shift; my $hash = shift; %$hash = (); opendir(DIR,$directory) || die "Can not open $directory"; my @files = grep(!/^\.\.?$/, readdir(DIR)); closedir(DIR); for (my $i=0; $i<=$#files; $i++) { $hash->{$files[$i]} = (stat("$directory/$files[$i]"))[9]; } } # See if two hashes of files differ. The hashes are considered differ +ent if one of the # following occurrs: # # 1. The hashes have different number of elements. # 2. The new hash is missing a key that is in the old hash. # 3. For a given key, the value in the old hash differs from the val +ue in the new hash. # sub fileListsDiffer { my $oldList = shift; my $newList = shift; my @oldKeys = (keys(%$oldList)); my @newKeys = (keys(%$newList)); if ($#newKeys != $#oldKeys) { return 1; } foreach my $key (@oldKeys) { if ( ! defined($newList->{$key}) || $newList->{$key} ne $oldList-> +{$key} ) { return 1; } } return 0; } # Copies one hash to another. The destination has ($to below) is empt +ied first. # sub copyFileList { my $to = shift; my $from = shift; %$to = (); foreach my $key (keys(%$from)) { $to->{$key} = $from->{$key}; } } ############ Final de Directory Listen ############################ ################################################################## sub list_dir_enviados { # my $mw = MainWindow->new; my $box1 = $mw->Listbox( -relief => 'sunken', -height => 5, -setgrid => 0, ); my @items1 = glob "c:/AAAvalida/valida/enviados/*.*"; #my @items = qw(One Two Three Four Five Six Seven Eight Nine Ten Eleve +n Twelve); foreach (@items1) { $box1->insert('end', $_); } my $scroll1 = $mw->Scrollbar(-command => ['yview', $box1]); $box1->configure(-yscrollcommand => ['set', $scroll1]); $box1->pack(-side => 'left', -fill => 'both', -expand => 1); $scroll1->pack(-side => 'right', -fill => 'y'); } ################################################################### sub list_dir_respuesta { # my $mw = MainWindow->new; my $box2 = $mw->Listbox( -relief => 'sunken', -height => 5, -setgrid => 0, ); my @items2 = glob "c:/AAAvalida/valida/respuestas/*.*"; #my @items = qw(One Two Three Four Five Six Seven Eight Nine Ten Eleve +n Twelve); foreach (@items2) { $box2->insert('end', $_); } my $scroll2 = $mw->Scrollbar(-command => ['yview', $box2]); $box2->configure(-yscrollcommand => ['set', $scroll2]); $box2->pack(-side => 'left', -fill => 'both', -expand => 1); $scroll2->pack(-side => 'right', -fill => 'y'); } ###################################################################### +###

Replies are listed 'Best First'.
Re: Need help with program using Perl Tk
by TGI (Parson) on May 05, 2008 at 19:50 UTC

    You are blocking in list_dir_enviar.

    You should never1 use sleep in a Tk script. It stops everything.

    Use after to schedule polling your directory.

    1There may be some case where it is desirable to use sleep in a Tk script, but I've never run across one and can't imagine what it would be.


    TGI says moo

Re: Need help with program using Perl Tk
by zentara (Cardinal) on May 05, 2008 at 20:02 UTC
    TGI is right on about avoiding sleep. However, since you are a beginner, I will say to use a "repeat" statement, instead of an "after". Essentially, they are the same thing, but repeat is a bit clearer for repetitive things, whearas after is usually used for a 1 time delay.
    my $repeater = $mw->repeat( $update_rate, \&Refresh, $somedata); #later to stop it $repeater->cancel

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: Need help with program using Perl Tk
by thundergnat (Deacon) on May 06, 2008 at 19:30 UTC

    As was previously mentioned, sleep() will be a problem while using Tk unless they are very short. After or repeat is the way to go. You might also want to think about abstracting out some of your repeated code for the various directories you are monitoring.

    Loosely based on your script (with large chunks ripped out)

    #!usr/bin/perl use strict; use warnings; use Tk; my @directories = ( 'c:/test', 'c:/test/more', 'c:/test/less' ); my ( %object, %files ); my $interval = 5; #seconds my $mw = MainWindow->new( -relief => 'raised', -bd => 2, -title => "Directory Monitor" ); $mw->geometry("800x600+4+25"); my $head_frame = $mw->Frame()->pack; my $main_frame = $mw->Frame()->pack( -fill => 'both', -expand => 1, ); $head_frame->Button( -text => "Salir", -command => sub { exit } )->pack; setup($_) for @directories; $mw->repeat( $interval * 1000, sub { monitor(@directories) } ); MainLoop; sub setup { my $dir = shift; $object{$dir}{frame} = $main_frame->Frame()->pack( -side => 'left', -fill => 'both', -expand => 1, -padx => 2, ); $object{$dir}{message} = $object{$dir}{frame}->Label( -text => ' ' + )->pack; $object{$dir}{label} = $object{$dir}{frame}->Label( -text => $di +r )->pack; $object{$dir}{listbox} = $object{$dir}{frame}->Scrolled( 'Listbox', -scrollbars => 'ose', -relief => 'sunken', -height => 5, -setgrid => 0, )->pack( -fill => 'both', -expand => 1 ); my ( $ok, @files ) = get_file_list($dir); if ($ok) { $files{$dir}{$_} = ( stat("$dir/$_") )[9], $object{$dir}{listbox}->insert( 'end', $_ ) for @files; } else { $object{$dir}{message} ->configure( -text => '*** COULD NOT READ DIRECTORY ***' ); } } sub monitor { my @directories = @_; for my $dir (@directories) { my @differences = file_lists_differ($dir); if (@differences) { $object{$dir}{message}->configure( -text => join "\n", @differences ); } } } sub get_file_list { my $directory = shift; opendir( DIR, $directory ) or return 0; my @files = grep( !/^\.\.?$/, readdir(DIR) ); closedir(DIR); return 1, @files; } sub file_lists_differ { my $dir = shift; my ( %new_files, %old_files, @modified ); $object{$dir}{message}->configure( -text => ' ' ); my ( $ok, @files ) = get_file_list($dir); if ($ok) { $new_files{$_} = ( stat("$dir/$_") )[9] for @files; %old_files = %{ $files{$dir} }; for ( keys %new_files ) { if ( defined $old_files{$_} ) { if ( $new_files{$_} eq $old_files{$_} ) { delete $old_files{$_}; next; } push @modified, "$_ modified"; delete $old_files{$_}; } else { push @modified, "$_ added"; } } for ( keys %old_files ) { push @modified, "$_ deleted"; } %{ $files{$dir} } = %new_files; } else { $object{$dir}{message} ->configure( -text => '*** COULD NOT READ DIRECTORY ***' ); } my @view = $object{$dir}{listbox}->yview; $object{$dir}{listbox}->delete( 0, 'end' ); $object{$dir}{listbox}->insert( 'end', $_ ) for @files; $object{$dir}{listbox}->yviewMoveto( $view[0] ); return @modified; }