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

Dear Monks:

I am working on a program to display the contents of a folder and this program needs to check every 5 seconds to folder and put the contents on a Listbox I am using Perl / Tk to do it graphic, yesteday asking about other problem they notice I was using a Sleep and as they told me Sleep does not go well with Tk, so they recommended to use Tk::After and after looking in my book "Mastering Perl/Tk" in Time Delays I saw Repeat which works ok, the thing is that my knowledge is limited and right now every time it runs the program, it creates a new Listbox every 5 seconds, how can I told the Listbox to list the data in the same Listbox instead of openinng a new Listbox every 5 seconds. Can you please help ? this is the code so far :
#!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"); my $respuesta; &user_input($mw); &create_dropdown($mw); &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 { $mw->repeat(5000, \&refresh1); } ################################################################## 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'); } ###################################################################### +### sub refresh1 { my $box = $mw->Listbox( -relief => 'sunken', -height => 5, -setgrid => 0, ); my @items = glob "c:/test/*.*"; #my @items = qw(One Two Three Four Five Six Seven Eight Nine Ten Eleve +n Twelve); 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'); } sub user_input { my $mother = shift; my $label_wert = $mw->Label( -text => 'Tu respuesta :', )->place( -x => 10, -y => 10); my $entry_wert = $mw->Entry( -width => 20, )->place( -x => 80, -y => 10); } sub create_dropdown { my $mother = shift; # Create dropdown and another element which shows my selection my $dropdown_value; my $dropdown = $mother->BrowseEntry( -label => "Label", -variable => \$dropdown_value, )->pack; my $showlabel = $mother->Label( -text => "nothing selected", )->pack; # Configure dropdown $dropdown->configure( # What to do when an entry iws selected -browsecmd => sub { $showlabel->configure(-text => "Ha seleccionado: $dropdown +_value" ), }, ); # Populate dropdown with values foreach ( qw/Enviados Recibido Errores/ ) { $dropdown->insert('end', $_); } # Set the initial value for the dropdown $dropdown_value = "Enviados"; }

Replies are listed 'Best First'.
Re: Problem with Tk::Repeat
by zentara (Cardinal) on May 06, 2008 at 18:59 UTC
    moritz is right. Since you are a beginner, here is some more help. Make your listboxes as globals, then empty them and refill. Also, you probably don't need to make your scrollbars as separate widgets....thats the hard way. Use the Scrolled widget
    my $box = $mw->Scrolled('Listbox', -scrollbars => 'osoe', #only show bars if needed -relief => 'sunken', -height => 5, -setgrid => 0, );
    The only time you need to address the scrollbars as separate widgets, is if you want to position them manually from within the program, or have dual linked scrollbars. But even then, you can get the bar from the subwidget method.
    my $xscrollbar = $scrolled_box->Subwidget('xscrollbar');

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: Problem with Tk::Repeat
by moritz (Cardinal) on May 06, 2008 at 17:50 UTC
    You are calling the sub refresh1 repeatedly, and that sub creates a new Listbox every time it runs.

    A possible solution is to build that Listbox outside the function, and in refresh1 you just delete each element of the listbox, and fill it again.

    BTW it would help if your sub names were consistently in English ;-), that way a reader would only need to know one human language to understand the code.

