Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

wxPerl LCD Clock

by jmlynesjr (Friar)
on Feb 04, 2013 at 16:41 UTC ( #1016975=CUFP: print w/ replies, xml ) Need Help??

As suggested by ww in his response to my wxPerl Simulated 7 Segment LCD Display post, it's now available in clock form.

The LCD, Angular Meter, and Linear Meter are all now in module format using Class::Accessor. Sure makes changes easier/quicker. There is also an additional process control example displaying 4 linear meters and 2 angular(round) meters. The updated code will be(has been) posted to github http://github.com/jmlynesjr/wxPerl-Module-Examples in a couple of days. For now, enjoy the clock code below.

Update1: Need to add another flag to signal 12/24 hour display format. And light one of the decimal points on am/pm. Creeping elegance..:).

Update2: Made the fix for 12/24 hour display and realised that I have polluted the LCDdisplay class with data that is only needed by the LCDClock program. I need to derive a sub-class of LDCdisplay to hold this data, It's always something...

Update3: Derived class version done and will be the version posted to github when I can get to it.

Update4: Alarm Clock version completed. Uses a wxMediaControl within an AudibleAlarm.pm class to play a selected MP3 file as the wakeup alarm sound.

Update5: Latest code now posted to GitHub. A new repository was created, so the URL above was changed.

LCDClock.pl

#! /home/pete/CitrusPerl/perl/bin/perl # LCDClock.pl # # Uses LCDdisplay.pm module to display an LCD Clock # Includes a flashing colon(:) to indicate seconds, if enabled # LCDdisplay.pm can display 0-F, :, -, _, and a few other special char +acters # Up/down count, display your favorite nationa debt, etc. # # James M. Lynes, Jr # Last Modified: February 4, 2013 # package main; use strict; use warnings; my $app = App->new(); $app->MainLoop; package App; use strict; use warnings; use base 'Wx::App'; sub OnInit { my $frame = Frame->new(); $frame->Show(1); } package Frame; use strict; use warnings; use Wx qw(:everything); use base qw(Wx::Frame); use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_TIMER); use LCDdisplay; use Data::Dumper; sub new { my($self) = @_; $self = $self->SUPER::new(undef, -1, "LCD Clock", wxDefaultPosition, [400, 200]); EVT_PAINT( $self, \&onPaint ); # Initialize event h +andlers EVT_SIZE( $self, \&onSize ); EVT_TIMER( $self, -1, \&onTimer); $self->{LCD} = LCDdisplay::Data->new(); # Create an LCD + object $self->{LCD}->mBlinkFlag(1); # Blink colon ? 1->yes $self->{LCD}->mNumberDigits(5); # 5 digit display i +ncluding : $self->{LCD}->mValue(""); # Initialize the disp +lay $self->SetBackgroundColour($self->{LCD}->mDefaultColour); # Bla +ck background my $timer = Wx::Timer->new($self); # Initialize 1 s +econd timer $timer->Start(1000); return $self; } 1; # # Dismiss a size event # sub onSize{ my($self, $event) = @_; $event->Skip(); } # # Draw the LCD # sub onPaint { my($self, $event) = @_; LCDdisplay->Draw($self, $self->{LCD}); } # # Format the time for display # sub onTimer { my($self, $event) = @_; my($min, $hour) = (localtime)[1,2]; my $colon = ":"; if($self->{LCD}->mBlinkFlag) { # Blink the colon? if($self->{LCD}->mToggle) { # yes, toggle the : $self->{LCD}->mToggle(0); $colon = ":"; } else { $self->{LCD}->mToggle(1); $colon = " "; } } my $minstr = sprintf("%02d", $min); my $hourstr = sprintf("%02d", $hour); $self->{LCD}->mValue($hourstr . $colon . $minstr); $self->Refresh(0); }

LCDdisplay.pm

