I am working on a Perl Tkx application and I am having trouble getting useful/correct error messages. I am attempting to use croak so it will tell me exactly where it fails, but every time it croaks it just says the error is located "at C:/Perl64/lib/Tkx.pm line 347."
I have written a very simple script to demonstrate what is happening:
#!/usr/bin/perl
use strict;
use warnings;
use Carp;
use Tkx;
my $mw = Tkx::widget->new(".");
my $b = $mw->new_button(
-text => "Hello, world",
-command => sub { croak; },
);
$b->g_pack;
Tkx::MainLoop();
When I run this script and click the button I get the following popup box:
How can I make Tkx handle errors similar to using croak in a regular Perl script? is there a way to force croak to print to STDOUT or STDERR?
EDIT:
Michael Carman brings up a good point that generally with a GUI the console will be suppressed and the user will never see an error sent to STDOUT or STDERR, but what about finding a way to modify the text in the "Application Error" dialogue box to say something useful? Is that possible?
The text doesn't necessarily have to be useful to the end user, but should at least be understandable by the programmer so they know where to look for the issue when it is reported by the end user.
EDIT2:
Okay it appears that using die
or confess
instead of croak
prints a more useful error message to the "Application Error" window, but once I click "OK" the program just continues and doesn't actually die. How can I "kill it until it's dead" and make sure it stays dead?
POSSIBLE SOLUTION:
Here is a possible solution built off of Michael Carman's response. I modified it slightly because I think a messageBox looks a little bit nicer :)
#!/usr/bin/perl
use strict;
use warnings;
use Tkx;
use Carp;
my $mw = Tkx::widget->new(".");
my $b = $mw->new_button(
-text => "Hello, world",
-command => sub { die "uh-oh"; },
);
$b->g_pack;
Tkx::eval(<<'EOT');
proc bgerror {message} {
tk_messageBox -title "Application Error" -message $message -icon error -type ok
destroy .
}
EOT
Tkx::MainLoop();
So far this is the best solution but 5 days still remain in the bounty so keep those answers coming!
croak
reports errors from the perspective of the caller. Use die
to report errors from the perspective of your code.
croak
is typically used when writing modules so that you can report problems in the way your code is used. (e.g. for argument validation) GUI programming is sort of a mirror image of this. Instead of writing a library for someone else to use, you're injecting your code into a library that was written by someone else. When you pass a code reference to -command
the caller becomes Tkx, so it's better to report any errors from the perspective of your code.
Tkx catches fatal errors in callbacks and reports them via the "Application Error" dialog you're seeing. It's not uncommon for GUI applications to be disconnected from the console, meaning that STDOUT and STDERR are closed and any messages written to them are lost. Without the dialog your application would simply vanish and the user would have no clue as to why.
e.g.
use Tkx;
my $mw = Tkx::widget->new(".");
my $b = $mw->new_button(
-text => "Hello, world",
-command => sub { die "uh-oh" },
);
$b->g_pack;
Tkx::MainLoop();
When I run this (and press the button) the dialog message is
uh-oh at c:\temp\foo.pl line 9.
If you need full control over how Tk handles errors you can override the default handler. The catch is that you have to do it in Tcl. Here's a minimal version to create a dialog with the error message and exit the application when it's closed.
Tkx::eval(<<'EOT');
proc bgerror {message} {
tk_dialog .error "Error" $message [] 0 Close
destroy .
}
EOT