Re: Problem with Tk::Repeat
by TGI (Parson) on May 06, 2008 at 19:23 UTC

    The main thing to remember with Tk (or any GUI coding), is that you start out by creating a bunch of widgets, then you start the program running and the widgets need to respond to things that happen (events). This model is referred to as 'event driven programming'. It's a bit different than writing console apps, and takes some getting used to.

    Creating and destroying widgets in Tk leads to memory leakage. You need to keep your widgets around and reuse them instead of destroying them.

    I noticed you had "use Tk::ProgressBar" in your example code. I've had big problems with memory leaks using ProgressBar widgets with Tk 804.027. YMMV.

    I've hacked at your code a bit to make it work and refashion it a bit after my own style. There are things I'd still change (like naming things by purpose rather than 'Box_One'), but it works and should provide a good starting point.

    #!Perl #$^W = 1; # is there a reason why you don't just use warnings? use strict; use warnings; use Tk; use Tk::BrowseEntry; use Cwd; use List::Util qw(shuffle); #Declarations# my $VERSION = 2.7; my $loadhistory = 0; my $sort_cnt = 3; my ($ftp, $port, $after_id,); my $cwd = cwd; my $mw = MainWindow->new( -relief => 'raised', -bd => 2, ); $mw->title("Asociacion de Agentes Aduanales de Matamoros --- Validacio +n Automatica"); $mw->geometry("1024x764+4+25"); # Make all your widget groups my $entry = Build_User_Entry($mw); my $dd = Build_Dropdown($mw); my $box1 = Build_Listbox_One($mw); my $box2 = Build_Listbox_Two($mw); my $button = Build_Exit_Button($mw); # Lay them out - use only one geometry manager per containing frame. $entry->grid( -columnspan => 2 ); $dd->grid( -columnspan => 2 ); $box1->grid( $box2 ); $button->grid( -columnspan => 2 ); # Start monitoring my ($enviados, $respuestas) = Start_Directory_Monitors( $mw, $box1, $b +ox2 ); MainLoop(); ################################################### # Build widgets sub Build_User_Entry { my $mw = shift; my $f = $mw->Frame(); my $label_wert = $f->Label( -text => 'Tu respuesta :', )->pack( -side => 'left', ); my $entry_wert = $f->Entry( -width => 20, )->pack( -expand => 1, -fill => 'y', ); return $f; } sub Build_Dropdown { my $mw = shift; my $f = $mw->Frame(); my $label_text = "nothing selected"; my $dropdown_value; my $showlabel = $f->Label( -textvariable => \$label_text, ); my $dropdown = $f->BrowseEntry( -label => "Label", -variable => \$dropdown_value, -browsecmd => sub { $label_text = "Ha seleccionado: $dropdown_value"; }, ); # Populate dropdown with values foreach ( qw/Enviados Recibido Errores/ ) { $dropdown->insert('end', $_); } # Set the initial value for the dropdown $dropdown_value = "Enviados"; $showlabel->pack; $dropdown->pack; return $f; } sub Build_Listbox_One { my $mw = shift; my $box1 = $mw->Scrolled( 'Listbox', -scrollbars => 'e', -relief => 'sunken', -height => 5, -setgrid => 0, ); return $box1; } sub Build_Listbox_Two { my $mw = shift; my $box2 = $mw->Scrolled( 'Listbox', -scrollbars => 'e', -relief => 'sunken', -height => 5, -setgrid => 0, ); return $box2; } sub Build_Exit_Button { my $mw = shift; my $button = $mw->Button( -text => "Salir", -command => sub { exit }, ); return $button; } ############################################################## sub Start_Directory_Monitors { my $mw = shift; my $enviados_display = shift; my $respuesta_display = shift; my $env = $mw->repeat(5000, [ \&list_dir_enviados, $enviados_disp +lay ] ); my $res = $mw->repeat(5000, [ \&list_dir_respuesta, $respuesta_dis +play ] ); return $env, $res; } # monitor enviados sub list_dir_enviados { my $box = shift; $box->delete(0,'end'); # empty listbox #my @items = glob "c:/AAAvalida/valida/enviados/*.*"; my @items = shuffle qw(One Two Three Four Five Six Seven Eight Nin +e Ten Eleven Twelve); foreach (@items) { $box1->insert('end', $_); } } # monitor respuestas sub list_dir_respuesta { my $box = shift; $box->delete(0,'end'); # empty listbox #my @items = glob "c:/AAAvalida/valida/respuestas/*.*"; my @items = shuffle qw(One Two Three Four Five Six Seven Eight Nin +e Ten Eleven Twelve); foreach (@items) { $box->insert('end', $_); } } ###################################################################### +###


    TGI says moo

      Thank you all for helping me this is a better way
      but one question :
      how can I make the listbox bigger? because they are to small right now

      thanks

        You can adjust the size of the listbox by configuring its -height and -width.

        You can also allow the geometry manager to control a widget's size. For pack, you set -fill and -expand options when you pack the widget. For grid, you set the -sticky option to cause the widget to grow to fill the grid cell. You can also use gridRowconfigure and gridColumnconfigure with the -weight option to make a row/column expand as a window is resized.

        Here's a snippet you can paste in to replace line 38 of the code above:

        $box1->grid( $box2, -sticky => 'ns' ); $mw->gridRowconfigure(2, -weight => 1 );

        It's worth the time to really dig into and understand the pack and grid geometry managers. I've played with the other managers, but have never needed anything else for a real project.


        TGI says moo

        Thats why pack is the preferred geometry manager. You can use
        my $lb=$mw->Scrolled('Listbox')->pack(-fill=>'both', -expand=>1);
        and the listbox will grow in size to fill as much space as it can. It will auto-adjust size too, if you resize the window.

        Learning to use pack is definitely worth the time..... it takes a Saturday afternoon of time to get used to it's behavior, but it saves time and headaches in the long run. Grid has a more complex method called "weight".... but I always use pack.


        I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: Problem with Tk::Repeat
by thundergnat (Deacon) on May 07, 2008 at 15:39 UTC

    Did you try running the script I gave you in reply to your previous question? It addressed many of these issues. Sigh.

    Here it is again, further refined.

      UPDATE No download problem, it downloads fine, but when I run a dos2unix program on it to convert to unix line endings, it cuts it off? Investigating why.

      This is an odd problem, but when I download your code, it gets cut off at

      sub deaccent{ my $phrase = shift; return $phrase unless ($phrase =~ y/\xC0-\xFF//); $phrase =~ tr/ÀÁÂÃÄÅàáâãäåÇçÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖØòóôõöøÑñÙÚÛÜùúûü +Ý # download cuts off here.? Update no problem, my dos2unix software was doing it, when I changed l +ine endings
      Maybe there is some binary weirdness causing an EOF?

      I'm not really a human, but I play one on earth. Cogito ergo sum a bum