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