如何在执行外部命令之前禁用Perl按钮


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一个尝试。

最新更新