我的微店
得闲笔记
我命由我不由天

    好久没写过博客咯!瞎忙的不得了!整来整去没整出个正经东西,目前自己实现的电子病历已经投入使用,功能还不全面,很弱,质控以及标准化都还没去细整,平时业余的时间一个人整,还真是没那么多的时间与精力去一一的细化!哎,只能慢慢的来吧!年初整了个小米手机,功能上还是不错的,不像某些人说的那么垃圾,总之我用的还是很不错的。各种游戏,神马的跑动起来小意思,流畅狠。今天要整的主题就是手机上的一个功能了,直接给搬运到Delphi上来。那就是手机锁屏之后,开屏的时候,要求咱们输入密码的那个滑动效果输入的控件。想想,整在软件中,用来在客户离开计算机,锁屏的时候还是蛮不错的一种方式,而且一般的图形图像给人的记忆比纯粹的数字文字类的更能让人印象深刻。所以决定将这个东西整到PC上来。

   Android的那个锁屏的效果,用过的人应该都知道是个什么效果,也就是横竖各3行,排列成九宫格的效果,然后由用户在上面滑动以此来达到密码输入进而进行解锁和加密的效果。那么首先,俺们可以分析一下,他的具体形成思路,实际上是很简单的,就是一个排列,然后根据滑动产生的内容形成密码来达到解密的目的,那么最主要的就是这个密码和他本身的密码是如何对应解密的,实际上很简单,咱们给他排列的九宫格,都固定好位置

1 2 3
4 5 6
7 8 9

就像这样,排列的给他的位置固定好,然后每一个格子表示一个字符或者说字符串,进而用户滑动的时候,将对应的位置序列进入到一个列表中去保存,然后鼠标放开的时候,那么入队的选择位置进行组合,那么就是对应的密码了,比如

这样的输入就是表示123,如此顺序记录,就可以形成密码了,然后用户进行滑屏录入之后和以前的进行比较就可以知道密码是否正确了,当然我这个组合是相当简单的,如果想要整的复杂,可以给每个顺序位置给定复杂的字符串,这样形成的密码就足够的复杂了!给一般人去看,也是看不明白的。

那么分析清楚了,思路也就简单了,鼠标按下的时候,开始可以滑动形成密码,鼠标按下的第一个点,作为队列的第一个,然后再滑过的就顺序的一一的记录到队列中,鼠标放开的时候,从队列中获取各个顺序位置,组合形成密码然后和原密码比对,判断密码是否正确!源码如下:

{
  Delphi实现的类似Android鼠标锁屏效果的控件
  作者:不得闲
  2012-7-23
}
unit AndroidLockControl;

interface
uses Windows,Classes,SysUtils,Graphics,Controls;

type
  TDxLockItem = class
  private
    r: TRect;
    IsEnter: Boolean;
    IsChecked: Boolean;
    Value: AnsiChar;
    FRadio: TPoint;
  public
    constructor Create;
  end;

  TInPutPwdEvent = procedure(Sender: TObject;InputPwd: string) of object;
  TDxAndroidLock = class(TGraphicControl)
  private
    FItemSpace: Integer;
    FRowCount: Integer;
    FColCount: Integer;
    FItemRaidio: Integer;
    Items: TList;
    FUseNum: Boolean;
    FPassword: string;
    IsDown: Boolean;
    LastInItem: TDxLockItem;
    PwdItems: TList;
    FOnInputPwd: TInPutPwdEvent;
    procedure SetItemSpace(const Value: Integer);
    procedure SetItemRaidio(const Value: Integer);
    procedure SetUseNum(const Value: Boolean);
  protected
    procedure paint;override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure CalcItemRects;
  public
    constructor Create(AOwner: TComponent);override;
    destructor Destroy;override;
    property Password: string read FPassword write FPassWord;
  published
    property ItemSpace: Integer read FItemSpace write SetItemSpace default 10;
    property OnInputPwd: TInPutPwdEvent read FOnInputPwd write FOnInputPwd;
    property ItemRaidio: Integer read FItemRaidio write SetItemRaidio default 20;
    property UseNum: Boolean read FUseNum write SetUseNum;
  end;
implementation
uses pngimage;
{$R LockRc.RES}
var
  PngIn,PngOut: TPngImage;
{ TDxAndroidLock }

procedure TDxAndroidLock.CalcItemRects;
var
  i,j: Integer;
  p: TPoint;
  r: TRect;
  item: TDxLockItem;
begin
  p.Y := FItemRaidio;
  for i := 1 to 3 do
  begin
    p.X := FItemRaidio;
    r.Left := p.X - FItemRaidio;r.Top := p.Y - FItemRaidio;
    r.Right := p.x + FItemRaidio;r.Bottom := p.Y + FItemRaidio;
    for j := 1 to 3 do
    begin
      item := Items[3*(i-1)+j - 1];
      item.Value := AnsiChar(3*(i-1)+j+48);
      item.FRadio := p;
      item.r := r;
      p.X := p.X + FItemRaidio * 2 + FItemSpace;
      r.Left := p.X - FItemRaidio;r.Right := p.X + FItemRaidio;
    end;
    p.Y := p.Y + FItemRaidio * 2 + FItemSpace;
  end;
end;

constructor TDxAndroidLock.create(AOwner: TComponent);
var
  i: Integer;
begin
  inherited;
  LastInItem := nil;
  PwdItems := TList.Create;
  FPassWord := '';
  Items := TList.Create;
  FItemSpace := 10;
  FRowCount := 3;
  FColCount := 3;
  FItemRaidio := 20;
  Width := FItemRaidio * 2 * 3 + FItemSpace * 2;
  Height := FItemRaidio * 2 * 3 + FItemSpace * 2;
  for i := 0 to 8 do
  begin
    Items.Add(TDxLockItem.Create);
  end;
  CalcItemRects;
end;

destructor TDxAndroidLock.Destroy;
begin
  while Items.Count > 0 do
  begin
    TDxLockItem(Items[Items.Count - 1]).Free;
    Items.Delete(Items.Count - 1);
  end;
  PwdItems.Free;
  inherited;
end;

procedure TDxAndroidLock.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  IsDown := Button = mbLeft;
  if IsDown then
  begin
    if LastInItem <> nil then
    begin
      LastInItem.IsChecked := IsDown;
      PwdItems.Add(LastInItem);
    end;
    Invalidate;
  end;
end;

procedure TDxAndroidLock.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  i: Integer;
  p: TPoint;
  OldInItem,Item: TDxLockItem;
begin
  OldInItem := LastInItem;
  p := Point(x,y);
  LastInItem := nil;
  for i := 0 to items.Count - 1 do
  begin
    item := Items[i];
    if PtInRect(Item.r,p) then
    begin
      LastInItem := Item;
      LastInItem.IsEnter := True;
      LastInItem.IsChecked := IsDown;
      Break;
    end;
  end;
  if LastInItem <> OldInItem then
  begin
    if OldInItem <> nil then
      OldInItem.IsEnter := False;
    if IsDown then
    begin
      if LastInItem <> nil then
      begin
        PwdItems.Add(LastInItem);
      end;
      Invalidate;
    end;
  end;
end;

procedure TDxAndroidLock.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  i: Integer;
  item: TDxLockItem;
  Np: string;
begin
  IsDown := False;
  for i := 0 to items.Count - 1 do
  begin
    item := Items[i];
    item.IsChecked := False;
  end;
  for i := 0 to PwdItems.Count - 1 do
    Np := Np + TDxLockItem(PwdItems[i]).Value;
  PwdItems.Clear;
  Invalidate;
  if Assigned(FOnInputPwd) then
    FOnInputPwd(self,Np);
end;

procedure DrawLineArrow(canvas: TCanvas; p1, p2: TPoint);
const
  l = 6; //箭头长度
  w = 4; //箭头宽度
var
  slope, angle: Double;
  points: array[0..2] of TPoint;
  Xl,b: Single;
begin
  canvas.Brush.Color := canvas.Pen.Color;
  canvas.Brush.Style := bsSolid;
  canvas.MoveTo(p1.X,p1.Y);
  canvas.LineTo(p2.X,p2.Y);
  if (p2.Y <> p1.Y) and (P2.X <> p1.X) then
  begin
    xl := (P2.Y - p1.Y) / (P2.X - p1.X);
    b := p2.Y - xl * p2.X;
    p2.X := (p2.X - p1.X) div 2 + p1.X;
    p2.Y := Trunc(p2.X * xl + b);
  end
  else if p2.Y = p1.Y then
    p2.X := (p2.X - p1.X) div 2 + p1.X
  else P2.Y := (p2.Y - p1.Y) div 2 + p1.Y;
//画箭头
  points[0] := Point(p2.x, p2.y);//箭头顶点
  if (p2.x - p1.x = 0) then
  begin //垂直
    if (p2.y - p1.y > 0) then slope := -1 else slope := 1;
    points[1] := Point(p2.x - w, p2.y + Trunc(l * slope));
    points[2] := Point(p2.x + w, p2.y + Trunc(l * slope));
  end else
  begin //倾斜
    slope := (p2.y - p1.y) / (p2.x - p1.x);
    angle := ArcTan(slope);
    if (p2.x - p1.x > 0) then angle := angle - PI;
    points[1] := Point(p2.x + trunc(l * cos(angle) - w * sin(angle)),
      p2.y + trunc(l * sin(angle) + w * cos(angle)));
    points[2] := Point(p2.x + Trunc(l * cos(angle) + w * sin(angle)),
      p2.y + Trunc(l * sin(angle) - w * cos(angle)));
  end;
  canvas.Polygon(points);
end;

procedure TDxAndroidLock.paint;
var
  i: Integer;
  item,item1: TDxLockItem;
  r: TRect;
begin
  if not IsDown then
  begin
    for i := 0 to Items.Count - 1 do
    begin
      item := items[i];
      r.Left := item.FRadio.X - 5;r.Right := item.FRadio.X + 5;
      r.Top := item.FRadio.Y - 5;r.Bottom := item.FRadio.Y + 5;
      Canvas.Draw(r.Left,r.Top,pngIn);
    end;
  end
  else
  begin
    //绘制指向线条
    Canvas.Pen.Width := 2;
    Canvas.Pen.Color := clGreen;
    for i := 0 to PwdItems.Count - 2 do
    begin
      item := PwdItems[i];
      item1 := PwdItems[i + 1];
      Canvas.MoveTo(item.FRadio.X,item.FRadio.Y);
      Canvas.LineTo(item1.FRadio.X,item1.FRadio.Y);
      DrawLineArrow(Canvas,item.FRadio,item1.FRadio);
    end;
    for i := 0 to Items.Count - 1 do
    begin
      item := items[i];
      if item.IsChecked then
      begin
        Canvas.Draw(item.r.Left,item.r.Top,pngOut);
      end;
      r.Left := item.FRadio.X - 5;r.Right := item.FRadio.X + 5;
      r.Top := item.FRadio.Y - 5;r.Bottom := item.FRadio.Y + 5;
      Canvas.Draw(r.Left,r.Top,pngIn);
    end;
  end;
end;

procedure TDxAndroidLock.SetItemRaidio(const Value: Integer);
begin
  FItemRaidio := Value;
end;

procedure TDxAndroidLock.SetItemSpace(const Value: Integer);
begin
  FItemSpace := Value;
end;

procedure TDxAndroidLock.SetUseNum(const Value: Boolean);
begin
  FUseNum := Value;
end;

{ TDxLockItem }

constructor TDxLockItem.Create;
begin
  r := Rect(0,0,0,0);
  IsEnter := False;
end;

initialization
 PngIn := TPngImage.Create;
 PngIn.LoadFromResourceName(Hinstance,'InnerGra');
 PngOut := TPngImage.Create;
 PngOut.LoadFromResourceName(Hinstance,'Outer');

finalization
  PngIn.Free;
  PngOut.Free;
end.

运行之后的效果就是

posted on 2012-07-23 14:44  不得闲  阅读(5448)  评论(5编辑  收藏  举报