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

Delphi 實現照片抽獎-原創,

編輯:Delphi

Delphi 實現照片抽獎-原創,


有單位年會要用照片抽獎,上網搜了幾個都不滿意,且居然還要收費。自己寫一個算了。只是有一點不爽,Delphi 7 在 Windows 7 64位下有問題,不能雙擊 dpr 文件直接打開項目!

關於性能:

  • 因為總數不大(沒超過100個),所以一次性全部載入內存保存,啟動速度也不慢,秒開。以流的形式保存,因為可直接使用 TJPEGImage 的 LoadFromStream 方法。如果照片很多,那就要掂量掂量內存占用情況了。實時讀取文件的話,同時還要考慮磁盤讀寫的延時。
  • 圖片分辨率對 JPG 的解壓、顯示的速度影響較大(i3 CPU、B75主板、8G內存):
    4288*2848——耗時 260ms
    1440*956——耗時 109ms
    1156*768——耗時 63ms
    因此,必須限制原始圖片的分辨率,寧可放大顯示。如果對顯示性能要求較高,比如圖片切換間隔要求小於100ms(不過短於視覺暫留時間的話就看不見了),必須別想他法。

廢話不說,上代碼。

  1 unit main;
  2 
  3 interface
  4 
  5 uses
  6   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7   Dialogs, StdCtrls, ExtCtrls, ComCtrls, Menus, Jpeg;
  8 
  9 type
 10   TMainForm = class(TForm)
 11     MainTimer: TTimer;
 12     PopMenu: TPopupMenu;
 13     MenuClear: TMenuItem;
 14     MainPaint: TPaintBox;
 15     ExitMenu: TMenuItem;
 16     procedure MainTimerTimer(Sender: TObject);
 17     procedure FormKeyPress(Sender: TObject; var Key: Char);
 18     procedure FormClose(Sender: TObject; var Action: TCloseAction);
 19     procedure FormCreate(Sender: TObject);
 20     procedure MenuClearClick(Sender: TObject);
 21     procedure MainPaintPaint(Sender: TObject);
 22     procedure ExitMenuClick(Sender: TObject);
 23   private
 24     { Private declarations }
 25     procedure ShowPhoto(paint:TPaintBox; src:TGraphic; const name:string);
 26   public
 27     { Public declarations }
 28   end;
 29 
 30 const
 31   BufferSize=64;              //缺省照片緩存大小
 32   CoverFileName='COVER.JPG';  //封面圖片
 33   WinnerFileName='中獎.txt';  //抽獎結果文件
 34   
 35   TextColor=clRed;    //顯示文字顏色
 36   TextSize=72;        //顯示文字大小
 37   TextFont='華文行楷';//顯示文字字體
 38 
 39 var
 40   MainForm: TMainForm;
 41   PhotoIndex:integer=0;     //當前顯示的圖片索引
 42   PhotoCount:integer=0;     //圖片總數
 43   Names : array of string;  //圖片名稱緩存
 44   Photos : array of TMemoryStream; //JPG文件流緩存
 45   Selected : array of integer;  //已中獎圖片標志
 46   SelectedCount : integer=0;    //已中獎數量,如果全部中獎則停止抽獎
 47   Log : TStringList;  //中獎記錄,存入文本文件
 48 
 49   jpg:TJpegImage;   //解壓JPG用的公用變量
 50   Times:Cardinal;   //定時器事件的執行次數
 51 
 52   bmpPaint:TBitmap; //作為PaintBox的顯示緩存
 53 
 54 implementation
 55 
 56 {$R *.dfm}
 57 
 58 {
 59 procedure Mosaic(dest:TBitmap; src:TBitmap);
 60 var
 61   i,x,y:Integer;  
 62   from:TRect;
 63   bmpwidth,bmpheight:Integer;
 64 const  
 65   squ=20;
 66 begin  
 67   bmpwidth:=src.Width;
 68   bmpheight:=src.Height;
 69 
 70   dest.Width:=bmpwidth;
 71   dest.Height:=bmpHeight; 
 72 
 73   for i:=0 to 400 do
 74   begin
 75     Randomize;
 76     x:=Random(bmpwidth div squ);  
 77     y:=Random(bmpheight div squ);  
 78     from:=Rect(x*squ,y*squ,(x+1)*squ,(y+1)*squ);
 79     dest.Canvas.CopyRect(from,Src.Canvas,from);
 80   end;  
 81 end;
 82 
 83 procedure Alpha(bitmap:TBitmap; jpg:TJPEGImage);
 84 var
 85   BlendFunc: TBlendFunction;
 86   bit:TBitmap;
 87 begin
 88   bit := TBitMap.Create;
 89   try
 90     jpg.DIBNeeded;
 91     bit.Assign(jpg);
 92     BlendFunc.BlendOp := AC_SRC_OVER;
 93     BlendFunc.BlendFlags := 0;
 94     BlendFunc.AlphaFormat := 0;
 95     BlendFunc.SourceConstantAlpha := 127;
 96     windows.AlphaBlend(bitmap.Canvas.Handle, 0, 0, bit.Width, bit.Height,
 97                        bit.Canvas.Handle,  0, 0, bit.Width, bit.Height,
 98                        BlendFunc);
 99   finally
100     bit.Free;
101   end;
102 end;
103 }
104 
105 //源圖等比縮放後填充目標圖片,width、height指定可用顯示區域的大小
106 procedure ZoomFill(dest:TBitMap; src:TGraphic; width,Height:integer);
107 var
108   ZoomX,ZoomY,Zoom:double;
109 begin
110   zoomY:= Height / src.Height;
111   zoomX:= Width / src.Width;
112   // zoom 為 min(zoomX,zoomY)
113   if (ZoomX<ZoomY) then
114     zoom:= zoomX
115   else
116     zoom:=zoomY;
117   dest.Width:= trunc(src.width*zoom);
118   dest.Height:= trunc(src.Height*zoom);
119   dest.Canvas.StretchDraw(rect(0, 0, dest.Width, dest.Height), src);
120 end;
121 
122 // 顯示圖片,name指定了文本(固定居左、上下居中位置)
123 procedure TMainForm.ShowPhoto(paint:TPaintBox; src:TGraphic; const name:string);
124 begin
125   if not src.Empty then
126   begin
127     ZoomFill(bmpPaint,src,screen.Width,screen.Height);
128     if length(name)>0 then
129     begin
130       bmpPaint.Canvas.Brush.Style := bsClear;
131       bmpPaint.Canvas.TextOut(
132         10,
133         (bmpPaint.Height-bmpPaint.Canvas.textheight(name)) div 2,
134         name);
135     end;
136     paint.Repaint;
137   end;
138 end;
139 
140 //關閉 Form 時釋放資源
141 procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
142 var
143   i:integer;
144 begin
145   if MainTimer.Enabled then
146     MainTimer.Enabled:=false;
147 
148   bmpPaint.Free;
149   
150   Log.SaveToFile(WinnerFileName);
151   Log.Free;
152   jpg.Free;
153 
154   for i:=0 to photocount-1 do
155     Photos[i].Free;
156 end;
157 
158 //創建 Form 時初始化資源
159 procedure TMainForm.FormCreate(Sender: TObject);
160 var   
161   SearchRec:TSearchRec;
162   found:integer;
163   i:integer;
164 begin
165   // 開啟雙緩沖,減少屏幕閃爍
166   if not Self.doubleBuffered then
167     Self.doubleBuffered:=true;
168 
169   //初始化緩沖區
170   setlength(Names,BufferSize);
171   setlength(Photos,BufferSize);
172   setlength(Selected,BufferSize);
173 
174   Log:=TStringList.Create;
175   jpg:=TJpegImage.Create;
176   
177   bmpPaint:=tBitmap.create;
178   BmpPaint.pixelformat := pf24bit;
179   bmpPaint.Canvas.Font.Size:=textSize;
180   bmpPaint.Canvas.Font.Color:=textColor;
181   bmpPaint.Canvas.Font.Name:=TextFont;
182 
183   // 窗口全屏
184   Self.BorderStyle := bsNone;
185   Self.Left := 0;
186   Self.Top := 0;
187   Self.Width := Screen.Width;
188   Self.Height := Screen.Height;
189 
190   // 載入封面圖片
191   try
192     jpg.LoadFromFile(coverfilename);
193     jpg.DIBNeeded;
194   except
195   end;
196   ShowPhoto(MainPaint, jpg, '');
197 
198   // 載入 data 目錄下的所有JPG文件
199   found:=FindFirst('data\*.jpg',faAnyFile,SearchRec);
200   try
201     while found=0 do
202     begin
203       if (SearchRec.Name<>'.')  and (SearchRec.Name<>'..')
204            and (SearchRec.Attr<>faDirectory) then
205       begin
206         if (PhotoCount>=length(Names)) then  //內存緩沖長度不足
207         begin
208           setlength(Names,length(Names)*2);
209           setlength(Photos,length(Names));
210           setlength(Selected,length(Names));
211         end;
212         Names[PhotoCount]:= ChangeFileExt(SearchRec.Name,'');
213         Photos[PhotoCount]:=TMemoryStream.Create;
214         Photos[PhotoCount].LoadFromFile('data\'+ SearchRec.Name);
215         inc(PhotoCount);
216       end;
217       found:=FindNext(SearchRec);
218     end;
219   finally
220     FindClose(SearchRec);
221   end;
222 
223   //載入中獎紀錄
224   if fileexists(WinnerFileName) then
225     log.LoadFromFile(WinnerFileName);
226   if (log.Count>0) then //標記已中獎者
227   begin
228     for i:=0 to photoCount-1 do
229       if log.IndexOf(names[i])>=0 then
230       begin
231         Selected[i]:=1;
232         inc(selectedCount);
233       end;
234   end;
235 
236 end;
237 
238 //計時器事件
239 procedure TMainForm.MainTimerTimer(Sender: TObject);
240 var
241   s:TMemoryStream;
242 begin
243   repeat
244     Randomize;
245     PhotoIndex:=random(photocount);
246   until (Selected[photoIndex]<=0); //跳過已中獎的圖片
247   s:= Photos[PhotoIndex];
248   jpg.LoadFromStream(s);
249   s.Position:=0;  //這句必不可少。否則再讀時不會報錯,jpg.Empty不為空,但長度寬度均為0。
250   showPhoto(MainPaint,jpg,Names[PhotoIndex]);
251   inc(times);
252   //逐漸加快圖片滾動速度
253   if (times>16) then
254   begin
255     if MainTimer.Interval>125 then
256       MainTimer.Interval:=125;
257   end
258   else if times>8 then
259     maintimer.Interval:=250
260   else if times>3 then
261     Maintimer.Interval:=500
262   else
263     MainTimer.Interval:=800;
264 end;
265 
266 //按鍵處理
267 procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char);
268 begin
269   if (Key=#27) then //Esc
270   begin
271     MainTimer.Enabled:=false;
272     showmessage(Log.Text);
273     close;
274   end
275   else  if (Key=' ') or (Key=#13) then
276   begin
277     if MainTimer.Enabled then //要停止滾動
278     begin
279       MainTimer.Enabled:=false;
280       inc(SelectedCount);
281       Selected[PhotoIndex]:=1;  //設置中獎標記
282       Log.Append(Names[PhotoIndex]);
283       Log.SaveToFile(WinnerFileName);
284     end
285     else
286     begin //要開始滾動
287       if SelectedCount<PhotoCount then  //還有未中獎
288       begin
289         times:=0;
290         MainTimer.Enabled:=true;
291       end
292       else
293         showmessage('全部人員均已抽中!');  
294     end;
295   end;
296 end;
297 
298 //清除中獎紀錄
299 procedure TMainForm.MenuClearClick(Sender: TObject);
300 var
301   i:integer;
302 begin
303   if MessageDlg('真的要清除中獎記錄麼?',
304     mtConfirmation, [mbYes, mbNo], 0) = mrYes then
305   begin
306     Log.Clear;
307     SelectedCount:=0;
308     for i:=0 to PhotoCount-1 do
309       selected[i]:=0;
310     if fileexists(WinnerFileName) then
311       deletefile(WinnerFileName);
312   end;
313 end;
314 
315 //重繪 TPaintBox 事件
316 procedure TMainForm.MainPaintPaint(Sender: TObject);
317 begin
318   with MainPaint.Canvas do
319   begin
320     pen.mode := pmcopy;
321     brush.style := bssolid;
322     copymode := srccopy;
323     draw(
324       (MainPaint.Width-bmpPaint.Width) div 2,   //左右居中
325       (MainPaint.Height-bmpPaint.Height) div 2, //上下居中
326       bmpPaint);
327   end;
328 end;
329 
330 procedure TMainForm.ExitMenuClick(Sender: TObject);
331 begin
332   close;
333 end;
334 
335 end.

可執行程序下載

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved