Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Win32::SysTray Issue

by PilotinControl (Pilgrim)
on Oct 17, 2020 at 03:22 UTC ( [id://11122933]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks!
I have another issue that I am trying to wrap my head around the code is below:

use strict; use Win32::SysTray; my $tray = new Win32::SysTray ( 'icon' => 'C:\images\logo.ico', 'single' => 1, ) or exit 0; $tray->setMenu ( "> &Test" => sub { print "Hello from the Tray\n"; }, ">-" => 0, "> E&xit" => sub { return -1 }, ); $tray->runApplication;

The above code works as it should in standalone mode. However when I add it to a larger Win32::Console program only THIS code works:
my $tray = new Win32::SysTray ( 'icon' => 'C:\images\logo.ico', 'single' => 1, ) or exit 0;

The second part of the code never gets executed. If the second part of the code is added the program freezes. Any ideas? I believe it has to do with the $tray->runApplication; part conflicting with the Win32::Console. Thanks in advace!

Replies are listed 'Best First'.
Re: Win32::SysTray Issue
by syphilis (Archbishop) on Oct 17, 2020 at 04:09 UTC
    Hi,

    I can't reproduce the problem. I've taken your script, inserted use Win32::Console, specified a .ico file that exists on my system, and inserted print "Continuing on ...\n" to verify that the script does continue on to process the setMenu() command:

    UPDATE: Oh ... I had missed the $tray->runApplication; at the end, but I still don't see any crash.
    use strict; use Win32::Console; use Win32::SysTray; my $tray = new Win32::SysTray ( 'icon' => 'C:\_32\pscrpt\guiperl.ico', 'single' => 1, ) or exit 0; print "Continuing on ...\n"; $tray->setMenu ( "> &Test" => sub { print "Hello from the Tray\n"; }, ">-" => 0, "> E&xit" => sub { return -1 }, ); $tray->runApplication;
    It simply prints out Continuing on ... and exits cleanly.
    For me, it now outputs Continuing on ... and then hangs - irrespective of whether Win32::Console is loaded or not.
    What else do I need to do in order to see the problem that you've described ?

    Cheers,
    Rob

      Same here. The only code changes I made were to avoid indirect object creation, and to check the error on its own line. However, I would not imagine those would have any effect on the larger program.

      # ... my $tray = Win32::SysTray->new ( 'icon' => 'C:\images\somelogo.ico', 'single' => 1, ); exit 0 if !$tray; # ...
Re: Win32::SysTray Issue
by Corion (Patriarch) on Oct 17, 2020 at 06:01 UTC

    I guess that $tray->runApplication starts the event loop for your program. That loop only returns once your program quits.

    If you have what is basically a console program without an event loop and event architecture, you will have to post a Short Self-Contained Correct Example to demonstrate your problem. Then, we can maybe suggest how to change your program logic so it works together with the Windows event loop.

    As the documentation of Win32::SysTray says, it invokes Win32::GUI::Dialog, so basically it will involve rewriting your application in terms of Win32::GUI.

      I wondered about that myself and I think...I have not tested it yet...that Win32::GUI::Dialog is just for the systray icon menu as the one poster above was able too print to the console and run the icon menu code at the same time. However my whole program is quite console intensive as its a series of menu choices.

        If Win32::GUI is like Tk, you may be able to run the event loop in a "forked process" (perl emulates fork using threads on Windows) while your main program continues on with the menu choices. Arranging IPC in this scenario to make the systray icon anything more than a simple reminder that the program is running is up to you.

        Try:

        $tray->runApplication unless fork;
Re: Win32::SysTray Issue ( Win32::GUI::DoEvents )
by Anonymous Monk on Oct 18, 2020 at 07:31 UTC
    https://metacpan.org/pod/Win32::GUI::Reference::Methods#DoEvents
    #!/usr/bin/perl -- use strict; use warnings; use Win32::SysTray; Main( @ARGV ); exit( 0 ); sub Main { my $tray = new Win32::SysTray ( 'icon' => shift , 'single' => 1, ) or exit 0; $tray->setMenu ( "> &Test" => sub { print "Hello from the Tray\n"; }, ">-" => 0, "> E&xit" => sub { return -1 }, ); MainLoop( $tray ); } sub MainLoop { my( $tray ) = @_; for my $i (1 .. rand 1000){ print "my $i\n"; # $tray->runApplication; # last if -1 == Poke( $tray ); die "user quit" if -1 == Poke( $tray ); Win32::Sleep( rand 1000 ); } } #~ sub Win32::SysTray::Poke { sub Poke { my( $tray ) = @_; Win32::GUI::DoEvents(); }

      Hello Anon Monk
      I modified your code:

      #!/usr/bin/perl -- use strict; use warnings; use Win32::SysTray; sTray( @ARGV ); exit( 0 ); sub sTray { my $tray = new Win32::SysTray ( 'icon' => 'C:\images\logo.ico' , 'single' => 1, ) or exit 0; $tray->setMenu ( "> &Test" => sub { print "Hello from the Tray\n"; }, ">-" => 0, "> E&xit"=> sub { exit; }, ); begin( $tray ); } sub begin { my( $tray ) = @_; die "user quit" if -1 == Poke( $tray ); } #~ sub Win32::SysTray::Poke { sub Poke { my( $tray ) = @_; print "\nWhat is your name? "; chomp(my $name=<STDIN>); print "\nHello $name\n\n"; Win32::GUI::DoEvents(); }
      This is a smaller version from the larger program...a series of user inputs etc. When I run the above code it waits for an input....while I'm waiting for the input I would like to exit the program by clicking on the icon. That's what I'm trying to do....it works fine using your random number example. Thanks in advance.

        Oh! That should be easy, although this code is untested:

        # ... our $Tray = new Win32::SysTray ( ... ); # note that $Tray is global # ... my $name = Prompt("What is your name?"); print "\nHello $name\n\n"; # ... sub Prompt { my $prompt = shift; print "\n$prompt "; my $response = ''; my $rsel = ''; my $rrdy; vec($rsel,fileno(STDIN),1) = 1; CHAR: while (1) { die "user quit" if -1 == Win32::GUI::DoEvents(); while (select($rrdy=$rsel, undef, undef, 0.10)) { sysread(STDIN, $response, 1, length $response) == 1 or die "read error"; } last CHAR if chomp($response); } return $response; }

        Well, what do you expect a blocking call like readline to do other than block?

        Poke is a poor name for a Prompt function

Re: Win32::SysTray Issue
by pryrt (Abbot) on Oct 21, 2020 at 20:54 UTC
    Since you seem to be spinning your wheels on the console-based prompt function, why not make use of the fact that you're in a GUI environment, and make a Win32::GUI::DialogBox?

    Add an entry to your tray, like

    $tray->setMenu ( "> &Test" => sub { print "Hello from the Tray\n"; }, "> &Dialog" => \&interact_using_dialog, ">-" => 0, "> E&xit" => sub { return -1 }, );
    then define the sub interact_using_dialog(), where it creates a new Win32::GUI::Dialog with the appropriate form entries, and on clicking OK in that Dialog, grab the values from the form and close the Dialog, sending the data on to whatever data structures you are trying to populate.

    I would think that would be a faster debug path than continuing to play with trying to get console and GUI to mesh together properly.

    edit: fix link to Win32::GUI::DialogBox

      For example,
      #!perl # # [id://11122933] use 5.012; # strict, // use warnings; use Win32::SysTray; use Win32 qw/MB_ICONEXCLAMATION MB_ICONSTOP MB_ICONQUESTION MB_ICONINF +ORMATION/; $| = 1; my $tray = new Win32::SysTray ( 'icon' => 'C:\images\logo.ico', 'single' => 1, ) or exit 0; # each row of @choices needs a hashref, with the keys name, text, and +action -- name should be a perl-safe-identifier (single word), text i +s visible string, and action is a coderef my @choices = ( { name => 'EmployeeManagement', text => 'Employee Management', act +ion => sub { Win32::MsgBox("Do some management task", 0 | MB_ICONINFO +RMATION, 'Employee Management')} }, { name => 'Quit', text => 'Quit', action => sub { print "Exiting p +er user request\n"; exit 0 } }, ); my $DIALOG = create_dialog(); $tray->setMenu ( "> Show &Dialog" => sub { $DIALOG->Show() }, # can re-show +the dialog, too ">-" => 0, "> E&xit" => sub { return -1 }, ); $DIALOG->Show(); # if you want this dialog to default to visible; o +therwise, remove this line and rely on the tray to start it Win32::GUI::Dialog(); exit; sub create_dialog { my $dlg = Win32::GUI::DialogBox->new( -name => 'DlgBox', -text => 'Option Menu', -width => 300, -height => 120 + 20*@choices, ); $dlg->AddLabel( -text => 'Please make a selection', -pos => [15,10], -size => [$dlg->ScaleWidth() - 30 , 30], ); $dlg->AddButton( -text => 'Ok', -default => 1, -ok => 1, -size => [60,20], -pos => [$dlg->ScaleWidth() - 140, $dlg->ScaleHeight - 30], -onClick => \&DlgBox_Process, ); $dlg->AddButton( -text => 'Cancel', -cancel => 1, -size => [60,20], -pos => [$dlg->ScaleWidth() - 70, $dlg->ScaleHeight - 30], -onClick => \&DlgBox_Terminate, ); my $top = 50; for my $opt ( @choices ) { $dlg->AddRadioButton( -name => $opt->{name}, -size => [15,15], -pos => [15, $top], ); $dlg->AddLabel( -text => $opt->{text}, -pos => [45, $top], -size => [$dlg->ScaleWidth() - 45 - 10,15], ); $top += 20; } return $dlg; } sub DlgBox_Process { my $action = undef; for my $opt ( @choices ) { if( $DIALOG->{$opt->{name}}->Checked()) { $action = $opt->{action}; last; } } if(defined $action) { $DIALOG->Hide(); $action->(); #$DIALOG->Show(); # un-comment to automatically re-show the ma +in input dialog } else { Win32::MsgBox("Programmer needs to define action!", 0 | MB_ICO +NEXCLAMATION, 'ERROR in Management Dialog!') } return 0; } sub DlgBox_Terminate { $DIALOG->Hide(); return 0; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11122933]
Approved by GrandFather
Front-paged by haukex
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (7)
As of 2024-04-19 12:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found