Tk::LCD Investigations
I recently made a UTC clock script using Tk::LCD. It simulates the look of a 7-segment LCD display. The elements/digits are designed around a 22x36 pixel block(large) and an 11x18 pixel block(small). In using this package, I determined that the digits were too small and that leading zeros weren't displayed. I implemented an option for displaying leading zeros and another for scaling the elements to an arbitrary multiple(where 1 equals the original large size). I plan a separate post to discuss these changes further.
This post concerns a test script for adding support for special characters in this case the : (colon). Currently Tk::LCD only supports numbers, minus, and space. This script draws a : within a 22x36 pixel block and provides for scaling to an arbitrary multiple.
The challenge of this script was in returning lists from a callback. While I came across the solution(call by reference and the $_[0] construct) fairly quickly the implementation was not obvious to me. The result is shown below.
I plan to integrate this code into my version of Tk::LCD to allow display of an HH:MM format. Other specical characters could be implemented in a similar way.
Update1: colon2.pl listed below includes changes based on comments to colon1.pl. Thanks to all who provided comments.
#! /usr/bin/perl
# colon2.pl - Draw a scalable : (colon) on a canvas
# Test script for a planned addition to Tk::LCD.pm
# Tk::LCD defines elements within a 22 x 36 pixel re
+ctangle
# The colon is drawn as two circles within this rect
+angle
#
# @Base shapes are scaled and moved into @scaled sha
+pes for display
# Clicking the Next or Previous button rescales
# and redraws the screen
#
# James M. Lynes, Jr. - KE4MIQ
# Created: March 14, 2023
# Last Modified: 03/14/2023 - Initial Version
# 03/15/2023 - First working version
# 03/17/2023 - Updated with PerlMonks comments
#
# Environment: Ubuntu 22.04LTS
#
# Notes: Install Perl Tk and non-core modules
# sudo apt update
# sudo apt install perl-tk
use strict;
use warnings;
use Tk;
my @baseBox = (0, 0, 22, 0, 22, 36, 0, 36); # Base Rectangle b
+ounding box
my @baseTopColon = (8, 9, 14, 15); # Base Circle boun
+ding box
my @baseBotColon = (8, 21, 14, 27); # Base Circle boun
+ding box
my @scaledBox; # Scaled Rectangle
my @scaledTopColon; # Scaled Circle To
+p
my @scaledBotColon; # Scaled Circle Bo
+ttom
my $scale = 1; # Base scale facto
+r
scale(\@scaledBox, \@scaledTopColon, \@scaledBotColon); # Initial scal
+ing
# Define the Widgets
my $mw = MainWindow->new();
my $f1 = $mw->Frame;
my $bnext = $f1->Button(-text => 'Next',
-command => \&next)
->pack(-side => 'left');
my $bprev = $f1->Button(-text => 'Previous',
-command => \&previous)
->pack(-side => 'left');
my $label = $f1->Label(-text => 'Scale:',
-font => ['Ariel', 10])
->pack(-side => 'left');
my $txt = $f1->Text(-height => 1,
-width => 1,
-font => ['Ariel', 10])
->pack(-side => 'left');
my $bexit = $f1->Button(-text => 'Exit',
-command => sub{exit})
->pack(-side => 'left');
$txt->insert(0.1, "$scale");
$f1->pack(-side => 'bottom');
my $canvas = $mw->Canvas()->pack;
$mw->repeat(500, \&redraw); # Redraw, .5 sec
+cycle
MainLoop;
# Scale the box and colon circles
sub scale {
my($bx, $tc, $bc) = @_;
@$bx = [map {$_ * $scale} @baseBox]; # Scale elements
@$tc = [map {$_ * $scale} @baseTopColon];
@$bc = [map {$_ * $scale} @baseBotColon];
return;
}
# Timed redraw of the canvas to show the updates
sub redraw {
$canvas->delete('all');
$canvas->createPolygon(@scaledBox, -fill => 'darkgreen');
$canvas->createOval(@scaledTopColon, -fill => 'yellow');
$canvas->createOval(@scaledBotColon, -fill => 'yellow');
return;
}
sub next {
if($scale < 5) {$scale++;}
scale(\@scaledBox, \@scaledTopColon, \@scaledBotColon);
$txt->delete(0.1, 'end');
$txt->insert(0.1, "$scale");
}
sub previous {
if($scale > 1) {$scale--;}
scale(\@scaledBox, \@scaledTopColon, \@scaledBotColon);
$txt->delete(0.1, 'end');
$txt->insert(0.1, "$scale");
}
#! /usr/bin/perl
# colon1.pl - Draw a scalable : (colon) on a canvas
# Test script for a planned addition to Tk::LCD.pm
# Tk::LCD defines elements within a 22 x 36 pixel re
+ctangle
# The colon is drawn as two circles within this rect
+angle
#
# @Base shapes are scaled and moved into @scaled sha
+pes for display
# Clicking the Next buttons rescales and redraws the
+ screen
#
# James M. Lynes, Jr. - KE4MIQ
# Created: March 14, 2023
# Last Modified: 03/14/2023 - Initial Version
# 03/15/2023 - First working version
#
# Environment: Ubuntu 22.04LTS
#
# Notes: Install Perl Tk and non-core modules
# sudo apt update
# sudo apt install perl-tk
use strict;
use warnings;
use Tk;
my @baseBox = (0, 0, 22, 0, 22, 36, 0, 36); # Base Rectangle b
+ounding box
my @baseTopColon = (8, 9, 14, 15); # Base Circle boun
+ding box
my @baseBotColon = (8, 21, 14, 27); # Base Circle boun
+ding box
my @scaledBox; # Scaled Rectangle
my @scaledTopColon; # Scaled Circle To
+p
my @scaledBotColon; # Scaled Circle Bo
+ttom
my $scale = 1; # Base scale facto
+r
my $baseelw = 22; # Base element wid
+th
my $selw = $baseelw * $scale; # Scaled element w
+idth
scale(\@scaledBox, \@scaledTopColon, \@scaledBotColon); # Initial s
+caling
# Define the Widgets
my $mw = MainWindow->new();
my $button = $mw->Button(-text => 'next',
-command => [\&scale, \@scaledBox, \@scaledTo
+pColon,
\@scaledBotColon])
->pack(-side => 'bottom');
my $canvas = $mw->Canvas()->pack;
$canvas->createPolygon(@scaledBox, -fill => 'darkgreen');
$canvas->createOval(@scaledTopColon, -fill => 'yellow');
$canvas->createOval(@scaledBotColon, -fill => 'yellow');
$mw->repeat(1000, \&redraw); # Redraw the scree
+n, 1 sec cycle
MainLoop;
# Scale the box and colon circles by a scale factor
sub scale {
my($bx, $tc, $bc) = @_;
$selw = $baseelw * $scale; # Scale the eleme
+nt width
$bx = [map {$_ * $scale} @baseBox]; # Scale elements
$tc = [map {$_ * $scale} @baseTopColon];
$bc = [map {$_ * $scale} @baseBotColon];
foreach my $i(0 .. $#$bx) { # Return scaled e
+lements
$_[0][$i] = @$bx[$i]; # via referenc
+es
}
foreach my $i(0 .. $#$tc) {
$_[1][$i] = @$tc[$i];
}
foreach my $i(0 .. $#$bc) {
$_[2][$i] = @$bc[$i];
}
$scale = $scale + 1; # Bump for next c
+ycle
return;
}
# Timed redraw of the canvas to show the updates
sub redraw {
$canvas->delete('all');
$canvas->createPolygon(@scaledBox, -fill => 'darkgreen');
$canvas->createOval(@scaledTopColon, -fill => 'yellow');
$canvas->createOval(@scaledBotColon, -fill => 'yellow');
return;
}
James
There's never enough time to do it right, but always enough time to do it over...