Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

wxPerl Simulated Round Panel Meter

by jmlynesjr (Deacon)
on Jan 20, 2013 at 17:54 UTC ( [id://1014312]=CUFP: print w/replies, xml ) Need Help??

Another wxPerl example ported from the "wxBook" and wxIndustrial Controls. This one draws a round panel meter. Move your mouse across the meter display to move the needle.

Use this meter with Device::Serialport::Arduino to display analog data from your Arduino of choice.

#! /home/pete/CitrusPerl/perl/bin/perl # # AngularMeter.pl # This script draws a simulated round panel meter. # # # Written in wxPerl. Tested on Citrus Perl 5.16 with wxWidgets 2.8.x. # Ported by: James M. Lynes. Jr. # Last Modified Date: January 20, 2013 # # Adapted from AngularMeter.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 # # Added limit checking with green/red zones - Normal/Hi-limit # could reverse colors to alarm on a low limit if needed. # Added animation - ***Needle follows left/right mouse movement*** # Added Meter identification label # Could add mouse click event to capture value at that point # and use the meter as an input device. # use 5.010; use strict; use warnings; use Wx qw(:everything :allclasses); use Wx::Event qw( EVT_PAINT EVT_SIZE EVT_MOTION); use Math::Trig; # # Configuration Data ------------------------------------------------- +----------------- # my $MeterWidth = 350; # Define the meter size my $MeterHeight = $MeterWidth; # Must be square to look + right my $ScaledVal = 0; my $RealVal = 0; my $Tick = 9; # Number of tic marks my $Sec = 2; # Number of sections - green/red my $RangeStart = 0; # Define Meter Span - Min my $RangeEnd = 100; # - Max my $AlarmLimit = 65; # Alarm Limit my $AngleStart = -20; # East is 0 degrees, + is CCW my $AngleEnd = 200; my @SectorColours = (wxGREEN, wxRED); # Only using two sect +ions my $BackColour = wxLIGHT_GREY; my $NeedleColour = wxBLACK; my $BorderColour = wxBLUE; my $PI = 4.0*atan(1.0); my $Font = Wx::Font->new(10, wxFONTFAMILY_SWISS, wxNORMAL, wxNORMAL); my $DrawCurrent = 1; # Turn on/off value displayed +as text my $Label = "Process Temperature - degC"; # Label Meter at bott +om of display my $ramp = 25; # Initial value/needle position my $lastpos = 0; # Last mouse position # # Main Application --------------------------------------------------- +-------------------- # my $app = Wx::SimpleApp->new; my $frame = Wx::Frame->new(undef, -1, "Simulated Round Panel Meter", wxDefaultPosition, [$MeterWidth, $MeterHeight]); SetValue($ramp); # Initial value/needle position EVT_PAINT( $frame, \&onPaint ); EVT_SIZE( $frame, \&onSize ); EVT_MOTION( $frame, \&onMotion ); $frame->Show; $app->MainLoop; # # Dismiss a size event # sub onSize{ my($self, $event) = @_; $event->Skip(); } sub onMotion { # Change the setpoint value and +redraw my($self, $event) = @_; my $x = $event->GetPosition->x; # Current mouse positio +n if($x > $lastpos) {$ramp += 1; $lastpos = $x} # Mouse right, in +crement needle if($x < $lastpos) {$ramp -= 1; $lastpos = $x} # Mouse left, dec +rement needle if($ramp >= $RangeEnd) {$ramp = $RangeEnd;} # Clamp to max +range if($ramp <= $RangeStart) {$ramp = $RangeStart;} # Clamp to min +range SetValue($ramp); $self->Refresh; $self->Update; } # # Paint the simulated LCD Display ------------------------------------ +---------------------- # sub onPaint { my($self, $event) = @_; my $dc = Wx::PaintDC->new($self); my( $w, $h) = $dc->GetSizeWH(); my $memdc = Wx::MemoryDC->new(); $memdc->SelectObject(Wx::Bitmap->new($MeterWidth, $MeterHeight)); my $brush = Wx::Brush->new($BackColour, wxSOLID); $memdc->SetBackground($brush); $memdc->SetBrush($brush); $memdc->Clear(); my $pen = Wx::Pen->new($BorderColour, 2, wxSOLID); $memdc->SetPen($pen); $memdc->DrawRectangle(0, 0, $w, $h); DrawSectors($memdc); if($Tick > 0) {DrawTicks($memdc);} DrawNeedle($memdc); if($DrawCurrent) { # Display current value as t +ext my $valuetext = sprintf("%d", $RealVal); my @te = $memdc->GetTextExtent($valuetext); my $x = ($w-$te[0])/2; $memdc->SetFont($Font); $memdc->DrawText($valuetext, $x, ($h/2)+20); } DrawLabel($memdc); $dc->Blit(0, 0, $w, $h, $memdc, 0, 0); } sub DrawNeedle { my($dc) = @_; my($w, $h) = $dc->GetSizeWH(); my $pen = Wx::Pen->new($NeedleColour, 1, wxSOLID); $dc->SetPen($pen); my $brush = Wx::Brush->new($NeedleColour, wxSOLID); $dc->SetBrush($brush); my $val = ($ScaledVal + $AngleStart) * $PI/180; my $dyi = sin($val-90)*2; my $dxi = cos($val-90)*2; my @points; $points[0] = Wx::Point->new($w/2-$dxi, $h/2-$dyi); $dxi = cos($val) * ($h/2-4); $dyi = sin($val) * ($h/2-4); $points[2] = Wx::Point->new($w/2-$dxi, $h/2-$dyi); $dxi = cos($val+90)*2; $dyi = sin($val+90)*2; $points[4] = Wx::Point->new($w/2-$dxi, $h/2-$dyi); $points[5] = $points[0]; $val = ($ScaledVal + $AngleStart + 1) * $PI/180; $dxi = cos($val) * ($h/2-10); $dyi = sin($val) * ($h/2-10); $points[3] = Wx::Point->new($w/2-$dxi, $h/2-$dyi); $val = ($ScaledVal + $AngleStart - 1) * $PI/180; $dxi = cos($val) * ($h/2-10); $dyi = sin($val) * ($h/2-10); $points[1] = Wx::Point->new($w/2-$dxi, $h/2-$dyi); $dc->DrawPolygon(\@points, 0, 0, wxODDEVEN_RULE); $brush = Wx::Brush->new(wxWHITE, wxSOLID); # Draw white + dot at base of needle $dc->SetBrush($brush); $dc->DrawCircle($w/2, $h/2, 4); } sub DrawSectors { my($dc) = @_; my($w, $h) = $dc->GetSizeWH(); my $pen = Wx::Pen->new(wxBLACK, 1, wxSOLID); $dc->SetPen($pen); my $starc = $AngleStart; my $endarc = $starc + (($AngleEnd - $AngleStart) * ($AlarmLimit/$R +angeEnd)); my $ctr = 0; while($ctr < $Sec) { my $brush = Wx::Brush->new($SectorColours[$ctr], wxSOLID); $dc->SetBrush($brush); $dc->DrawEllipticArc(0, 0, $w, $h, 180-$endarc, 180-$starc); $starc = $endarc; $endarc = $AngleEnd; $ctr++; } my $val = $AngleStart * $PI / 180; my $dx = cos($val) * $h/2; my $dy = sin($val) * $h/2; $dc->DrawLine($w/2, $h/2, $w/2-$dx, $h/2-$dy); $val = $AngleEnd * $PI / 180; $dx = cos($val) * $h/2; $dy = sin($val) * $h/2; $dc->DrawLine($w/2, $h/2, $w/2-$dx, $h/2-$dy); } sub DrawTicks { my($dc) = @_; my($w, $h) = $dc->GetSizeWH(); my $interval = ($AngleEnd - $AngleStart) / ($Tick +1); my $valint = $interval + $AngleStart; my $ctr = 0; while($ctr < $Tick) { my $val = $valint * $PI/180; my $dx = cos($val) * $h/2; my $dy = sin($val) * $h/2; my $tx = cos($val) * (($h/2)-10); my $ty = sin($val) * (($h/2)-10); $dc->DrawLine($w/2-$tx, $h/2-$ty, $w/2-$dx, $h/2-$dy); my $DeltaRange = $RangeEnd - $RangeStart; my $DeltaAngle = $AngleEnd - $AngleStart; my $Coeff = $DeltaAngle / $DeltaRange; my $rightval = (($valint - $AngleStart) / $Coeff) + $RangeStar +t; my $string = sprintf("%d", $rightval+.5); my($tew, $teh, $dct, $ext) = $dc->GetTextExtent($string); $val = ($valint - 4) * $PI/180; $tx = cos($val) * (($h/2)-12); $ty = sin($val) * (($h/2)-12); $dc->SetFont($Font); $dc->DrawRotatedText($string, $w/2-$tx, $h/2-$ty, 90-$valint); $valint = $valint + $interval; $ctr++; } } sub SetValue { # Scale the value for displa +y my($Value) = @_; my $DeltaRange = $RangeEnd - $RangeStart; my $RangeZero = $DeltaRange - $RangeStart; my $DeltaAngle = $AngleEnd - $AngleStart; my $Coeff = $DeltaAngle / $DeltaRange; $ScaledVal = ($Value - $RangeStart) * $Coeff; $RealVal = $Value; } sub DrawLabel { # Draw a label at bottom of + meter my($dc) = @_; my($w, $h) = $dc->GetSizeWH(); my @te = $dc->GetTextExtent($Label); my $x = ($w-$te[0])/2; $dc->DrawText($Label, $x, $h-25); }

James

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

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (3)
As of 2024-03-19 05:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found