sub push_button2
{
$but2->configure(-state => 'disabled');
open(launch, "+>C:\integration\check_label\launch_check_label.bat") or die "Couldn't open file launch_check_label.bat$!";
print launch "$ARGV[1]:n";
print launch "perl C:\integration\check_label\check_label.pl $ARGV[0] $ARGV[1] $text";
system("start C:\integration\check_label\external_command.bat");
$but2->configure(-state => 'normal');
}
上面的代码片段没有工作,它只禁用了按钮几毫秒,甚至在批处理文件运行之前,按钮就立即激活了。
在执行system
命令之前没有关闭launch
如果对launch
文件句柄的输出被缓冲(通常为4KB),那么在运行system
命令时,您的文件可能是空的。如果你的system
命令在这种情况下会立即返回,那么你的按钮也会立即重新激活。
在system
命令之前,您应该:
close(launch);
(另外,传统上使用全大写的文件句柄)
您的方法存在几个问题。首先,顺序"禁用按钮","做一些非tk -ish","启用按钮"不起作用,按钮始终处于启用状态。原因是只有当回调返回或者显式地调用update()
或idletasks()
时才执行显示更改。为了演示这一点,在下面的示例中,按钮永远不会被禁用:
use Tk;
my $mw = tkinit;
my $b; $b = $mw->Button(-text => 'Click me!', -command => sub {
$b->configure(-state => 'disabled');
# $mw->idletasks; # or alternatively: $mw->update;
sleep 10; # simulate some task
$b->configure(-state => 'normal');
})->pack;
MainLoop;
但是如果idletasks()
或update()
调用被激活,那么事情就会像预期的那样工作。
示例脚本有一个缺陷:当sleep()
(或任何繁忙的任务)处于活动状态时,无法对GUI进行更新。对用户来说,应用程序似乎被冻结了。甚至连窗口刷新都不再发生了。如果这是一个问题,那么整个脚本必须以非阻塞的方式进行重组。在这种情况下,可以在后台启动一个新进程(正如您已经使用start
命令那样),但是您必须知道后台进程何时结束,并再次启用该按钮。一种简单的方法是使用某种"信号文件",并定期检查该信号文件是否从后台进程创建。下面是一个在Unix系统上工作的例子(但如果在system()
调用中使用自定义脚本,也应该在Windows上工作):
use Tk;
my $mw = tkinit;
my $b; $b = $mw->Button(-text => 'Click me!', -command => sub {
$b->configure(-state => 'disabled');
# no idletasks/update necessary now
system("(rm -f /tmp/signal_file; sleep 10; touch /tmp/signal_file) &");
my $repeater; $repeater = $mw->repeat(1000, sub {
if (-e "/tmp/signal_file") {
unlink "/tmp/signal_file";
$b->configure(-state => 'normal');
$repeater->cancel;
}
});
})->pack;
MainLoop;
这种方法不是很优雅,因为它需要定期检查。可以使用Tk::IO
模块编写一种更优雅的方法,但这可能只在Unix平台上工作:
use Tk;
use Tk::IO;
my $exec_fh;
my $mw = tkinit;
my $b; $b = $mw->Button(-text => 'Click me!', -command => sub {
$b->configure(-state => 'disabled');
# no idletasks/update necessary now
$exec_fh = Tk::IO->new(-linecommand => sub {
# empty, we're not interested in the output
}, -childcommand => sub {
$b->configure(-state => 'normal');
});
$exec_fh->exec("sleep 10");
})->pack;
MainLoop;
进一步的阅读是Tk::fileevent
Pod,也许你可以给AnyEvent
一个尝试。