程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 淺析桌面精靈的實現

淺析桌面精靈的實現

編輯:Delphi

1    軟件的開發目的


   想必大家對桌面精靈很熟悉吧,想不想自己編一個?筆者非常想編一個,其目的居然是為了取得美眉的喜歡,由此引出了我開發本軟件的目的。如果讀者有我同樣的需求,那麼請繼續看下去,我將和你共同探討這個問題。注意以下示例代碼均用Delphi描述。
  

2    實現原理


   其實桌面精靈的原理很簡單,主要分以下幾步:
   1.獲取桌面窗口的HDC。
       API 定義如下:
       GetDC函數用於獲取指定窗口的圖形設備描述表
       HDC GetDC(
       HWND hWnd   // 窗口句柄
       );
       例如:
       DeskTopDC:HDC;//定義桌面窗口的圖形設備描述表句柄
       DeskTopDC:=GetDC(0);
       或者DeskTopDC:=GetDC(GetDesktopWindow());
   2.創建一個內存位圖,把桌面中將要繪圖的區域,保存到內存位圖中去,以便繪圖完成時恢復桌面。為此我定義了一個函數:
       procedure savebackground(BKCanvas :TCanvas;//內存位圖的畫布對象
                           sp_w:integer;//要保存區域的寬度
                           sp_h :integer ;//要保存區域的高度
                           nx:integer;//要保存區域的X坐標
                           ny:integer);//要保存區域的Y坐標
   3.將動畫對象透明地拷貝到桌面的繪圖區域,筆者用了一個GDIAPI函數方便地實現了此功能。
       定義如下:
       BOOL TransparentBlt(HDC hdcDest,//目標圖形設備描述表句柄
                           int nXOriginDest,//繪圖矩形的X坐標
                           int nYOriginDest,//繪圖矩形的Y坐標
                           int nWidthDest,//繪圖矩形的寬度
                           int hHeightDest,//繪圖矩形的高度
                           HDC hdcSrc,//源圖形設備描述表句柄
                           int nXOriginSrc,//源繪圖矩形的X坐標
                           int nYOriginSrc,//源繪圖矩形的Y坐標
                           int nWidthSrc,//源繪圖矩形的寬度
                           int nHeightSrc,//源繪圖矩形的高度
                           UINT crTransparent//設置透明色RGB(r,g,b)
                           );
       注意:
       Windows NT: 需要5.0或以上版本
       Windows: 需要 Windows 98 或 以上版本
       其它低版本不支持。
       此函數包含在msimg32.dll.
       筆者定義了一個tranbit函數來動態調用TransparentBlt函數,具體定義見第三節。
   4.將第二步生成的內存位圖拷貝到桌面。這樣一幀動畫就顯示完成。不斷循環1-4步,你就能看到連續的動畫場景了。
  

