Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
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 learning in the Monastery: (3)
As of 2024-04-24 03:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found