有单位年会要用照片抽奖,上网搜了几个都不满意,且居然还要收费。自己写一个算了。只是有一点不爽,Delphi 7 在 Windows 7 64位下有问题,不能双击 dpr 文件直接打开项目!

关于性能:

  • 因为总数不大(没超过100个),所以一次性全部载入内存保存,启动速度也不慢,秒开。以流的形式保存,因为可直接使用 TJPEGImage 的 LoadFromStream 方法。如果照片很多,那就要掂量掂量内存占用情况了。实时读取文件的话,同时还要考虑磁盘读写的延时。
  • 图片分辨率对 JPG 的解压、显示的速度影响较大(i3 CPU、B75主板、8G内存):
    4288*2848——耗时 260ms
    1440*956——耗时 109ms
    1156*768——耗时 63ms
    因此,必须限制原始图片的分辨率,宁可放大显示。如果对显示性能要求较高,比如图片切换间隔要求小于100ms(不过短于视觉暂留时间的话就看不见了),必须别想他法。

废话不说,上代码。

 unit main;

 interface

 uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls, Menus, Jpeg; type
TMainForm = class(TForm)
MainTimer: TTimer;
PopMenu: TPopupMenu;
MenuClear: TMenuItem;
MainPaint: TPaintBox;
ExitMenu: TMenuItem;
procedure MainTimerTimer(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure MenuClearClick(Sender: TObject);
procedure MainPaintPaint(Sender: TObject);
procedure ExitMenuClick(Sender: TObject);
private
{ Private declarations }
procedure ShowPhoto(paint:TPaintBox; src:TGraphic; const name:string);
public
{ Public declarations }
end; const
BufferSize=; //缺省照片缓存大小
CoverFileName='COVER.JPG'; //封面图片
WinnerFileName='中奖.txt'; //抽奖结果文件 TextColor=clRed; //显示文字颜色
TextSize=; //显示文字大小
TextFont='华文行楷';//显示文字字体 var
MainForm: TMainForm;
PhotoIndex:integer=; //当前显示的图片索引
PhotoCount:integer=; //图片总数
Names : array of string; //图片名称缓存
Photos : array of TMemoryStream; //JPG文件流缓存
Selected : array of integer; //已中奖图片标志
SelectedCount : integer=; //已中奖数量,如果全部中奖则停止抽奖
Log : TStringList; //中奖记录,存入文本文件 jpg:TJpegImage; //解压JPG用的公用变量
Times:Cardinal; //定时器事件的执行次数 bmpPaint:TBitmap; //作为PaintBox的显示缓存 implementation {$R *.dfm} {
procedure Mosaic(dest:TBitmap; src:TBitmap);
var
i,x,y:Integer;
from:TRect;
bmpwidth,bmpheight:Integer;
const
squ=20;
begin
bmpwidth:=src.Width;
bmpheight:=src.Height; dest.Width:=bmpwidth;
dest.Height:=bmpHeight; for i:=0 to 400 do
begin
Randomize;
x:=Random(bmpwidth div squ);
y:=Random(bmpheight div squ);
from:=Rect(x*squ,y*squ,(x+1)*squ,(y+1)*squ);
dest.Canvas.CopyRect(from,Src.Canvas,from);
end;
end; procedure Alpha(bitmap:TBitmap; jpg:TJPEGImage);
var
BlendFunc: TBlendFunction;
bit:TBitmap;
begin
bit := TBitMap.Create;
try
jpg.DIBNeeded;
bit.Assign(jpg);
BlendFunc.BlendOp := AC_SRC_OVER;
BlendFunc.BlendFlags := 0;
BlendFunc.AlphaFormat := 0;
BlendFunc.SourceConstantAlpha := 127;
windows.AlphaBlend(bitmap.Canvas.Handle, 0, 0, bit.Width, bit.Height,
bit.Canvas.Handle, 0, 0, bit.Width, bit.Height,
BlendFunc);
finally
bit.Free;
end;
end;
} //源图等比缩放后填充目标图片,width、height指定可用显示区域的大小
procedure ZoomFill(dest:TBitMap; src:TGraphic; width,Height:integer);
var
ZoomX,ZoomY,Zoom:double;
begin
zoomY:= Height / src.Height;
zoomX:= Width / src.Width;
// zoom 为 min(zoomX,zoomY)
if (ZoomX<ZoomY) then
zoom:= zoomX
else
zoom:=zoomY;
dest.Width:= trunc(src.width*zoom);
dest.Height:= trunc(src.Height*zoom);
dest.Canvas.StretchDraw(rect(, , dest.Width, dest.Height), src);
end; // 显示图片,name指定了文本(固定居左、上下居中位置)
procedure TMainForm.ShowPhoto(paint:TPaintBox; src:TGraphic; const name:string);
begin
if not src.Empty then
begin
ZoomFill(bmpPaint,src,screen.Width,screen.Height);
if length(name)> then
begin
bmpPaint.Canvas.Brush.Style := bsClear;
bmpPaint.Canvas.TextOut(
,
(bmpPaint.Height-bmpPaint.Canvas.textheight(name)) div ,
name);
end;
paint.Repaint;
end;
end; //关闭 Form 时释放资源
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
var
i:integer;
begin
if MainTimer.Enabled then
MainTimer.Enabled:=false; bmpPaint.Free; Log.SaveToFile(WinnerFileName);
Log.Free;
jpg.Free; for i:= to photocount- do
Photos[i].Free;
end; //创建 Form 时初始化资源
procedure TMainForm.FormCreate(Sender: TObject);
var
SearchRec:TSearchRec;
found:integer;
i:integer;
begin
// 开启双缓冲,减少屏幕闪烁
if not Self.doubleBuffered then
Self.doubleBuffered:=true; //初始化缓冲区
setlength(Names,BufferSize);
setlength(Photos,BufferSize);
setlength(Selected,BufferSize); Log:=TStringList.Create;
jpg:=TJpegImage.Create; bmpPaint:=tBitmap.create;
BmpPaint.pixelformat := pf24bit;
bmpPaint.Canvas.Font.Size:=textSize;
bmpPaint.Canvas.Font.Color:=textColor;
bmpPaint.Canvas.Font.Name:=TextFont; // 窗口全屏
Self.BorderStyle := bsNone;
Self.Left := ;
Self.Top := ;
Self.Width := Screen.Width;
Self.Height := Screen.Height; // 载入封面图片
try
jpg.LoadFromFile(coverfilename);
jpg.DIBNeeded;
except
end;
ShowPhoto(MainPaint, jpg, ''); // 载入 data 目录下的所有JPG文件
found:=FindFirst('data\*.jpg',faAnyFile,SearchRec);
try
while found= do
begin
if (SearchRec.Name<>'.') and (SearchRec.Name<>'..')
and (SearchRec.Attr<>faDirectory) then
begin
if (PhotoCount>=length(Names)) then //内存缓冲长度不足
begin
setlength(Names,length(Names)*);
setlength(Photos,length(Names));
setlength(Selected,length(Names));
end;
Names[PhotoCount]:= ChangeFileExt(SearchRec.Name,'');
Photos[PhotoCount]:=TMemoryStream.Create;
Photos[PhotoCount].LoadFromFile('data\'+ SearchRec.Name);
inc(PhotoCount);
end;
found:=FindNext(SearchRec);
end;
finally
FindClose(SearchRec);
end; //载入中奖纪录
if fileexists(WinnerFileName) then
log.LoadFromFile(WinnerFileName);
if (log.Count>) then //标记已中奖者
begin
for i:= to photoCount- do
if log.IndexOf(names[i])>= then
begin
Selected[i]:=;
inc(selectedCount);
end;
end; end; //计时器事件
procedure TMainForm.MainTimerTimer(Sender: TObject);
var
s:TMemoryStream;
begin
repeat
Randomize;
PhotoIndex:=random(photocount);
until (Selected[photoIndex]<=); //跳过已中奖的图片
s:= Photos[PhotoIndex];
jpg.LoadFromStream(s);
s.Position:=; //这句必不可少。否则再读时不会报错,jpg.Empty不为空,但长度宽度均为0。
showPhoto(MainPaint,jpg,Names[PhotoIndex]);
inc(times);
//逐渐加快图片滚动速度
if (times>) then
begin
if MainTimer.Interval> then
MainTimer.Interval:=;
end
else if times> then
maintimer.Interval:=
else if times> then
Maintimer.Interval:=
else
MainTimer.Interval:=;
end; //按键处理
procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char);
begin
if (Key=#) then //Esc
begin
MainTimer.Enabled:=false;
showmessage(Log.Text);
close;
end
else if (Key=' ') or (Key=#) then
begin
if MainTimer.Enabled then //要停止滚动
begin
MainTimer.Enabled:=false;
inc(SelectedCount);
Selected[PhotoIndex]:=; //设置中奖标记
Log.Append(Names[PhotoIndex]);
Log.SaveToFile(WinnerFileName);
end
else
begin //要开始滚动
if SelectedCount<PhotoCount then //还有未中奖
begin
times:=;
MainTimer.Enabled:=true;
end
else
showmessage('全部人员均已抽中!');
end;
end;
end; //清除中奖纪录
procedure TMainForm.MenuClearClick(Sender: TObject);
var
i:integer;
begin
if MessageDlg('真的要清除中奖记录么?',
mtConfirmation, [mbYes, mbNo], ) = mrYes then
begin
Log.Clear;
SelectedCount:=;
for i:= to PhotoCount- do
selected[i]:=;
if fileexists(WinnerFileName) then
deletefile(WinnerFileName);
end;
end; //重绘 TPaintBox 事件
procedure TMainForm.MainPaintPaint(Sender: TObject);
begin
with MainPaint.Canvas do
begin
pen.mode := pmcopy;
brush.style := bssolid;
copymode := srccopy;
draw(
(MainPaint.Width-bmpPaint.Width) div , //左右居中
(MainPaint.Height-bmpPaint.Height) div , //上下居中
bmpPaint);
end;
end; procedure TMainForm.ExitMenuClick(Sender: TObject);
begin
close;
end; end.

可执行程序下载

Delphi 实现照片抽奖-原创的更多相关文章

  1. 《zw版·delphi与Halcon系列原创教程》THOperatorSetX版hello,zw

    <zw版·delphi与Halcon系列原创教程>THOperatorSetX版hello,zw 下面介绍v3版的hello,zw. Halcon两大核心控件,THImagex.THOpe ...

  2. 《zw版·delphi与halcon系列原创教程》zw版_THOperatorSetX控件函数列表 v11中文增强版

    <zw版·delphi与halcon系列原创教程>zw版_THOperatorSetX控件函数列表v11中文增强版 Halcon虽然庞大,光HALCONXLib_TLB.pas文件,源码就 ...

  3. 《zw版·delphi与halcon系列原创教程》zw版_THImagex控件函数列表

    <zw版·delphi与halcon系列原创教程>zw版_THImagex控件函数列表 Halcon虽然庞大,光HALCONXLib_TLB.pas文件,源码就要7w多行,但核心控件就是两 ...

  4. 《zw版·delphi与halcon系列原创教程》hello,zw

    <zw版·delphi与halcon系列原创教程>hello,zw 按惯例,第一个程序是‘hello’ 毕竟,Halcon是专业的图像库,所以我们就不用纯文本版的,来一个专业版.Halco ...

  5. JS原生实现照片抽奖

    HTML表格标记实现九宫格,放入九张图片.利用CSS的滤镜属性控制图片的透明度.Javascript实现抽奖和中奖. 可以做为教师上课,随机抽取回答问题的同学,使学生感受到随机的公平性,简单有趣! 点 ...

  6. Delphi中的RectTracker - 原创

    本文算是副产品,正品是利用FFmpeg从任意视频中生成GIF片段的小程序,写完了就发. 因为要对视频画面进行框选,再生成GIF,所以得有个框选的控件,可Delphi里没有啊,只好自己写一个了. 声明 ...

  7. Delphi 中的 RectTracker - 原创

    本文算是副产品,正品是利用 FFmpeg 从任意视频中生成GIF片段的小程序,写完了就发. V2G 正品已出炉,虽然不大像样,但好歹是能用,请见:用 Delphi 7 实现基于 FFMS2 的视频转 ...

  8. 【《zw版·Halcon与delphi系列原创教程》Halcon图层与常用绘图函数

    [<zw版·Halcon与delphi系列原创教程>Halcon图层与常用绘图函数 Halcon的绘图函数,与传统编程vb.c.delphi语言完全不同,     传统编程语言,甚至cad ...

  9. 《zw版·ddelphi与halcon系列原创教程》Halcon的短板与delphi

    [<zw版·delphi与Halcon系列原创教程>Halcon的短板与delphi 看过<delphi与Halcon系列>blog的网友都知道,笔者对Halcon一直是非常推 ...

随机推荐

  1. docker搭建本地私仓

    环境centos7  docker-ce 18 启动仓库镜像 docker run -d -p 5000:5000 registry:2 docker images 通过docker tag 标识镜像 ...

  2. nodejs( koa2 )配置 browserHistory

    前言 既然能搜到并且还点进来看这篇文章, 那么肯定是知道后台为什么要配置 browserHistory, 也肯定知道为什么非要去用相对来说更麻烦的吧browserHistory, 而不用更简单点的不需 ...

  3. Solr 同义词搜索

    1.  进入solr配置目录 cd /usr/local/solr/solrhome/collection1/conf vi schema.xml 增加配置节 <fieldType name=& ...

  4. 关于使用iframe,父元素无法获得子iframe对的元素

    首先确定自己写的方法对不对: $(document.getElementById('iframe的ID').contentWindow.document.body).find("要获得的元素 ...

  5. 用户从地址栏输入url,按下enter键后,直到页面加载完成的这个过程都发生了什么?

    流程大概描述一下: 用户将url输入后,服务器接受到请求,然后将这个请求进行处理,然后将处理后的结果返回给浏览器,浏览器将该结果以页面的形式呈现给用户. 详细描述: 1:用户将url(例如www.ba ...

  6. STM32F4 SPI双机通讯调试总结

    1.如果查询方式进行数据收发,不管是Master,还是Slave,流程如下:(假设收发n+1个字节) a.等待TXE,写入一个字节 b.等待TXE,写入一个字节 c.等待RXNE,读取一个字节 循环b ...

  7. hadoop分布式安装及其集群配置笔记

    各机器及角色信息: 共10台机器,hostname与ip地址映射在此不做赘述.此为模拟开发环境安装,所以不考虑将NameNode和SecondaryNameNode安装在同一台机器. 节点 角色 na ...

  8. C++的一些关键字用法

    const 这个关键字真是太常用了, 所以干脆总结一下. int const a = 8; //定义一个int常量a, 不能再给a赋值了 const int a = 8; //和上面一样 int co ...

  9. Python学习:16.Python面对对象(三、反射,构造方法,静态字段,静态方法)

    一.构造方法 在使用类创建对象的时候(就是类后面加括号)就自动执行__init__方法. class A: def __init__(self): print('A') class B: def __ ...

  10. PHP-学习笔记-进阶

    PHP-学习笔记-进阶 PHP类和对象之定义类的方法 访问控制的关键字代表的意义为: public:公开的 protected:受保护的 private:私有的 我们可以这样定义方法: class C ...