模拟Windows任务管理器CPU使用率的动态折线图-农夫山泉

Delphi的TCanvas类可以实现各种复杂的图形输出功能,基于近期项目的需求,利用它实现了一个很炫的动态折线图(模拟了资源管理器中CPU使用率的折线图),可以直观地展现出数值的实时变化情况。

这段代码里边有几个核心的地方:

  • 首先是为了缓解刷新时画布闪烁,利用了双缓冲的原理;
  • 其次结合队列,保证了数据的顺序压入;
  • 还有就是一些简单的数组算法。

最终的效果如下:

单元代码如下:

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls,Contnrs;
 
const
  {* 网格间隔 *}
  GridSpace = 12;
  {* 移动步长(能够被间隔整除) *}
  MoveStep = 3;
  {* Y轴最大值(最大刻度) *}
  MaxY = 100;
 
type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Button1: TButton;
    Image1: TImage;
    procedure DrawPL(Shower:TImage);
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
  {* 网格竖线X坐标数组 *}
  GridXPArr: array of Integer;
  {* 点坐标数组 *}
  PointLst: array of TPoint;
  {* 数值队列 *}
  YPQueue: TQueue;
  {* 数值指针 *}
  PYValue: PInteger;
  {* 网格偏移量 *}
  X: Word;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
var
  YValue:Integer;
begin
  Randomize;
  YValue := Random(100);
  //新Y坐标点按顺序压入队列
  New(PYValue);
  PYValue^ := YValue;
  YPQueue.Push(PYValue);
end;
 
procedure TForm1.DrawPL(Shower:TImage);
var
  Bit: TBitmap;
  i: Integer;
  PW,PH: Integer;
  YValue:Integer;
begin
  //偏移量计算
  Inc(X);
  if X = GridSpace div MoveStep then
  X := 0;
  //初始化画布(双缓冲)
  Bit := TBitmap.Create;
  try
    PW := Shower.Width;
    PH := Shower.Height;
    Bit.Width := PW;
    Bit.Height := PH;
    //初始化网格竖线X坐标数组长度为宽/间隔+1
    SetLength(GridXPArr,PW div GridSpace + 1);
    with Bit.Canvas do
    begin
      Brush.Color := clBlack;
      Brush.Style := bsSolid;
      Rectangle(0,0,PW,PH);
      Pen.Color := $00408000;
      //画网格,根据偏移量实现动态效果
      for i := 0 to PW div GridSpace + 1 do
      begin
        GridXPArr[i] := GridSpace * i - X * MoveStep;
        MoveTo(GridXPArr[i],0);
        LineTo(GridXPArr[i],PH);
      end;
      for i := 0 to PH div GridSpace do
      begin
        MoveTo(0,GridSpace * i);
        LineTo(PW,GridSpace * i);
      end;
      //画折线
      Pen.Color := clLime;
      YValue := 0;
      //如果队列中有新的Y坐标点,则输出
      if YPQueue.Count > 0 then
      begin
        PYValue := YPQueue.Pop;
        YValue := PYValue^;
        Dispose(PYValue);
      end;
      //画笔移动到起点位置
      MoveTo(0,PH);
      //每执行一次函数,Y坐标向前移动一位,并连线各个点
      for i := 0 to Length(PointLst) - 2 do
      begin
        PointLst[i].Y := PointLst[i + 1].Y;
        LineTo(PointLst[i+1].X,PointLst[i+1].Y);
      end;
      //按比例更新最后一位坐标点
      PointLst[Length(PointLst)-1].X := PW;
      PointLst[Length(PointLst)-1].Y := PH - (YValue  * PH div MaxY);
      //打印信息(可根据需要调整显示位置和内容)
      Brush.Style:=bsClear;
      Font.Color:=clYellow;
      TextOut(10,10,'数值:'+inttostr(YValue));
    end;
    Shower.Canvas.Draw(0,0,Bit);
  finally
    Bit.Free;
  end;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
var
  i:Integer;
begin
  YPQueue := TQueue.Create;
  //初始化坐标点个数为宽/步长+1
  SetLength(PointLst,Image1.Width div MoveStep + 1);
  //初始化坐标点为X轴基线位置
  for i := 0 to Length(PointLst) - 1 do
  begin
    PointLst[i].X := i*MoveStep;
    PointLst[i].Y := Image1.Height;
  end;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  YPQueue.Free;
end;
 
procedure TForm1.FormShow(Sender: TObject);
begin
  DrawPL(Image1);
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  DrawPL(Image1);
end;
 
end.

 

posted on 2015-09-18 09:47  雪夜  阅读(1429)  评论(0编辑  收藏  举报