Slickuser has asked for the wisdom of the Perl Monks concerning the following question:

I post this message in google groups for help as well. Here is what I want to achieve: Have the GUI up, use thread to process the data (read from file) and Excel OLE to output the data. I don't want my GUI to freeze up when it's running. I got the script going but I got couple of errors below. Any help would be great. Thanks a lot.
Attempt to free non-existent shared string '_TK_RESULT_', Perl interpreter: 0x2e e14dc at C:\Documents and Settings\slickuser\Desktop\thread3.pl line 22. Tk::Error: Can't call method "Call" on an undefined value at C:/Perl/ site/lib/Tk /After.pm line 89. [once,[{},after#7,idle,once,[ConfigChanged,{},{}]]] ("after" script) Tk::Error: Can't call method "Call" on an undefined value at C:/Perl/ site/lib/Tk /After.pm line 89. [once,[{},after#8,idle,once,[ConfigChanged,{},{}]]] ("after" script) Attempt to free non-existent shared string 'Value', Perl interpreter: 0x22485c a t (eval 9) line 1. Free to wrong pool 222da8 not 2ed3ec8 at (eval 9) line 1.
Here is my code:
use strict; use warnings; use Tk; use threads; my $thr; my $mainWindow = MainWindow->new; my $textBox = $mainWindow->Scrolled("Text", -width=>80, -height=>7, -scrollbars=>"ose", -wrap=>"word")->pack(); my $goBut = $mainWindow->Button(-foreground=>"blue", -text=>"Click", -command=>sub { $thr = threads->new(\&excecute) } ) +- >pack(); my $stopBut = $mainWindow->Button(-foreground=>"red", -text=>"Exit", -command=>sub{ if(defined($thr)){ $thr->detach; } exit; })->pack(); MainLoop; sub excecute { $goBut->configure(-state=>"disabled"); $textBox->configure(-state=>"normal"); open(FILE,"C:/file.txt") or die "Can't open file.\n"; while(<FILE>) { my $message = $_; $textBox->insert('end', $message); } close(FILE); $textBox->configure(-state=>"disabled"); $textBox->see('end'); use Win32::OLE; use Win32::OLE::Const 'Microsoft Excel'; my ($Excel,$Workbook,$fileOutput,$CurrentSheet,$Range); $fileOutput = "C:/test.xls"; $Excel = Win32::OLE->new('Excel.Application', 'Quit') || die " +Can't create Excel object. \n"; $Excel->{'Visible'} = 1; #0 is hidden, 1 i +s visible $Excel->{DisplayAlerts} = 0; #0 is hide alerts + $Excel->{SheetsInNewWorkbook} = 1; $Workbook = $Excel->Workbooks->Add(); $Workbook->SaveAs($fileOutput) or die "Can't save Excel.\n"; $CurrentSheet = $Workbook->Worksheets(1); $CurrentSheet->Select; for (my $i=1; $i<=65356; $i++) { $Range = $CurrentSheet->Range("A$i"); $Range->{Value} = $i; sleep(0.01); } $Workbook->Save(); $Workbook->Close(); $Excel->Quit(); Win32::OLE->FreeUnusedLibraries(); $goBut->configure(-state=>"normal"); return;

Replies are listed 'Best First'.
Re: Tk & threads & Excel OLE??
by Sandy (Curate) on Jun 10, 2008 at 22:11 UTC
    I was fooling around to try to find a workable solution.

    Because I was trying a variety of things, the solution below is rather untidy (stuff left over from things that didn't work)

    However, I am running short of time, so I simply give you something that might be what you are looking for.

    Main points:
    1. Use $mainWindow->update() within loops. It keeps Tk alive
    2. Launching process using after allows you to continue processing within your current process (kinda like thread?)
    3. If you are using a system command that blocks your process, you should look at fileevent and pipes.

    Good luck.

    use strict; use warnings; use Tk; my $excelflag; my $mainWindow = MainWindow->new; my $textBox = $mainWindow->Scrolled("Text", -width=>80, -height=>7, -scrollbars=>"ose", -wrap=>"word")->pack(); #my $goBut = $mainWindow->Button(-foreground=>"blue", -text=>"Click", # -command=>sub { $thr = threads->new(\&excecute) } +)->pack(); my $goBut = $mainWindow->Button(-foreground=>"blue", -text=>"Click", -command=>sub { excecute() } )->pack(); my $stopBut = $mainWindow->Button(-foreground=>"red", -text=>"Stop", -command=>sub{ $excelflag = 1 })->pack(); my $exitBut = $mainWindow->Button(-foreground=>"red", -text=>"Exit", -command=>sub{ $excelflag = 1; exit })->pack(); MainLoop; sub excecute { $goBut->configure(-state=>"disabled"); $textBox->configure(-state=>"normal"); $excelflag = 0; $textBox->after(2,\&excel); open(FILE,"C:/file.txt") or die "Can't open file.\n"; while(<FILE>) { my $message = $_; $textBox->insert('end', $message); } close(FILE); $textBox->configure(-state=>"disabled"); $textBox->see('end'); return; } sub excel { use Win32::OLE; use Win32::OLE::Const 'Microsoft Excel'; my ($Excel,$Workbook,$fileOutput,$CurrentSheet,$Range); $fileOutput = "C:/test.xls"; $Excel = Win32::OLE->new('Excel.Application', 'Quit') || die "Can't create Excel object. \n"; $Excel->{'Visible'} = 1; #0 is hidden, 1 i +s visible $Excel->{DisplayAlerts} = 0; #0 is hide alerts + $Excel->{SheetsInNewWorkbook} = 1; $Workbook = $Excel->Workbooks->Add(); $Workbook->SaveAs($fileOutput) or die "Can't save Excel.\n"; $CurrentSheet = $Workbook->Worksheets(1); $CurrentSheet->Select; for (my $i=1; $i<=6500; $i++) { $Range = $CurrentSheet->Range("A$i"); $Range->{Value} = $i; sleep(0.01); $mainWindow->update(); last if $excelflag; } $Workbook->Save(); $Workbook->Close(); $Excel->Quit(); Win32::OLE->FreeUnusedLibraries(); $goBut->configure(-state=>"normal"); return; }
    Disclaimer: this could be a lot cleaner - but want to go home.

    Sandy

      Thanks for the code Sandy. When I test the code you gave to me, I get my GUI to freeze up until it's done running the Excel part. It's the same way I have before, and this is why I switch to threads to prevent the GUI from freezing up.
Re: Tk & threads & Excel OLE??
by zentara (Cardinal) on Jun 11, 2008 at 12:48 UTC
    I already answered you in the newsgroups.

    1. You cannot spawn a thread from a Tk Button callback.

    2. You cannot access a Tk widget from a thread.

    Here is some code to show you how to use shared variables and Tk with threads. I don't use win32, so OLE stuff is left out and may be a bigger problem yet.

    #!/usr/bin/perl use strict; use warnings; use Tk; use threads; use threads::shared; my $data:shared = ''; my $go_control:shared = 0; my $die_control:shared = 0; #create thread before any Tk my $thr = threads->new(\&excecute); my $mainWindow = MainWindow->new; my $textBox = $mainWindow->Scrolled("Text", -width=>80, -height=>7, -scrollbars=>"ose", -wrap=>"word")->pack(); my $goBut; # need to declare here so can be used in -command $goBut = $mainWindow->Button(-foreground=>"blue", -text=>"Click", -command=>sub { $goBut->configure(-state=>"disabled +"); $textBox->configure(-state=>"normal"); $go_control = 1; #start thread } )->pack(); my $stopBut = $mainWindow->Button(-foreground=>"red", -text=>"Exit", -command=>sub{ $die_control = 1; $thr->join; exit; })->pack(); #use a timer to read the shared variable and deal with Tk stuff my $repeater = $mainWindow->repeat(20,sub{ $textBox->insert('end',$data); $textBox->see('end'); }); MainLoop; sub excecute{ # require Win32::OLE; # require Win32::OLE::Const 'Microsoft Excel'; while(1){ #wait for $go_control if($go_control){ open(FILE,$0 ) or die "Can't open file.\n"; while(<FILE>){ if($die_control){return} $data = $_; } close(FILE); }else{ select(undef,undef,undef,.25); }# sleep until awakened } return; }

    I'm not really a human, but I play one on earth CandyGram for Mongo
Re: Tk & threads & Excel OLE??
by Anonymous Monk on Jun 11, 2008 at 08:35 UTC