首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么即使使用不同的变量ref,waitVariable调用也不独立?

为什么即使使用不同的变量ref,waitVariable调用也不独立?
EN

Stack Overflow用户
提问于 2017-01-05 17:50:44
回答 2查看 161关注 0票数 5

我对Tk并不熟悉,我想知道所讨论的问题是否是正常的Tk行为。

简而言之:我有一个Perl/Tk ( two 804.028)脚本,它使用两个Tk::ExecuteCommand (v1.6)小部件。这样的对象有一个execute_command方法,它使用定义的文件事件回调来读取已执行的命令的stdout,并在它完成后返回。它是通过使用waitVariable来解决的。但是,如果两个ExecuteCommand一起启动,它们只在较慢的返回时才返回。我可以预期,在完成后,更快的回报会立即出现。

我做了一个小小的测试Perl/Tk脚本来演示这个问题:

代码语言:javascript
复制
#!/usr/bin/perl

use strict;
use warnings;
use Tk;
use Tk::ROText;

my $MAIN = new MainWindow -title => "TEST";
my $text = $MAIN->Scrolled('ROText')->pack(qw/-expand 1 -fill both/);

sub pr { # Write into ROText widget
  $text->insert('end', join '', @_); $text->yview('end');
}
pr "Tk version ", Tk->VERSION, "\n";

my @v = (100, 200);
sub doo { # Button callback
  my ($rv, $txt) = @_;
  pr "B4 wait: $txt, ref=$rv, val=", $$rv, "\n";
  $MAIN->waitVariable($rv);
  pr "Aft wait: $txt, ref=$rv, val=", $$rv, "\n";
}

$MAIN->Button(-text => 'Do 0', -command => [\&doo, \$v[0], "Do 0" ]
    )->pack(qw/-expand 1 -side left -fill both/);
$MAIN->Button(-text => 'Stop 0', -command => [sub {++$v[0]; pr "Stop 0\n";} ]
    )->pack(qw/-expand 1 -side left -fill both/);
$MAIN->Button(-text => 'Do 1', -command => [\&doo, \$v[1], "Do 1" ]
    )->pack(qw/-expand 1 -side left -fill both/);
$MAIN->Button(-text => 'Stop 1', -command => [sub {++$v[1]; pr "Stop 1\n";} ]
    )->pack(qw/-expand 1 -side left -fill both/);

MainLoop();

这将绘制一个ROText小部件和4个按钮(Do 0Do 1) (见附图)。单击Do按钮,调用函数doo,该函数等待分配的标量更改。当按下“停止”按钮时,变量将被更改。

如果按Do 0Do 1顺序按下按钮,则输出似乎没有问题(参见第2-7行)。但是,如果“任务”以并行方式启动,那么只有当两者都被停止时,两个回调才会结束。因此,按Do 0Stop 0中的按钮(参见第8-13行)会产生一个奇怪的结果(见图)。

我对第二个测试的期望是,第一个回调函数在按下第一个停止按钮后立即返回。所以我认为产出应该是:

代码语言:javascript
复制
B4 wait: Do 0, ref=SCALAR(0x9970560), val=101
B4 wait: Do 1, ref=SCALAR(0x9970bfc), val=201
Stop 0
Aft wait: Do 0, ref=SCALAR(0x9970560), val=102
Stop 1
Aft wait: Do 1, ref=SCALAR(0x9970bfc), val=202

它运行在Linux机器上。

我是不是遗漏了什么?提前感谢!

更新

为了绕过这个waitVariable问题,我重写了这个小部件,改为使用回调(感谢Tantalus!)。现在,execute_command立即返回。有两个回调,一个用于取消,一个用于完成。现在,调用者通过这些回调被告知。无论如何,我在某个地方读到(我现在找不到源代码),在Tk中长时间地等待回调不是一个好主意。新的解决方案符合这一点。

谢谢你的帮助!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-05 18:11:14

$widget->waitVariable(\$name) $widget->waitVisibility $小部件->等待窗口 tk等待方法等待几种情况中的一种发生,然后在不采取任何其他操作的情况下返回。返回值始终是空字符串。waitVariable需要对perl变量的引用,命令等待修改该变量。此表单通常用于等待用户完成与对话框的交互,该对话框将变量设置为交互的一部分(可能是最终的)部分。waitVisibility等待$小部件的可见性状态的更改(如VisibilityNotify事件的到来所示)。此表单通常用于等待新创建的窗口出现在屏幕上,然后才采取某些操作。waitWindow等待$widget被销毁。此表单通常用于在使用该交互的结果之前等待用户完成与对话框的交互。请注意,每次需要对话框时创建和销毁窗口都会使代码模块化,但会增加开销,可以通过取消窗口并使用waitVisibility来避免这种开销。 当tk等待方法等待时,它们以正常的方式处理事件,因此应用程序将继续响应用户交互。如果事件处理程序再次调用tkwait,则必须在外部调用完成之前完成对tkwait的嵌套调用。

强调我的。

票数 3
EN

Stack Overflow用户

发布于 2017-01-05 18:10:48

您不应该在事件循环中等待。正在发生的情况是,您正在生成一个包含在前一个等待循环中的调用堆栈。例如,如果在顶部添加use Carp;,然后更改pr函数,如下所示:

代码语言:javascript
复制
sub pr { # Write into ROText widget
  $text->insert('end', Carp::longmess(join '', @_)); $text->yview('end');
}

然后你会看到waitVariable出现-我们不能回到那里,直到我们回到那个循环,你结束了循环中的循环。

要完成您想要做的事情而不将所有事情转化为事件,您可能需要尝试科洛,它可以像这样反转事件。

而且,在现代perls中,qw并不意味着括号,因此您的pack调用需要在qw/.../列表中插入。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41491554

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档