How to print selected value with checkbutton in Tkx - perl

I'm using the Tkx module to create a window populated with text values from a #list. Then I select one or more then one with a checkbutton. I want to print the already selected ones after pressing the 'OK' button but don't know how to pass the variables to the 'OK' -command => sub {}. Thanks.
use autodie;
use strict;
use warnings;
use Tkx;
my $mw = Tkx::widget->new( "." );
$mw->g_wm_title( "Listbox" );
$mw->m_configure( -background => "#191919" );
my $width = '700';
my $height = '500';
Tkx::update('idletasks');
$width ||= Tkx::winfo('reqwidth', $mw);
$height ||= Tkx::winfo('reqheight', $mw);
my $x = int((Tkx::winfo('screenwidth', $mw) / 2) - ($width / 2));
my $y = int((Tkx::winfo('screenheight', $mw) / 2) - ($height / 2));
$mw->g_wm_geometry($width . "x" . $height . "+" . $x . "+" . $y);
my #list = ('TEXT1', 'TEXT2', 'TEXT3', 'TEXT4', 'TEXT5');
for my $list (#list) {
my $cb = $mw->new_ttk__checkbutton(
-text => $list,
-onvalue => 1,
-offvalue => 0,
);
$cb->g_pack(
-anchor=>'w',
-side=>'top',
-fill => 'x'
);
}
my $ok = $mw->new_button(
-text => "OK",
-command => sub {
print "Selected Values";
Tkx::after(500, sub { $mw->g_destroy });
},
);
$ok->g_pack(
-anchor=>'c',
-side=>'bottom',
);
Tkx::MainLoop();