3.具體代碼


   以下是一個演示程序,在Delphi5.0+Windows2000P中調試通過。創建一個窗體Form1,放上兩個Image控件,命名為Image1,Image2,再放上一個Timer控件,命名為Timer1。准備兩張位圖,一張放入Image1,另一張放入Image2。筆者用了如下樣式的位圖(截取了一部分),你可以自己畫動畫對象,也可以借用別人的,筆者就是用微軟畫的圖片。
  
   從圖片你可以看出,圖片中包括了許多連續的動畫幀,一張圖片完成一個動作,如旋轉一周等,每幀動畫大小完全一樣,除了動畫對象其它像素用一種透明色填充。好了你可以看具體的代碼了。
  
   unit Unitmain;
   interface
   uses
     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
     ExtCtrls, StdCtrls,mmsystem;
  
   type
     TForm1 = class(TForm)
       Timer1: TTimer;//爆炸定時器
       Image1: TImage;//儲存爆炸的圖片
       Image2: TImage;//儲存飛行器的圖片
       procedure Timer1Timer(Sender: TObject);
       procedure FormCreate(Sender: TObject);
       procedure FormClose(Sender: TObject; var Action: TCloseAction);
     private
       { Private declarations }
       DeskTopDC:HDC;//桌面窗口的圖形設備描述表句柄
       stop:boolean;//控制循環的變量
       expnum:integer;//爆炸的當前次數
       procedure Explode(X:integer;Y:integer);//爆炸函數
       procedure shipmove(X:integer;Y:integer);//飛行器函數
     public
       { Public declarations }
     end;
   var
     Form1: TForm1;
      implementation
  
   {$R *.DFM}  
   //保存桌面背景
   procedure savebackground(BKCanvas :TCanvas;
                           sp_w:integer;
                           sp_h :integer ;
                           nx:integer;
                           ny:integer);
   var sc:TCanvas;
   begin
     sc:=TCanvas.Create;
     try
       sc.Handle:=GetDC(0);
       bkcanvas.CopyRect( rect(0,0,sp_w, sp_h), sc,rect(nx, ny, nx+sp_w, ny+sp_h));
       ReleaseDC(0, sc.handle);
     finally
       sc.free;
     end;
   end;
  
   //透明拷貝圖像函數
   //靜態調用API函數TransparentBlt
   procedure tranbit(hdcDest:HDC;
                       nXOriginDest:integer;
                       nYOriginDest:integer;
                       nWidthDest:integer;
                       hHeightDest:integer;
                       hdcSrc:HDC;
                       nXOriginSrc:integer;
                       nYOriginSrc:integer;
                       nWidthSrc:integer;
                       nHeightSrc:integer;
                       crTransparent:UINT) ;
   Var
       LibHandle:HWND;//動態連接庫句柄
       //函數原型定義
       DllName:Procedure(hdcDest:HDC;
                       nXOriginDest:integer;
                       nYOriginDest:integer;
                       nWidthDest:integer;
                       hHeightDest:integer;
                       hdcSrc:HDC;
                       nXOriginSrc:integer;
                       nYOriginSrc:integer;
                       nWidthSrc:integer;
                       nHeightSrc:integer;
                       crTransparent:UINT);Stdcall;
   begin
       //以下是靜態調用dll中函數的例行公事
       LibHandle:=LoadLibrary('msimg32.dll');
       if LibHandle<32 then
       begin
           MessageBox(Form1.Handle,'Not Found msimg32.dll','Error',0);
           Exit;
       end;
       @DllName:=GetProcAddress(LibHandle,'TransparentBlt');
       if @DllName=nil then
       begin
           MessageBox(Form1.Handle,'Not Found TransparentBlt in msimg32.dll','Error',0);
           FreeLibrary(LibHandle);
           Exit;
       end;
       try
           TransparentBlt(hdcDest,
                       nXOriginDest,
                       nYOriginDest,
                       nWidthDest,
                       hHeightDest,
                       hdcSrc,
                       nXOriginSrc,
                       nYOriginSrc,
                       nWidthSrc,
                       nHeightSrc,
                       crTransparent);
       finally
           FreeLibrary(LibHandle);
       end;
   end;
    
   //爆炸函數
   //在桌面的X,Y坐標處發生爆炸
   procedure TForm1.Explode(X:integer;Y:integer);
   var
       BitMapB : TBitMap;//保存桌面指定區域的內存位圖
       w:integer;//一幀動畫的寬度
       h:integer;//一幀動畫的高度
       i:integer;
       j:integer;
   begin
       BitMapB:=TBitMap.Create;
       try
           //動畫位圖為4*5=20幀
           w:=Image1.Width div 4;//計算每幀的寬度
           h:=image1.Height div 5;//計算每幀的高度
           //初始化內存為圖的大小
           BitMapB.Height :=h;
           BitMapB.Width :=w;
           //保存桌面上指定區域的位圖
           //注意,由於爆炸是在同一位置完成的,所以只要保存爆炸區域一次就行了。
           savebackground(BitMapB.canvas,w,h,X,Y);
           for i:=0 to 4 do
           begin
               for j:=0 to 3 do
               begin
                   //把相應幀畫到桌面上
                   tranbit(DeskTopDC ,x,y,w,h,
                           image1.Canvas.Handle,j*w,i*h,w,h,RGB(208,2,178));
                   Sleep(20);//顯示速度太快,停頓20毫秒
                   //恢復桌面
                   bitblt(DeskTopDC,X,Y,w,h,BitMapB.Canvas.handle,0,0,srccopy);
               end;
           end;
       finally
           BitMapB.Free;
       end;
   end;
    
   //飛行器的飛行函數
   //參數x,y指定飛行器飛行的目的地
   procedure TForm1.shipmove(X:integer;Y:integer);
   var
       w:integer;
       h:integer;
       i:integer;
       j:integer;
       k:integer;
       l:integer;
       BitMapB : TBitMap;
   begin
       Randomize();
       BitMapB:=TBitMap.Create;
       try
           //動畫位圖為4*16-3幀空幀=61幀
           w:=Image2.Width div 4;
           h:=image2.Height div 16;
           BitMapB.Height :=h;
           BitMapB.Width :=w;
           k:=0;
           l:=0;
           while not stop do
               for i:=0 to 15 do
                   for j:=0 to 3 do
                   begin
                       if (i=15) and (i>0) then break;//如果是空幀就不畫了
                   //保存桌面上指定區域的位圖
               //注意,由於飛行是在不同位置完成的,所以要保存即將被繪圖的桌面區域
                       savebackground(BitMapB.canvas,w,h,k,l);
       tranbit(DeskTopDC ,k,l,w,h,image2.Canvas.Handle,j*w,i*h,w,h,RGB(208,2,178));
    
                       sleep(10);
                       bitblt(DeskTopDC,k,l,w,h,BitMapB.Canvas.handle,0,0,srccopy);
                       if(k<x)then k:=k+1;
                       if(l<y)then l:=l+1;
                       if timer1.Enabled =false then
                       if(k>x-10)then//到達目的地就停止飛行,並引爆炸彈
                       begin
                           stop:=true;
                           timer1.Enabled :=true;//炸彈引爆器
                       end;
               end;
       finally
           BitMapB.Free;
       end;
   end;
    
   procedure TForm1.Timer1Timer(Sender: TObject);
   var
       x,y:integer;
   begin
      
       if(expnum = 0) then
       begin
           Explode(screen.width div 2-20,screen.Height div 2-20);
           sndPlaySound('explosion.wav',SND_NOSTOP);
           expnum:=expnum+1;
       end
       else if expnum<10 then//爆炸最多10次
       begin
           //產生隨機位置
           x:=Random(screen.Width-100);
           y:=Random(Screen.Height-100);
           Explode(x,y);//爆炸
           sndPlaySound('explosion.wav',SND_NOSTOP);//播放爆炸聲音
           expnum:=expnum+1;
       end
       else
       begin
           stop:=true;
           timer1.Enabled :=false;
           close();
       end;
   end;
    
   procedure TForm1.FormCreate(Sender: TObject);
   begin
       DeskTopDC:=GetDC(0);
       chdir(ExtractFilePath(application.ExeName));
       stop:=false;
       expnum:=0;
       //飛行器開始飛行,目的地為屏幕中央
       self.shipmove(screen.width div 2,screen.Height div 2);
   end;
    
   procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
   begin
       stop:=true;
       Timer1.Enabled :=false;
       ReleaseDC(0, DeskTopDC);
   end;
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved