Create new perl/tk window that will automatically close after 1sec - perl

I want to add a new widget to my script that will open a new window with text and will close automatically after 1sec.
how can I do it ?

I think what you want is Tk::after.
#!/usr/bin/perl
use strict;
use warnings;
use Tk;
my $mw = MainWindow->new;
my $spawn = $mw->Button(
-text => 'spawn',
-command => sub {
my $subwindow = MainWindow->new;
my $label = $subwindow->Label(-text => "spawned");
$label->pack;
$subwindow->after(1_000, sub { $subwindow->destroy; });
}
);
$spawn->pack;
my $exit = $mw->Button(
-text => 'exit',
-command => sub { print "exiting...\n"; exit }
);
$exit->pack;
MainLoop;

Related

perl TK combination/ I cannot find any example

I'm searching for any moderately short example that I can download which would combine Perl/GTK or any other graphics environment with buttons displayed after excution.
#!/usr/bin/perl
use warnings;
use strict;
use Tk qw{ MainLoop };
my $mw = 'MainWindow'->new;
my $b_show;
$b_show = $mw->Button(-text => 'Show',
-command => sub {
$b_show->configure(-command => undef);
$mw->Button(-text => 'Quit',
-command => sub { exit })->pack;
})->pack;
MainLoop();

Passing variable from subroutine in tk perl interface

I am using the perl Tk interface where I want to have a button test_1 and upon clicking on this button I would like a variable $varchoice to be defined as test_1. If I press on the button test_2, the variable $varchoice should be defined as test_2.
Before is the snippet of code in which I attempted to accomplish this:
$budget_frame->Button(-text => 'test_1',-command => sub{$varchoice=budget_plot_1()})->pack(-side => "left");
$budget_frame->Button(-text => 'test_2',-command => sub{$varchoice=budget_plot_2()})->pack(-side => "left");
sub budget_plot_1()
{
print "plotting 1\n";
my $var=1;
return $var;
}
sub budget_plot_2()
{
print "plotting 2\n";
my $var=2;
return $var;
}
How do I tweak this code to get the desired results?
Your program seems to work fine. Here is an example of how I tested it:
use feature qw(say);
use strict;
use warnings;
use Tk;
my $budget_frame = MainWindow->new(-title=>"Button test");
my $varchoice;
$budget_frame->Button(
-text => 'test_1',
-command => sub{ $varchoice = budget_plot_1() }
)->pack(-side => "left");
$budget_frame->Button(
-text => 'test_2',
-command => sub{ $varchoice = budget_plot_2() }
)->pack(-side => "left");
MainLoop;
say "Value of \$varchoice = $varchoice";
sub budget_plot_1()
{
print "plotting 1\n";
return "test_1";
}
sub budget_plot_2()
{
print "plotting 2\n";
return "test_2";
}
Output:
Value of $varchoice = test_1

perl tk gui to show script stdout and stderr in text widget

I have a GUI that runs a script from a command button, but how can I get it to display output in the text widget?
If I wanted to display the output via a logfile insert, could I have the command on the same button/sub as the run button?
use warnings;
use strict;
use Tk;
use Tk::Text ;
use POSIX 'strftime';
my $DATE = strftime("Report.pl for %dth %b %Y" , localtime());
my $mw = MainWindow->new;
my $filename = "c:\\Temp\\perl.txt";
$mw->geometry("720x500");
$mw->title(" backupadmin ");
my $main_frame = $mw->Frame()->pack(-side => 'top', -fill => 'x');
my $left_frame = $main_frame->Frame(-background => "snow2")->pack(-side => 'left', -fill => 'y');
my $right_frame = $main_frame->Scrolled("Text", -scrollbars => 'se',-background => "black",-foreground => "yellow",-height => '44')->pack(-expand => 1, -fill => 'both');
my $failures_button = $left_frame->Button(-text => " $DATE ",
-command => [\&runscript])->pack;
my $Close_button = $left_frame->Button(-text => ' Close ',
-command => [$mw => 'destroy'])->pack;
my $Help_button = $left_frame->Button(-text => " Help Guide ",
-command => [\&load_file])->pack(-side => "bottom");
my $Close_help = $left_frame->Button(-text => ' Close Help ',
-command => [$right_frame => \&clear_file])->pack(-side => "bottom");
MainLoop;
sub runscript {
system("report.pl");
}
sub load_file {
open (FH, "$filename");
while (<FH>) { $right_frame->insert("end", $_); }
close (FH);
}
sub clear_file {
$right_frame->('quit');
}
If your report.pl script outputs to STDOUT, then you could try something like this in your runscript callback:
sub runscript {
right_frame->delete('1.0','end');
my $text = `report.pl`;
$right_frame->insert('end', $text);
}
Alternatively, if report.pl outputs to c:\temp\perl.txt then you could try the following:
sub runscript {
right_frame->delete('1.0','end');
system("report.pl");
load_file();
}

Resize Notepad based on holding frame