If you just want to find what checkboxes are selected:
my $settings;
for my $list (#list) {
my $cb = $mw->new_ttk__checkbutton(
-text => $list,
-onvalue => 1,
-offvalue => 0,
-variable => \$settings->{checkbuttons}->{$list},
);
$cb->g_pack(
-anchor=>'w',
-side=>'top',
-fill => 'x'
);
}
my $ok = $mw->new_button(
-text => "OK",
-command => sub {
print "Selected Values: [";
print join( ", ", grep { $settings->{checkbuttons}->{$_} } #list ), "]\n";
Tkx::after(500, sub { $mw->g_destroy });
},
);

Related

use Image::Magick with perl on Ubuntu

Image::Magick module is installed.
I do see the perldoc if I type:
perldoc Image::Magick
While trying to use it with a Dancer2 application I don't get any results.
A simple test script does compile but except my hello I don't get to see any results or warnings? What am I doing wrong?
#!/usr/bin/perl
use strict;
use warnings;
use Image::Magick;
print "hello!\n";
my $image = Image::Magick->new;
$image->Set(size=>'100x100');
$image->ReadImage('xc:white');
$image->Set('pixel[49,49]'=>'red');
$image->Write("cool.jpeg");
Below I provide the relevant parts of the code for the Dancer2 app. On my local (OS X) system everything works fine. On the server the Image::Magick part is not functioning.
As per request the way I use Image::Magick with Dancer2..
package myDancer;
use Dancer2;
use Dancer2::Plugin::Database;
use Dancer2::Plugin::Auth::Extensible;
use Data::Dumper;
use Image::Size;
use Image::Magick;
use File::Basename;
use File::Spec;
use FindBin;
use File::Copy qw(move);
# --below relevant code--
# UPLOAD-----------
get '/upload' => require_login sub {
template 'upload', {}, { layout => 'cms' };
};
post '/upload' => require_login sub {
my $data = request->upload('file');
return 'Error' if not defined $data;
my $upload_dir = path( config->{appdir}, "public/images/uploads" );
debug( "Line 79: ", $upload_dir );
# full path with file-name
# $data->basename is the name provided with uploaded file
my $path = path( $upload_dir, $data->basename );
if ( -e $path ) {
return "$path already exists";
}
$data->link_to($path);
redirect '/fm/uploaded';
};
#---------------------------------------------------------------------
#
# What have we uploaded?
#
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
get '/fm/uploaded' => require_login sub {
my $upload_dir = path( config->{appdir}, "public/images/uploads/*.jpeg" );
debug( "Line: 102 - Full path used for uploaded: ",
$upload_dir );
my #images = glob($upload_dir);
my #glob_uploaded;
for my $record (#images) {
my ( $w, $h ) = imgsize($record);
push(
#glob_uploaded,
{
photo_name => basename($record),
width => $w,
height => $h,
}
);
}
my $message = <<'MESSAGE';
Just a message
MESSAGE
template 'fm/uploads',
{ forklifts => \#glob_uploaded, message => $message },
{ layout => "cms" };
};
get '/fm/new-image/:photo_name' => require_login sub {
# my $curdir = File::Spec->rel2abs('.');
my $upload_dir = path( config->{appdir}, "public/images/uploads" );
debug( "Line 137: ", $upload_dir );
#---------------------------------------------------------------------
#
# What is the latest id?
# And add 1 to this id.
#
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
my $sql = <<'SQL';
select seq from sqlite_sequence where name = ?
SQL
my $sth = database->prepare($sql);
$sth->execute('images');
my $current = $sth->fetchall_arrayref();
my $current_plus_one = $current->[0][0] + 1;
my $new_name = &TimeStamp . "-" . $current_plus_one . ".jpeg";
debug( "line: 154 - new_name: ", $new_name );
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#---------------------------------------------------------------------
my $photo_name = route_parameters->get('photo_name');
debug( "line 159 - photo_name ", $photo_name );
my $pathFoto =
path( config->{appdir}, "public/images/uploads/$photo_name" );
# my $pathFoto = "$upload_dir . $photo_name";
debug( "line 164: pathFoto", $pathFoto );
if ( -e $pathFoto ) {
print "File exists.\n"; # Debug
template 'fm/new-image', { photo => $new_name, sh_note => $photo_name },
{ layout => 'cms' };
}
else {
print "File doesn't exist.\n"; # Debug
redirect '/fm/forklift'; # TODO
}
};
#---------------------------------------------------------------------
#
# Adding the new image to the database together with meta-data
#
#vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
post '/fm/new-image' => require_login sub {
my $new_name = body_parameters->get('photo_name')
or die "missing content parameter";
my $caption = body_parameters->get('caption');
my $location = body_parameters->get('location');
my $short_note = body_parameters->get('sh_note');
my $note = body_parameters->get('note');
database->quick_insert(
'images',
{
photo_name => $new_name,
caption => $caption,
note => $note,
sh_note => $short_note,
location => $location,
}
);
my $curdir = path( config->{appdir}, "public/images/" );
debug( "line: 205 - check path: ", $curdir );
my $old_image_location_lg =
path( config->{appdir}, "public/images/uploads/$short_note" );
debug( "line: 209 - check path: ", $old_image_location_lg );
my $magick = new Image::Magick;
$magick->Read($old_image_location_lg);
$magick->Write( path( config->{appdir}, "public/images/lg/$new_name" ) );
$magick->Resize( gravity => 'Center' );
$magick->Scale( geometry => '3%x3%' );
$magick->Write( path( config->{appdir}, "public/images/tn/$new_name" ) );
unlink $old_image_location_lg;
redirect '/fm/recent-images';
};
####################################################### TIMESTAMP #######
# perldoc -q time
# perldoc -f localtime
sub TimeStamp {
my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
( 0, 0, 0, 0, 0, 0, 0, 0, 0 );
( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
localtime(time);
$year += 1900;
$mon += 1;
$sec = sprintf( "%02d", $sec );
$min = sprintf( "%02d", $min );
$hour = sprintf( "%02d", $hour );
$mon = sprintf( "%02d", $mon );
$mday = sprintf( "%02d", $mday );
my $timestamp =
"$year" . "-" . "$mon" . "-" . "$mday" . "-" . "$hour" . "-" . "$min";
return $timestamp;
}
####################################################### TIMESTAMP #######
true;
I tested your code and in the directory where my perl file is, it generated a new jpeg file.
I can suggest checking if your file and directory have the needed permissions for writing new files.
P.S. I am using FreeBSD 13

PERL tk module handling

I am using tk module to build a checklist for user to choose. I am totally beginner to this module. Currently the checklist created is all in the same series column, since it will be a long list, any idea how could I separate few of the options to another column? Also, any idea how to align those text to the left while checkbox to the right? To display it cleanly and neatly.
#!/usr/bin/perl
use Tk;
$main = MainWindow->new();
$label = $main->Label(-text => "Presence Check");
$label->pack();
$frame = $main->Frame(-relief=>"groove", -borderwidth=>2);
#$frame = $main->Frame(-relief=>"groove", -borderwidth=>2)->pack(-side => 'top', -expand => 1, -fill =>'both');
#$frame = $main->Frame->pack(-side => 'left', -fill => 'x');
$check1 = $frame->Checkbutton(-text=>"Document A (docx, pdf)",
-variable=>\$a,
-onvalue=>"APRESENT",
-offvalue=>"AABSENT");
#$check1->pack(-side=>"top");
$check2 = $frame->Checkbutton(-text=>"Document B (xlsx)",
-variable=>\$b,
-onvalue=>"BPRESENT",
-offvalue=>"BABSENT");
$check2->pack(-side=>"top");
$check3 = $frame->Checkbutton(-text=>"C specification",
-variable=>\$c,
-onvalue=>"CPRESENT",
-offvalue=>"CABSENT");
$check3->pack(-side=>"top");
$check4 = $frame->Checkbutton(-text=>"A-Specification",
-variable=>\$aspec,
-onvalue=>"ASPECPRESENT",
-offvalue=>"ASPECSABSENT");
$check4->pack(-side=>"top");
$check5 = $frame->Checkbutton(-text=>"Important Report",
-variable=>\$report,
-onvalue=>"REPORTPRESENT",
-offvalue=>"REPORTSABSENT");
$check5->pack(-side=>"top");
$check6 = $frame->Checkbutton(-text=>"Handbook",
-variable=>\$handbook,
-onvalue=>"HANDBOOKPRESENT",
-offvalue=>"HANDBOOKABSENT");
$check6->pack(-side=>"top");
$check7 = $frame->Checkbutton(-text=>"Data Spreadsheet",
-variable=>\$dataxls,
-onvalue=>"DATAPRESENT",
-offvalue=>"DATAABSENT");
$check7->pack(-side=>"top");
$check8 = $frame->Checkbutton(-text=>"D file",
-variable=>\$dfile,
-onvalue=>"DFILEPRESENT",
-offvalue=>"DFILEABSENT");
$check8->pack(-side=>"top");
$check10 = $frame->Checkbutton(-text=>"xx doc",
-variable=>\$xxdoc,
-onvalue=>"XXDOCPRESENT",
-offvalue=>"XXDOCABSENT");
$check10->pack(-side=>"top");
$check18 = $frame->Checkbutton(-text=>"yy Doc",
-variable=>\$yydoc,
-onvalue=>"YYDOCPRESENT",
-offvalue=>"YYDOCABSENT");
$check18->pack(-side=>"top");
$frame->pack();
$button = $main->Button(-text => "Exit",
-command => \&exit_button);
$button->pack();
MainLoop();
sub exit_button {
print "$a $b $c $aspec $report $handbook $dataxls $dfile $xxdoc $yydoc \n";
#print "$rv\n";
exit,
}
... any idea how could I separate few of the options to another
column? Also, any idea how to align those text to the left while
checkbox to the right?
Here is an example of how you can use the grid geometry manager to align the labels and checkboxes:
use feature qw(say);
use strict;
use warnings;
use Tk;
my $mw = MainWindow->new();
my #label_texts = (
"Document A (docx, pdf)",
"Document B (xlsx)",
"C specification"
);
my #labels;
my #checkvars;
my #check_buttons;
for my $text ( #label_texts ) {
my $label = $mw->Label(-text => $text);
push #labels, \$label;
my $check_var;
my $check = $mw->Checkbutton(
-text=>"",
-variable=>\$check_var,
);
push #checkvars, \$check_var;
push #check_buttons, \$check;
Tk::grid($label, $check, -sticky => 'w');
}
my $button = $mw->Button(
-text => "Exit",
-command => \&exit_button
);
Tk::grid($button, "-");
MainLoop();
sub exit_button {
for my $i (0..$#checkvars) {
my $var = $checkvars[$i];
my $state = $$var;
$state = 'undef' if !defined $state;
say "Variable $i: ", $state;
}
exit;
}
Please see attached screenshot to this code snippet if it is what you desired
!/usr/bin/perl
#
# vim: ai:ts=4:sw=4
#
use strict;
use warnings;
use feature 'say';
use Tk;
use Data::Dumper;
my $main = MainWindow->new( -title => 'Checkboxes' );
my $label = $main->Label(-text => 'Presence Check');
$label->pack();
my $frame = $main->Frame(-relief=>'groove', -borderwidth=>2);
my $values;
my #chk_boxes = (
[\$values->{doc_a},'Document A (docx, pdf)'],
[\$values->{doc_b},'Document B (xlsx)'],
[\$values->{spec_c},'C specification'],
[\$values->{spec_a},'A-Specification'],
[\$values->{report},'Important Report'],
[\$values->{hand_b},'Handbook'],
[\$values->{data_s},'Data Spreadsheet'],
[\$values->{data_d},'D file'],
[\$values->{doc_xx},'xx doc'],
[\$values->{doc_yy},'yy Doc']
);
check_box(\#chk_boxes);
$frame->pack();
my $button = $main->Button(
-text => 'Exit',
-command => \&exit_button
);
$button->pack();
MainLoop();
sub exit_button {
while( my($k,$v) = each %{$values} ) {
say "$k => $v" if $v;
}
exit;
}
sub check_box {
my $data = shift;
my $index = 0;
for my $chk_box ( #{$data} ) {
my $column = $index % 2;
my $row = int($index/2);
$frame->Checkbutton(
-text => $chk_box->[1],
-variable => $chk_box->[0]
)->grid( -column => $column, -row => $row, -sticky => 'w');
$index++;
}
}
Perhaps following form of data input may be preferable
#!/usr/bin/perl
#
# vim: ai:ts=4:sw=4
#
use strict;
use warnings;
use feature 'say';
use Tk;
use Data::Dumper;
my $main = MainWindow->new( -title => 'Checkboxes' );
my $label = $main->Label(-text => 'Presence Check');
$label->pack();
my $frame = $main->Frame(-relief=>'groove', -borderwidth=>2);
my $values;
my #chk_boxes;
while( <DATA> ) {
chomp;
my($var,$desc) = split '\t';
push #chk_boxes, [\$values->{$var}, $desc];
}
check_box(\#chk_boxes);
$frame->pack();
my $button = $main->Button(
-text => 'Exit',
-command => \&exit_button
);
$button->pack();
MainLoop();
sub exit_button {
while( my($k,$v) = each %{$values} ) {
say "$k => $v" if $v;
}
exit;
}
sub check_box {
my $data = shift;
my $index = 0;
for my $chk_box ( #{$data} ) {
my $column = $index % 2;
my $row = int($index/2);
$frame->Checkbutton(
-text => $chk_box->[1],
-variable => $chk_box->[0]
)->grid( -column => $column, -row => $row, -sticky => 'w');
$index++;
}
}
__DATA__
doc_a Document A (docx, pdf)
doc_b Document B (xlsx)
spec_c C specification
spec_a A-Specification
report Important Report
hand_b Handbook
data_s Data Spreadsheet
data_d D file
doc_xx xx Doc
doc_yy yy Doc
Add-on:
sub check_box {
my $data = shift;
my $index = 0;
for my $chk_box ( #{$data} ) {
my $column = $index % 2;
my $row = int($index/2);
my $chk_x = $frame->Checkbutton(
-text => $chk_box->[1],
-variable => $chk_box->[0]
)->grid( -column => $column, -row => $row, -sticky => 'w');
$chk_x->select if $index == 4;
$index++;
}
}

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();
}

implementing retry logic for subroutine using Sub::Attempts

refreshing my question.
Sub::Attempts retries once it find the exception (die).
For me, I want the sub to retry when sub is returning the false value.
Please let me know what should I change to make it work?
If you want to use Sub::Attempts, just make a subroutine that modifies the one you have to make it die rather than return false:
sub die_on_failure {
my $name = (caller).'::'.shift;
my $glob = do {no strict 'refs'; \*$name};
my $code = \&$glob;
no warnings 'redefine';
*$glob = sub {
my $ret = &$code;
$ret ? $ret : die "$name failed"
}
}
Then just do:
die_on_failure 'your_sub_name';
before calling:
attempts 'your_sub_name', ...;
sub retryBeforeFail {
my $className = shift;
my $attempt = shift;
my $max = shift;
my $success = 0;
... main code here ...
if (!$success && $attempt < $max) {
$attempt++;
return $self->retryBeforeFail($attempt, $max);
} else {
return $success;
}
}
Sounds like you need a loop, of some kind. One way to deal with this would be a simple “all done” flag:
sub foo {
my $success = undef;
until ($success) {
# do something interesting
redo if $something_failed;
# do more things here
++$success; # if it all worked properly
# or, exit early on success:
return $something if $all_is_well;
}
}
Without using a temporary var and an until loop, you can also use the special form of goto &subroutine to restart your sub:
sub foo {
# do something interesting
if ($something_failed) {
goto &foo;
}
}
The goto &sub form will throw out local lexical variables, and start the subroutine over again, but it is susceptible to any changes you may have made to #_:
sub foo {
my $x = shift #_;
if ($x < 5) {
#_ = ($x + 1);
goto &foo;
}
return $x;
}
print &foo;
__END__
5
The difference between return &foo(#_) and goto &foo, is that the goto version doesn't add to the call stack — a bit like tail recursion optimization.
Or you could us a simple while loop:
sub retry_before_fail {
my ( $maxtries , $coderef , #args ) = #_ ;
while( $maxtries ) {
# $coderef returns non zero upon success
if( my $result = $coderef->( #args ) ) {
return $result ;
}
$maxtries-- ;
}
# Failure now either return or die
return ;
}
If you have about 60 subs, you could use a wrapper function (idea stolen from HOP)- like this:
sub rpw {
my $f = shift;
my $t = shift;
my $r = &$f(#_);
while ('fail' eq $r && --$t) {
$r = &$f(#_);
}
return $r;
}
to call 'worker' functions (not exactly) like
sub s00 {
my $r = 0.2 > rand() ? 'ok' : 'fail';
print ' in s00 => ', join( '-', #_, $r), "\n";
return $r;
}
sub s01 {
my $r = 0.5 < rand() ? 'ok' : 'fail';
print ' in s01 => ', join( '-', #_, $r), "\n";
return $r;
}
from main code like
print 'from s00 => ', s00(1, 2, 3), "\n";
print 'from s01 => ', s01(qw/a b/), "\n";
print 'from rpw => ', rpw(\&s00, 5, 1, 2, 3), "\n";
print 'from rpw => ', rpw(\&s01, 5, qw/a b/), "\n";
output (not lucky):
in s00 => 1-2-3-fail
from s00 => fail
in s01 => a-b-fail
from s01 => fail
in s00 => 1-2-3-fail
in s00 => 1-2-3-fail
in s00 => 1-2-3-fail
in s00 => 1-2-3-fail
in s00 => 1-2-3-fail
from rpw => fail
in s01 => a-b-fail
in s01 => a-b-ok
from rpw => ok
with a bit of luck:
in s00 => 1-2-3-ok
from s00 => ok
in s01 => a-b-fail
from s01 => fail
in s00 => 1-2-3-fail
in s00 => 1-2-3-fail
in s00 => 1-2-3-fail
in s00 => 1-2-3-ok
from rpw => ok
in s01 => a-b-fail
in s01 => a-b-fail
in s01 => a-b-ok
from rpw => ok

How to set cell style using OpenOffice::OODoc?

How to apply a style to cell using OpenOffice::OODoc module in Perl?
I tried:
my $container = odfContainer("report1.ods", create => 'spreadsheet');
my $doc = odfDocument (
container => $container,
part => 'content'
);
# Styles
my $styles = odfDocument (
container => $container,
part => 'styles'
);
$styles->createStyle ('TTT',
family => 'cell',
display-name => 'Table Headers',
properties => {
'fo:font-weight' => 'bold',
'fo:color' => '#ffffff',
}
);
{
for (my $x = 0; $x < $X; $x++) {
$doc->columnStyle ($sheet, $x, "TTT"); # does not work
for (my $y = 0; $y < $Y; $y++) {
my $cell = $doc->getTableCell ($sheet, $y, $x);
$doc->cellValueType ($cell, $headers->[$x][1]);
$doc->updateCell ($cell, $data->[$y][$x]);
$doc->setStyle ($cell, 'TTT'); # does not work
$doc->cellStyle ($cell, 'TTT'); # does not work
}
}
}
See style:
style(object [, style])
Returns the style name of a text or graphics object. If the first
argument is a "master page" (see OODoc::Styles), it even returns the
associated "page layout".
Replaces the object's style if a style name is given as the second
argument.