好久沒寫過博客咯!瞎忙的不得了!整來整去沒整出個正經東西,目前自己實現的電子病歷已經投入使用,功能還不全面,很弱,質控以及標准化都還沒去細整,平時業余的時間一個人整,還真是沒那么多的時間與精力去一一的細化!哎,只能慢慢的來吧!年初整了個小米手機,功能上還是不錯的,不像某些人說的那么垃圾,總之我用的還是很不錯的。各種游戲,神馬的跑動起來小意思,流暢狠。今天要整的主題就是手機上的一個功能了,直接給搬運到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.
運行之后的效果就是