I'm trying to get the notepad to expand when dragging the main
window .... and suggestions? I have it to where it reads the screen size but it won't keep the changing size of the window. All my attempts of add a loop have failed... is there anyway to create a loop or a constant call back?
#!/usr/bin/perl -w
use strict;
use Tkx;
use strict;
use LWP::Simple;
use LWP::UserAgent;
use Cwd;
use Tkx;
Tkx::package_require("Tktable");
Tkx::package_require("tile");
Tkx::package_require("style");
Tkx::style__use("as", -priority => 70);
Tkx::package_require('widget::scrolledwindow');
Tkx::package_require("BWidget");
our $VERSION = "1.00";
(my $progname = $0) =~ s,.*[\\/],,;
my $mw = Tkx::widget->new(".");
$mw->g_wm_title("Wikiget");
$mw->g_wm_minsize(500, 200);
cow();
Tkx::MainLoop();
exit;
sub cow
{
my $sw = $mw->new_ScrolledWindow();
my $sf = $sw->new_ScrollableFrame();
$sw->g_pack(-fill => "both", -expand => 1); $sw->setwidget($sf);
my $printer_frame = Tkx::widget->new($sf->getframe());
Tkx::update('idletasks');
my $x = int((Tkx::winfo('width', $mw))- 10);
my $y = int((Tkx::winfo('height', $mw)) - 50);
my $nb = $printer_frame->new_ttk__notebook(-height => $y, -width => $x);
$nb->g_pack(-fill => "both", -expand => 1);
my $fm1 = $nb->new_ttk__frame;
my $fm2 = $nb->new_ttk__frame;
$fm1->new_label(-text => 'Test1Test1Test1')->g_pack(qw/-anchor nw/);
$fm2->new_label(-text => 'Test2Test2Test2')->g_pack(qw/-anchor nw/);
$nb->add($fm1, -text => 'One');
$nb->add($fm2, -text => 'Two');
}

Delete the subwidgets/entries from a tk::menu widget

I want to implement a history/recent-files functionality for my Perl/Tk program.
Here is a working code excerpt from my program to demonstrate my problem.
#!/usr/bin/perl
use strict;
use warnings;
use English qw( -no_match_vars );
use Tk;
my #history_entries = qw(Back To The History);
my $mw = MainWindow->new();
my $menubar = $mw->Menu();
$mw->configure( -menu => $menubar );
my $file = $menubar->cascade( -label => '~File' );
my $history = $file->cascade( -label => '~History', );
build_history();
MainLoop();
#=== FUNCTION ================================================================
# NAME: build_history
# PURPOSE: Polulate the history
#===============================================================================
sub build_history {
foreach (#history_entries) {
$history->command(
-label => $ARG,
-command => \&some_function,
-compound => 'left',
);
}
return;
} # ---------- end of subroutine build_history ----------
As you can see, the entries are created with $history->command but how can I delete them every time I call build_history?
The reason I want them deleted is that everytime a user opens a file, the last item (in this case 'History') should be deleted and a new item should be put on top of the list. So that I have a maximum of (in this example) four entries.
Any other ways of implementing this functionality with Tk are welcome.
Thanks for your time.
UPDATE:
I followed the advice of "mu" and tried to get the subwidgets with the children() function just after the function is called, like this:
my #child = $history->children();
foreach my $c ( #child ) {
if ($c->Exists()){
$c->destroy;
}
}
The program exits with the error:
Can't locate object method "children" via package "Tk::Menu::Cascade" at /home/alex/Desktop/stack_history.pl line 28.
you can create a submenu from the menubar first:
my $sub_menu = $menubar->Menu(-tearoff => 0);
Then you can pass this submenu to the cascade menuitem:
$file->cascade( -label => '~History', -menu => $sub_menu);
Then you can add/delete menuitems to the submenu:
foreach (#history_entries) {
$sub_menu->command(
-label => $ARG,
-compound => 'left',
);
}
...
$sub_menu->delete(0); # Remove first element
With this solution you can avoid rebulding the whole menu.
I ended up rebuilding the whole menu. That's how my code looks like atm. I am not proud of it but it works ... I am open to any form of advice.
#!/usr/bin/perl
use strict;
use warnings;
use English qw( -no_match_vars );
use Tk;
# History entries are stored in array
my #history_entries = qw(Back To The History);
my $mw = MainWindow->new();
$mw->geometry('200x200');
my $menubar = $mw->Menu();
#Build menus
$mw->configure( -menu => $menubar );
build_menu();
$mw->Button(
-text => 'Update History',
-command => \sub {
#when a user opens a file insert_history is called.
insert_history();
}
)->pack( -side => 'bottom', -anchor => 'sw' );
MainLoop();
#=== FUNCTION ================================================================
# NAME: build_menu
# PURPOSE: Update/Build the menu
#===============================================================================
sub build_menu {
#delete the whole menu
$menubar->delete(1);
#built it again
my $file = $menubar->cascade( -label => '~File' );
my $history = $file->cascade( -label => '~History', );
foreach (#history_entries) {
$history->command(
-label => $ARG,
-compound => 'left',
);
}
return;
} # ---------- end of subroutine build_menu ----------
#=== FUNCTION ================================================================
# NAME: insert_history
# PURPOSE: Do something with the array containing the history entries.
# Then rebuild the menu.
#===============================================================================
sub insert_history {
#make something with the array
my $last_element = pop #history_entries;
unshift #history_entries, $last_element;
#update menu
build_menu();
return;
} # ---------- end of subroutine insert_history ----------