#! /home/pete/CitrusPerl/perl/bin/perl # # LCDdisplay.pm # This script draws a simulated seven segment LCD Display. # Segments are drawn as 4 or 6 sided polygons # The colon(:) is drawn as 2 ellipses and takes up a character space # The decimal(.) is drawn as 1 ellipse and does not take a character s +pace # A leading decimal(.) must be prefaced by a 0 as 0.1234 # The string value to be displayed is stored in mValue # # Written in wxPerl. Tested on Citrus Perl 5.16 with wxWidgets 2.8.x. # Ported by: James M. Lynes. Jr. # Last Modified Date: February 4, 2013 # # Adapted from LCDWindow.cpp by Marco Cavallini # based in part(mostly) on the work of # the KWIC project (http://www.koansoftware.com/kwic/index.htm). # Referenced on pg 596 of the "Wx Book" - # "Cross-Platform GUI Programming with wxWidgets", Smart, Hock, & Csom +or # # package LCDdisplay; use 5.010; # Using Given/When use strict; use warnings; use Wx qw(:everything); use Data::Dumper; my %defaults = ( # Object initialization Data mSegmentLen => 40, mSegmentWidth => 10, mSpace => 5, mNumberDigits => 6, # width of mValue includ +ing . or : mValue => "", # Default string to be d +isplayed LCD_Number_Segments => 8, # Segment 7 is the decim +al point mLightColour => Wx::Colour->new(0, 255, 0), # Brigh +t green mGrayColour => Wx::Colour->new(0, 64, 0), # Dim gr +een mDefaultColour => Wx::Colour->new(0, 0, 0), # Black mCounter => 0, # use for up/down c +ounter mToggle => 0, # use to toggle the : mBlinkFlag => 0, # use to enable blinking +the : ); my %wxDigitData = ( # Actual string to be displ +ayed value => "", decimal => 0, # 1=true turns on the deci +mal point for digit ); my %ctbl = ( # Map character to segments - 0 => 0x3F, # Not defined in the 7-segme +nt "abcdefg" format 1 => 0x14, 2 => 0x6D, # ***0*** Bit Num +bers -654 3210 3 => 0x75, # * * 4 => 0x56, # 1 2 5 => 0x73, # * * 6 => 0x7B, # ***6*** 7 => 0x15, # * * 8 => 0x7F, # 3 4 9 => 0x77, # * * A => 0x5F, # ***5*** 7 B => 0x7A, C => 0x2B, D => 0x7C, E => 0x6B, F => 0x4B, '-' => 0x40, '_' => 0x20, '^' => 0x47, # code for degree symbol '=' => 0x61, # code for undefined symbo +l ' ' => 0x00, # code for a space ); # Other options could be added # # Paint the simulated LCD Display ------------------------------------ +---------------------- # sub Draw { my($class, $self, $lcd) = @_; my $disp = Wx::PaintDC->new($self); # Create paint +device context my( $dw, $dh) = $disp->GetSizeWH(); # Calculate dis +play scaling my $bw = GetBitmapWidth(); my $bh = GetBitmapHeight(); my $xs = $dw/$bw; my $ys = $dh/$bh; my $as = $xs > $ys ? $ys : $xs; $disp->SetUserScale($as, $as); $disp->SetDeviceOrigin((($dw-$bw*$as)/2), (($dh-$bh*$as)/2)); DoDrawing($disp, $lcd); # Paint the display } sub DoDrawing { my($dc, $lcd) = @_; my @cbuf = reverse(split(//,$lcd->mValue)); # Process o +ne character at a time my $cbuflen = @cbuf; if($cbuflen > $lcd->mNumberDigits) { # Truncate string +to max display width $cbuflen = $lcd->mNumberDigits; } my $ctr = 0; my $seg = 0; while($ctr < $cbuflen) { if($cbuf[$ctr] ne '.') { # Skip decimal point, +not drawn as a character $wxDigitData{value} = $cbuf[$ctr]; $wxDigitData{decimal} = 0; if($cbuf[$ctr-1] eq '.') {$wxDigitData{decimal} = 1;} # Turn o +n decimal point for this digit DrawDigit($dc, $seg, $lcd); $seg++; } $ctr++ } } sub DrawDigit { my($dc, $digit, $lcd) = @_; my $value = $wxDigitData{value}; my $dec = Decode($value); if($value eq ':') { # Draw a colon(:) DrawTwoDots($dc, $digit, $lcd); } else { my $ctr = 0; while($ctr < $lcd->LCD_Number_Segments-1) { DrawSegment($dc, $digit, $ctr, ($dec>>$ctr)&1, $lcd); $ctr++; } DrawSegment($dc, $digit, 7, $wxDigitData{decimal}, $lcd); # + Draw the decimal point } } sub DrawTwoDots { # Draws a colon(:) my($dc, $digit, $lcd) = @_; my $sl = $lcd->mSegmentLen; my $sw = $lcd->mSegmentWidth; my $sp = $lcd->mSpace; my $x = DigitX($digit); my $y = DigitY($digit); $x += ($sl/2)-$sw; $y += ($sl/2)-$sw; my $brushOn = Wx::Brush->new($lcd->mLightColour, wxSOLID); $dc->SetBrush($brushOn); $dc->SetPen(Wx::Pen->new($lcd->mDefaultColour, 1, wxSOLID)); $dc->DrawEllipse($x, $y, $sw*2, $sw*2); $y += $sl; $dc->DrawEllipse($x, $y, $sw*2, $sw*2); } sub DrawSegment { my($dc, $digit, $segment, $state, $lcd) = @_; my $sl = $lcd->mSegmentLen; my $sw = $lcd->mSegmentWidth; my $x = DigitX($digit); my $y = DigitY($digit); my $brushOn = Wx::Brush->new($lcd->mLightColour, wxSOLID); my $brushOff = Wx::Brush->new($lcd->mGrayColour, wxSOLID); if($state) { # bit set for On segment $dc->SetBrush($brushOn); # Bright color for On +segment } else { # bit cleared for Off segment $dc->SetBrush($brushOff); # Dim color for Off s +egment } $dc->SetPen(Wx::Pen->new($lcd->mDefaultColour, 1, wxSOLID)); my @points; # Verticies for 4 sided seg +ments my @p6; # Verticies for the 6 sided seg +ment given($segment) { when(0) { $points[0] = Wx::Point->new($x, $y); $points[1] = Wx::Point->new($x+$sl, $y); $points[2] = Wx::Point->new($x+$sl-$sw, $y+$sw); $points[3] = Wx::Point->new($x+$sw, $y+$sw); } when(1) { $points[0] = Wx::Point->new($x, $y); $points[1] = Wx::Point->new($x, $y+$sl); $points[2] = Wx::Point->new($x+$sw, $y+$sl-$sw/2); $points[3] = Wx::Point->new($x+$sw, $y+$sw); } when(2) { $x += $sl-$sw; $points[0] = Wx::Point->new($x,$y+$sw); $points[1] = Wx::Point->new($x+$sw, $y); $points[2] = Wx::Point->new($x+$sw, $y+$sl); $points[3] = Wx::Point->new($x, $y+$sl-$sw/2); } when(3) { $y += $sl; $points[0] = Wx::Point->new($x, $y); $points[1] = Wx::Point->new($x, $y+$sl); $points[2] = Wx::Point->new($x+$sw, $y+$sl-$sw); $points[3] = Wx::Point->new($x+$sw, $y+$sw-$sw/2); } when(4) { $x += $sl-$sw; $y += $sl; $points[0] = Wx::Point->new($x, $y+$sw/2); $points[1] = Wx::Point->new($x+$sw, $y); $points[2] = Wx::Point->new($x+$sw, $y+$sl); $points[3] = Wx::Point->new($x, $y+$sl-$sw); } when(5) { $y += 2*$sl-$sw; $points[0] = Wx::Point->new($x+$sw, $y); $points[1] = Wx::Point->new($x+$sl-$sw, $y); $points[2] = Wx::Point->new($x+$sl, $y+$sw); $points[3] = Wx::Point->new($x, $y+$sw); } when(6) { $y += $sl-$sw/2; $p6[0] = Wx::Point->new($x, $y+$sw/2); $p6[1] = Wx::Point->new($x+$sw, $y); $p6[2] = Wx::Point->new($x+$sl-$sw, $y); $p6[3] = Wx::Point->new($x+$sl, $y+$sw/2); $p6[4] = Wx::Point->new($x+$sl-$sw, $y+$sw); $p6[5] = Wx::Point->new($x+$sw, $y+$sw); } default {} } if($segment < 6) { # Draw the 4 sided segme +nts(0-5) $dc->DrawPolygon(\@points, 0, 0); } elsif($segment == 6) { # Draw the 6 sided segme +nt(6) $dc->DrawPolygon(\@p6, 0, 0); } else { # Draw the decimal point(7) $y += 2*$sl; $x += $sl; $dc->DrawEllipse($x+1, $y-$sw, $sw, $sw); } } sub Decode { $ctbl{$_[0]} // $ctbl{'='}} # Table lookup # for character translation # # Support subs ------------------------------------------------------- +--------------------- # sub GetDigitWidth { return $defaults{mSegmentLen} + $defaults{mSegmentWidth} + $defaul +ts{mSpace}; } sub GetDigitHeight { return ($defaults{mSegmentLen}*2) + ($defaults{mSpace}*2); } sub GetBitmapWidth { return ($defaults{mNumberDigits}*GetDigitWidth()) + $defaults{mSpa +ce}; } sub GetBitmapHeight { return GetDigitHeight(); } sub DigitX { my($digit) = @_; return GetBitmapWidth()-(($digit+1)*GetDigitWidth()); } sub DigitY { my($digit) = @_; return $defaults{mSpace}; } sub SetNumberDigits { my $ndigits = @_; $defaults{mNumberDigits} = $ndigits; } sub SetValue { my $value = @_; $defaults{mValue} = $value; } sub GetValue { return $defaults{mValue}; } sub GetNumberDigits { return $defaults{mNumberDigits}; } sub SetLightColour { my($ref) = @_; $defaults{mLightColour} = $ref; } sub SetGrayColour { my($ref) = @_; $defaults{mGrayColour} = $ref; } sub GetLightColour { return $defaults{mLightColour}; } sub GetGrayColour { return $defaults{mGrayColour}; } sub GetDigitsNeeded { my($string) = @_; $string =~ s/\.//g; return strlen($string); } package LCDdisplay::Data; use strict; use warnings; use Class::Accessor::Fast; use base qw(Class::Accessor::Fast); __PACKAGE__->mk_accessors(qw(mSegmentLen mSegmentWidth mSpace mNumberD +igits mValue LCD_Number_Segments mLightColour m +GrayColour mDefaultColour mCounter mToggle mBlinkFla +g)); sub new {shift->SUPER::new(@_, \%defaults);} 1;

James

There's never enough time to do it right, but always enough time to do it over...

Comment on wxPerl LCD Clock
Select or Download Code

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://1016975]
Approved by ww
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (10)
As of 2014-12-27 01:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (176 votes), past polls