Perl在长线程上更新UI

Perl在长线程上更新UI

本文介绍了Perl在长线程上更新UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Perl脚本,它在Windows XP上的ActiveStates 5.10 build 1004版本的ActiveStates上运行,这会创建一个UI,然后在按下按钮后运行一个较长的过程.在此过程中,我想使用该线程执行期间发生的状态来更新UI(列表框).这是该代码的精简版本.

I have a Perl script running on version 5.10 build 1004 of ActiveStates Active Perl on windows xp which creates a UI and then runs a long process after a button press. During this process I would like to update the UI (a list box) with status on what is going on during the execution of this thread. Here is a stripped down version of the code.

#!/usr/local/bin/perl

use warnings;
use strict;
use Tkx;
use threads;
use threads::shared;

my $outputText = " {a} {b}";

my $mw = Tkx::widget->new(".");
$mw->g_wm_title("MD5 Checker");
$mw->g_wm_minsize(300,200);
my $content = $mw->new_ttk__frame(-padding => "12 12 12 12");
my $btnCompare = $content->new_ttk__button(-text => "Compare", -command => sub{startWork()});
my $lstbxOutput = $content->new_tk__listbox(-listvariable => \$outputText, -height => 5);
my $scollListBox = $content->new_ttk__scrollbar(-orient => 'vertical', -command => [$lstbxOutput, 'yview']);
$lstbxOutput->configure(-yscrollcommand => [$scollListBox, 'set']);

sub startWork()
{
    print "Starting thread \n";
    my $t = threads->create(\&doWork, 1);
    sleep (5);
    print $outputText . "\n";
}

sub doWork()
{
    for (my $a = 0; $a<10; $a++)
    {
        $outputText .= " {$a}";
        print "Counting $a\n";
        sleep(2);
    }
    print "End thread\n";
}

当前,打印命令是用于调试的,因此我知道主线程和子线程在做什么.从我阅读的有关线程的内容中,我需要use threads::shared;来允许线程共享变量.目前,在子线程执行期间或线程结束时,我的列表框根本没有更新.如果没有线程,则列表框将在主线程完成循环后更新.我缺少在线程执行期间更新UI的什么功能?

Currently the print commands are for my debugging so I know what the main and child threads are doing. From what I have read about threading I need the use threads::shared; to allow threads to share variables. At the moment my list box does not update at all during the child threads execution nor when the thread has ended. Without the threading, the list box would update after the main thread was done with the loop. What am I missing to get the UI to update during the threads execution?

谢谢

卫斯理

推荐答案

一个问题是,列表框变量需要在线程之间共享. Tk对直接共享的listbox变量似乎不满意,因此我制作了两个副本,并设置了定期状态更新以将共享版本复制到非共享版本.

One problem is that the listbox variable needs to be shared between the threads. Tk doesn't seem happy with the listbox variable shared directly, so I made two copies, and set up a periodic status update to copy the shared version to the non-shared version.

但是,将线程与Tkx一起使用可能会很麻烦.尝试join线程而不是detach线程时出现段错误,如果将my $t移到startWork()中,则会出现以下代码段错误. 此讨论建议您可能需要在创建任何Tk小部件以使其可靠工作之前启动线程.

However, using threads with Tkx may be dicey. I was getting segfaults when I tried to join the thread rather than detach it, and I get a segfault with the code below if I move my $t inside startWork(). This discussion suggests that you may need to start the thread before creating any Tk widgets for it to work reliably.

这是我最后得到的代码:

Here is the code I ended up with:

my $outputTextShared :shared = " {a} {b}";
my $outputText = " {a} {b}";

my $t;
sub startWork()
{
    print "Starting thread \n";
    $t = threads->create(\&doWork, 1);
}

sub updateStatus()
{
    $outputText = $outputTextShared;
}

sub doWork()
{
    threads->detach();
    for (my $a = 0; $a<10; $a++)
    {
        $outputTextShared .= " {$a}";
        print "Counting $a\n";
        sleep(1);
    }
    print "End thread\n";
}

my $update;
$update = sub {
    Tkx::after (1000, $update);
    updateStatus();
};
Tkx::after (1000, $update);

Tkx::MainLoop();

这篇关于Perl在长线程上更新UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 18:25