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

My beloved and truly merciful monks:

Please hear my most pitiful plea. You have over graciously assisted me so many times. My ignorance is truly overwhelming. Could you be please be extra sympathetic to such a pathetic creature such as myself? If you find it in your infinite grace, please read the rest of my humble petition before you.

I am trying out the TK module (TK 804.028) on a Windows XP machine with Perl v5.10.0 installed, particularly the getopenfile dialog box command but I am having some difficulties trying to enable end users to be able to pick a file. I did try to read up on getopenfile,(reading extensively on the web and on PerlMonks, and I did go on the PerlMonks CB and tye did seem to narrow it down to my misunderstanding filehandler.

I had written a non-working program, Aggregating Lines from a CSV who lines match a particular field and save those matches based on that matching field name, that ikegami out of his extreme brilliance and genorosity, completely built anew for me. I must also commend a miracle that NetWallah was able to shrink it to a one liner.

Now what I want to do is have that program that ikegami wrote for me but now work with the getopenfile dialog box so that end users can run the program using the GUI instead of the DOS prompt. Here is the code:

#!/usr/local/bin/perl -w use Tk; use strict; use Tk::DialogBox; my $fh; my $last; my $file; my $main = MainWindow->new; #create Window $main->title('Menu'); my $menubar = $main->Menu(-type => 'menubar'); $main->configure(-menu => $menubar); my $file_menu = $menubar->cascade(-label => '~File', -tearoff => 0); $file_menu->command(-label => "Open", -accelerator => 'Ctl+O', -command => \&Open); my $text = $main->Text->pack(-fill => "both", -expand => 1); my $exit = $main->Button(-text => 'Exit', -command => [$main => 'destroy']); $exit->pack; my $types = [ ['CSV files', '.csv'], ['All Files', '*'], ]; MainLoop; sub Open { my $open = $main->getOpenFile(-filetypes => $types); open(File_Open, "< $open"); while (<>) { my ($file) = /^([^,]+),/; if (!defined($last) || $file ne $last) { open($fh, '>', "$file.txt") or die($!); } print $fh $_; $last = $file; } }

Do I admit that I have obviously used commands that I do not have any clue about. I am certainly guilty. Please give, for someone truly unworthy and fully remorseful, something that I am sure will be a rather easy for monks such as yourself, to give me the necessary enlightenment so I can get this program to work. I am at my wits ends.

Thank you very very much!

Replies are listed 'Best First'.
Re: GetOpenFile (Perl::TK 804.028) on v.5.10.0
by Util (Priest) on Dec 30, 2008 at 04:37 UTC

    To fix your main problem, just change while (<>) to while (<File_Open>) in your Open sub.
    The <> is a "null filehandle" (see "I/O Operators" in perlop), which would cause your program to seem to hang because it was waiting (silently) for keyboard input from the DOS window.

    Incidentally, 'Ctl+O' should be 'Ctrl+O', and you need to add this line to make the accelerator work:

    $main->bind("<Control-o>", \&Open);

    Also, here are some improvements to your Open sub; clearer names, tightened variable scope, and correctly handling the user <cancel>ing out of the Open dialog box:

    sub Open { my $csv_path = $main->getOpenFile( -filetypes => [ [ 'CSV files', '.csv' ], [ 'All Files', '*' ], ] ); return if not defined $csv_path; open my $csv_fh, '<', $csv_path or die "Cannot open '$csv_path': $!"; my $out_fh; my $last_filename = ''; while (<$csv_fh>) { my ($f) = /^([^,]+),/; my $filename = "$f.txt"; if ( $filename ne $last_filename ) { open $out_fh, '>', $filename or die "cannot open $filename: $!"; } print {$out_fh} $_; $last_filename = $filename; } }

      Dear Most Holy Util,

      You are so much smarter than me. Thank you for getting back to me so soon. You are truly

      AMAZING!!!

      I looked at the perlop and will read it super duper tomorrow. I REALLY APPRECIATE your genius!!!