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

时间:2015-05-26 10:09:02

标签: windows perl batch-file perltk

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');
}

上面的代码片段没有用完,它只禁用了几毫秒的按钮,并且即使在批处理文件运行之前,按钮仍然处于活动状态。

2 个答案:

答案 0 :(得分:0)

在执行launch命令之前,您没有关闭system

如果缓存了launch文件句柄的输出(通常为4KB),那么在运行system命令时,您的文件可能是空的。如果您的system命令在这种情况下立即返回,那么您的按钮也会立即重新激活。

在你的system命令之前,你应该:

close(launch);

(另外,传统上使用全大写的文件句柄。)

答案 1 :(得分:0)

您的方法存在一些问题。首先,顺序"禁用按钮","做一些非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