If you have code that actually runs, you should paste the relevant part of the running code when you post (or at least be more careful about typing/pasting it in). What you have here has some glaring errors. Update as you see fit (and mention what you've updated), but when I first saw this post, there were the following problems:
- The first curly brace is a close-brace, not an open-brace -- it doesn't compile.
- You have "opendir(SPAM...)" followed by "close(SPAM)", not "closedir(SPAM)" -- maybe that actually works, but it just seems wrong.
- Is "%temp" actually a global hash (like $mw appears to be a globally declared "MainWindow" widget)? If not, it isn't being declared with "my" where it should be. Likewise for $new in "sub view". (Does the script "use strict", or not? If not, try it, please.)
- You aren't checking for success or errors when opening files in the "view()" sub -- likewise for opening the directory.
As for the symptom -- the buttons appear to be labeled as intended, but you aren't seeing the file name or its contents in the new Toplevel window when you hit a button -- well, it's hard to comment on this, because you say your code runs, but what you've posted won't run, so you haven't posted the code that produces that symptom.
Anyway, you might try initializing the "-command" parameter on the button like this:
...
-command => [ \&view, $open ],
...
This way, the "-command" option gets a reference to an anonymous array; the first element of the array is a reference to a subroutine to be run when the button is clicked, and subsequent elements in the array (one in this case) are parameters to be passed to the subroutine in @_. | [reply] [d/l] |
Foreach Loops
The "foreach" loop iterates over a normal list value and sets
the variable VAR to be each element of the list in turn. If
the variable is preceded with the keyword "my", then it is
lexically scoped, and is therefore visible only within the
loop. Otherwise, the variable is implicitly local to the
loop and regains its former value upon exiting the loop. If
the variable was previously declared with "my", it uses that
variable instead of the global one, but it's still localized
to the loop. This implicit localisation occurs only in a
"foreach" loop.
The variable $open is local to the loop and regains its former value at the end of the loop. You're calling &view with a localized package variable that is uninitialized.
Use a lexical iterator instead so that the anonymous subroutine definition keeps a reference to the $open that exists at the time of the definition. Change this:
foreach $open (@deleted)
{
....
}
to this:
foreach my $open (@deleted)
{
...
}
| [reply] [d/l] [select] |
UPDATE: Well, I don't know for sure if it was the additon of the my because I found some other errors too, but the whole thing works as planned now!
THANX!!
I was working on another computer at the time so I didn't have the whole code with me, I typed in the part that I had a problem with. I will post the entire code here.
I also included the second suggestion to add the my into the for loop itself, same result. It names the button properly, but it doesn't pass the argument to the subroutine VIEW.
-Kevin | [reply] [d/l] |
So, you've posted the version that actually works as intended? No way for any of us to tell, since the code is, um, quite "personalized". Anyway, you might enjoy a few tricks for reducing the amount of repetition:
my %black_on_tan = (-fg=>'black',
-bg=>'tan',
-activebackground=>'blue',
-activeforeground=>'red');
my %black_on_yel = (-fg=>'black',
-bg=>'yellow',
-activebackground=>'yellow',
-activeforeground=>'black');
# ...
my $see_list=$w->Button(-text=>'See Deleted List', %black_on_tan);
# likewise for other buttons...
Next, all those ugly regex tests on the output of "ps -ef | grep ..." can certainly be simplified -- look up the unix man page for "ps" to see how you can control what it prints, and just have it print the info you need. And, as with the attribute hash example above, assign the needed regex to a scalar variable, and use the scalar in your various "if" statements.
Alternatively, if this GUI is the only thing you use to start and stop the "check.pl" and "email.pl" scripts, try starting them like this, and avoid using ps altogether:
my %pid; # this should have global scope
sub start_proc
{
my $proc = shift; # use one sub for both jobs
return if ( $pid{$proc} ); # already set means it's running
$pid{$proc} = fork;
if ( $pid{$proc} == 0 ) { # true for the child process
$path = ( $proc eq "email" ) ? $spam_dir : $check_dir;
exec "perl $path/$proc.pl";
}
# in the parent, $pid{$proc} is >0
}
sub stop_proc
{
my $proc = shift;
return unless ( $pid{$proc} );
`kill -9 $pid{$proc}`;
$pid{$proc} = 0;
}
I haven't tested that, and it may be inappropriate if these jobs have a tendancy to die unexpectedly, or are liable to be started from outside the GUI. But it should at least give some ideas about writing less redundant code.
(Actually, by starting the jobs with "fork", it becomes easier to check their status at any time afterwards, because you know what pid to look for -- e.g. you could use "ps -p $pid{$proc}", and just look for $pid{$proc} in its output -- if the pid doesn't show up there, it's not running.) | [reply] [d/l] [select] |