千家论坛_智能建筑与智能家居技术交流社区

标题: 编程技巧收录大全---- Delphi 技巧 [打印本页]

作者: 0758河台小赵    时间: 2004-9-5 13:20
标题: 编程技巧收录大全---- Delphi 技巧

Delphi 技巧

不规则窗口的建立(字体窗体)

不规则窗口的讨论,请将以下代码添加到FormCreate事件中 运行即可完成字体窗体的创建。

procedure TForm1.FormCreate(Sender: TObject); var rgn:HRGN; begin Form1.Color:=clRed; BeginPath(Canvas.Handle); SetBKMode(Canvas.Handle,TRANSPARENT); Canvas.Font.Name:='宋体'; Canvas.Font.Size:=200; Canvas.TextOut(150,130,'黄昏狼'); EndPath(Canvas.Handle); rgn:=PathToRegion(Canvas.Handle); SetWindowRgn(Handle,rgn,true); end;


作者: 0758河台小赵    时间: 2004-9-5 13:25
在Delphi中自动检测、建立数据库别名和表格

procedure TForm1.CreateDBandTable; var

strAlias:TStringList; iAnswer:Integer;

begin

strAlias:=TStringList.Create; Session.GetAliasNames(strAlias); if (strAlias.IndexOf('myDB') = -1) then begin

iAnswer:=Application.MessageBox('数据库不存在,现在创建吗?','信息窗口',MB_OKCANCEL); if iAnswer = IDCANCEL then begin

strAlias.Free; Exit;

end; Session.AddStandardAlias('myDB' , Path , 'Paradox'); Session.SaveConfigFile;

end; strAlias.Clear; Session.GetTableNames('myDB','',False,False,strAlias); if ( strAlias.IndexOf( tbName) = -1 ) then begin

iAnswer:=Application.MessageBox('参数表格不存在,现在创建一个?','信息窗口',MB_OKCANCEL); if iAnswer = IDCANCEL then begin

strAlias.Free; Exit;

end; Table1.Active:=False; Table1.DatabaseName:='myDB'; Table1.TableName:=tbName; Table1.TableType:=ttParadox; Table1.FieldDefs.Clear; Table1.FieldDefs.Add('Name',ftString,6,False); Table1.FieldDefs.Add('Sex',ftString,4,False); Table1.IndexDefs.Clear; Table1.IndexDefs.Add('Index','Name',[ixPrimary,ixUnique] ); Table1.CreateTable;

end;

end;


作者: 0758河台小赵    时间: 2004-9-5 13:28

用DEPHI 3.0实现动画ABOUT窗口

一般系统的ABOUT窗口中都含有当前系统的信息(如:CPU类型,硬盘容量,内存容量等),一个标志系统的图标,一个OK按钮等内容。笔者在工作中用DEPHI 3.0实现了动画效果的ABOUT窗口。

一. 创建含有如下控件的窗体:控件属性 值 FORM1 CAPTION 动画ABOUT窗口 ANIMATE1 COMMONAVI aviFindFolder ACTIVEtrueBUTTON1 CAPTION OKLABEL1 CAPTION 通用进销存管理系统V3.0LABEL2 CAPTION 版权所有:1997-1999年LABEL3 CAPTION 物理内存总容量:LABEL4 CAPTION 虚拟内存总容量:LABEL5 CAPTION 可用虚拟内存容量:LABEL6 CAPTION 硬盘容量:LABEL7 CAPTION 硬盘可用容量:LABEL8 CAPTION CPU类型:LABEL9 CAPTION 显示器分辨率:LABEL18 CAPTION 用物理内存:LABEL11,LABEL12,LABEL13,LABEL14,LABEL15,LABEL16,LABEL17LABEL19 CAPTION 空二.程序:unit sysinfo;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls;type TForm1 = class(TForm) Button1: TButton; Animate1: TAnimate; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; Label9: TLabel; Label10: TLabel; Label11: TLabel; Label12: TLabel; Label13: TLabel; Label14: TLabel; Label15: TLabel; Label16: TLabel; Label17: TLabel; Label18: TLabel; Label19: TLabel; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end;var Form1: TForm1;implementation{$R *.DFM}procedure TForm1.Button1Click(Sender: TObject);begin close;end;procedure TForm1.FormCreate(Sender: TObject);var x,y:integer; sysinfTsysteminfo; meminfTmemorystatus; c2,c3,c4,c5:integer;begingetsysteminfo(sysinfo);label16.caption:=inttostr(sysinfo.dwProcessorType);x:=getsystemmetrics(0);y:=getsystemmetrics(1);label17.caption:=inttostr(x)+'*'+inttostr(y);globalmemorystatus(meminfo);label11.caption:=inttostr(meminfo.dwTotalPhys)+'字节';label19.caption:=inttostr(meminfo.dwAvailPhys)+'字节';label12.caption:=inttostr(meminfo.dwTotalVirtual)+'字节';label13.caption:=inttostr(meminfo.dwAvailVirTual)+'字节';getdiskfreespace('c:\',c2,c3,c4,c5);label14.caption:=inttostr(c5*c2*c3)+'字节';label15.caption:=inttostr(c4*c2*c3)+'字节';end;end.

 

---- 以上程序在中文WINDOWS98,WINDOWS95,DEPHI 3.0软件环境下运行通过。


作者: 0758河台小赵    时间: 2004-9-5 13:35
在DELPHI中处理时间

---- 笔者在编写一个解除共享软件使用时间限制的小软件时,采用的原理是首先保存现在的时间,然后将系统时间设定为共享软件可运行的时间,再启动共享软件,最后在共享软件退出时再将系统时间恢复为原来保存的时间。但在调试程序的过程中发现了这样一个问题,由于在共享软件运行其间,时间已流逝,所以恢复原来保存的时间后就会导致系统时间滞后,滞后的时间为共享软件的运行时间。

---- 如何来解决这个问题呢?经过摸索,采用在共享软件启动的同时启动一个定时器,用一个变量保存流逝的时间,在共享软件结束时定时器停止工作,然后将流逝的时间加到原来保存的时间上作为系统时间恢复,这样就彻底解决了软件运行导致系统时钟变慢的问题。为了能在方便其他程序使用,编写了一个用于处理事件的类,在此介绍如下,以便于大家在编写与时间有关的程序时参考,从中可了解如何保存现在时间、设定新时间、记录流逝时间、恢复系统时间的方法。

---- 代码如下:

unit SystemTime;interfaceusesWindows, Messages, SysUtils, Classes,Graphics,Controls, Forms, Dialogs, StdCtrls,ExtCtrls;type TSysTime = class(TObject)private//系统日期、时间FStartDateTime : TDateTime;// 定时器FTimer : TTimer;// 流逝时间变量FElapsedTime : Integer;procedure Timer(Sender: TObject);protectedpublic constructor Create; virtual; destructor Destroy; override;procedure SetNewTime(NewTime :TSystemTime);procedure ResetTime;end;implementation//构造器constructor TSysTime.Create;begin//保存当前日期、时间FStartDateTime := Now;//生成定时器对象FTimer := TTimer.Create(nil);// 设定时钟间隔为一秒FTimer.Interval := 1000;//时钟事件FTimer.OnTimer := Timer;// 开始记时FTimer.Enabled := True;end;//设定系统新时间procedure TSysTime.SetNewTime(NewTime :TSystemTime);beginSetLocalTime(NewTime);end;//流逝时间procedure TSysTime.Timer(Sender: TObject);begin// 保存流逝的时间(以秒为单位),每秒加1Inc(FElapsedTime);end;//恢复系统时钟procedure TSysTime.ResetTime;varNewTime : TSystemTime;tmTemp : Double;dtTemp : TDateTime;begin//将流逝的时间转换为天数tmTemp := FElapsedTime/86400;//将流逝的时间加到原来的时间上dtTemp := FStartDateTime + tmTemp;//转换为Windows 32位时间格式DateTimeToSystemTime(dtTemp, NewTime);//设定时间SetLocalTime(NewTime);end;//释放destructor TSysTime.Destroy;begin//恢复系统时钟ResetTime;// 记时器停止FTimer.Enabled := False;// 释放时钟对象FTimer.Free;end;end.
作者: 0758河台小赵    时间: 2004-9-5 13:37
如何为Delphi程序添加事件和事件处理器

---- Delphi是一种功能很强的可视化程序开发工具。我们在使用Delphi开发WINDOWS 应用程序的过程中,虽然Delphi为每个可视化组件都提供了很多属性(Property)和事件(Event),但在实际应用中可能会碰到一些自己需要的特殊事件,这些特殊事件Delphi 又没有提供,这时我们就需要为应用程序添加这些特殊事件。当这些事件发生后,又能马上调用处理这些事件的过程。本文通过实例来说明如何为应用程序添加事件和处理事件的过程。

---- 在Delphi中,事件实际上是专门化的属性,它是一个过程(procedure)的指针。要添加事件,首先应在所定义的类中说明一个用来指向事件过程的指针,该指针的作用是当事件一旦发生,就通过这个指针执行所指向的处理这个事件的过程。最后通过指定符 published公布定义的事件属性以及与之关联的事件处理过程指针。

---- 本例中,FtooBig为定义的事件处理过程指针,OnTooBig为事件属性名。事件处理过程指针FtooBig通过程序的初始化使之指向过程TooBig1。在Delphi的表单(Form1)上放置三个编辑框,分别为Edit1、Edit2和Edit3,放一按钮Button1。程序中设私有整型变量val1、val2和res,变量res用来记录val1和val2的乘积,并用Edit3显示出来。当通过Edit1和Edit2输入的数据有一个大于100时,会触发一个事件,并调用事件处理过程TooBig1显示一个对话框,说明此事件已经发生并已进行处理。源程序代码如下, 该程序在Delphi 3中调试通过。

unit Unit1;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;type TForm1 = class(TForm) Edit1: TEdit; {输入第一个整数} Edit2: TEdit; {输入第二个整数} Edit3: TEdit; {输出前二个整数的积} Button1: TButton; procedure Button1Click(Sender: TObject);procedure TooBig1(Sender: TObject); {当事件触发后调用此过程} procedure FormCreate(Sender: TObject); privateval1,val2,res:integer; {val1和val2存放输入的两个整数,res存放两数的积}FTooBig : TNotifyEvent; {定义一个指向事件处理器的指针FTooBig} { Private declarations } public { Public declarations } publishedproperty OnTooBig:TNotifyevent read FTooBig write FTooBig;{定义事件} end;var Form1: TForm1;implementation{$R *.DFM}procedure TForm1.Button1Click(Sender: TObject);begin val1 := StrToInt(Edit1.Text); val2 := StrToInt(Edit2.Text); if(val1< 100)and(val2< 100) then begin res := val1*val2; Edit3.Text := IntToStr(res); end else if assigned(FTooBig) then OnTooBig(Self);end;procedure TForm1.TooBig1(Sender: TObject);beginApplication.MessageBox('Too Big',' Test Event! ',MB_OK);end;procedure TForm1.FormCreate(Sender: TObject);begin val1:=1; val2:=1; FTooBig := TooBig1;{使事件处理指针指向事件处理器}end;end.
作者: 0758河台小赵    时间: 2004-9-5 13:39
在DELPHI程序中使用ADO对象存取ODBC数据库

---- 作为一个ASP爱好者,笔者经常在ASP页面中使用ADO对象操作ODBC数据库,觉得用ASP创建WEB应用系统确定挺方便的.虽然在编程生涯中,笔者更喜欢Borland系列产品,对微软产品有点排斥,对ASP却是例外.某天,灵机一动,ADO对象是一个标准OLE对象,如果在DELPHI应用程序中能利用ADO操作数据库,应该挺不错.尤其在用DELPHI做网络数据库应用程序时,如果所在的WEB站点是WINNT站点并且支持ASP页面,就可以用ADO对象访问ODBC数据库,而不用把那么大的BDE再上载到站点上去,这样就可充分利用DELPHI和ASP的编程优势,做出更好的ISAPI/NSAPI/CGI.

---- 经过编程和测试,在DELPHI中可以成功地用ADO对象存取ODBC数据库,现将使用经验写出来,与大家共享,让我们多一个访问ODBC数据库的方法.

----   在32位的DELPHI中,可以声明一个variant变量(如AVariant),然后通过CreateOleObject 创建一个OLE对象,如AVariant:=CreateOleObject('ADODB.Connection')可以获得一个数据库连接对象的实例,然后就可以利用该对象的方法和属性来操作ODBC数据库了.

----   下面简单介绍一下访问ODBC数据库所用到的ADO对象及其方法和属性.

----   1.数据库连接对象(ADODB.Connection)

---- 该对象用于与ODBC数据库建立连接,所有对数据库的操作均通过该连接进行.

---- 数据库连接对象ADODB.Connection的作用象Delphi中的TDatabase对象.

---- 建立一个连接对象的方法为(AConnection为Variant类型变量):

---- AConnection:=CreateOleObject('ADODB.Connection')

---- 用于建立连接的方法为Open,使用语法为(以对象AConnection为例):

---- AConnection.Open( ConnectionString, UserId, Password )

---- 三个参数均为字符串类型,其中UserId和Password为用户名称和用户密码,用来访问

---- 数据库时使用,可以省略,因为在ConnectionString同样可以指定用户名称和用户 密码.ConnectionString是用来说明ODBC数据源信息的字符串,其格式为:

'Provider=ProviderName;DSN=DSNName;DRIVER=driver; SERVER=server; DATABASE=database; UID=user; PWD=password'

 

---- 其中:

---- Provider:数据提供者,默认为MSDASQL,为微软OLEDB,通常省略

---- DSN   :要打开的数据库对应的OBDC系统数据源(DSN),是可选参数

---- DRIVER :要打开的数据库所用的驱动程序名称,如Access对应

---- Microsoft Access Driver(*.mdb),是可选参数

---- SERVER :要打开的数据库所在的服务器名称,本机可用(local),是可选参数

---- DATABASE:要打开的数据库名称,是可选参数

---- UID   :用户名称,用来访问数据库,是可选参数

---- PWD   :用户密码,用来访问数据库,是可选参数

---- 以上参数均为可选参数,但必须提供足够的信息来描述一个系统数据源.

---- 假如已经定义了一个ODBC的系统DSN,名称为MyDsn,那么就可用以下语句建立一个数据库连接:

----

AConnection.Open('DSN=MyDsn');

 

---- 为了防止DSN不存在或其设置被他人修改时造成应用程序运行错误,可以用ADODB.Connection创建一个临时ODBC数据源,这样可以保证我们使用的系统DSN的参数设置是正确的.下面的语句可以创建一个临时ODBC系统DSN,对应一个ACCESS数据库,路径为

C:\Inetpub\wwwroot\test.mdb AConnection.open('Driver={Microsoft Access Driver (*.mdb)};DBQ=C:\inetpub\wwwroot\test.mdb')

 

---- 建立一个ADODB.Connection后,如果不需要返回操作结果(如删除,修改,更新等操作)就可以对数据库进行正常的SQL操作了,此时应用ADODB.Connection的另外一个方法Execute,使用语法为:

AConnection.Execute( strSQL );

 

---- 其中strSQL为执行操作的SQL语句,如删除操作可以为:delete from wfjcommu 用AConnection.Close关闭一个数据库连接.

----   2.数据集对象(ADODB.RecordSet)

---- 如果要执行查询操作并返回查询结果,或者要更方便地操作数据表,就需要用到数据集对象了.

---- 数据集对象ADODB.RecordSet的作用象Delphi中的TTable或TQuery对象.

---- 建立一个数据集对象的方法为(ARecordSet为Variant类型变量):

----

ARecordSet:=CreateOleObject('ADODB.RecordSet')

 

---- 从数据表取得数据的方法为Open方法,具体使用方法为:

ARecordSet.Open( strCommand,ActiveConnection,intCursorType,intLockType,intCommandType );

---- 其中: strCommand:字符串,为命令参数,可以是一个Table名称,可以是一个SQL语句,也可以是一个服务器上的存储过程(StoredProc)名称,具体需要后面的参数intCommandType来指定.

---- ActiveConnection:要使用的数据库连接,是一个ADODB.Connection对象.

---- intCursorType:长整数,数据集的Cursor类型,可选参数,请参见程序中注释。

---- intLockType:长整数,对数据表的加锁类型,可选参数,请参见程序中注释。

---- intCommandType:长整数,命令参数的类型,用来指明strCommand的作用,可以指定strCommand为命令(如SQL语句)或数据表(TTable)或储存过程(StoredProc),可选参数,请参见程序中注释。

---- 如执行一个SQL查询,可以采用如下语句:

ARecordSet.Open('Select * from wfjcommu',adOpenStatic,adLockOptimistic,adCmdText);

 

---- 其它常见属性和方法与TTable和TQuery相比较如下(具体请见ASP帮助文件):

eof,bof:eof,bof. MoveFirst, MoveLast:First, Last MovePrevious, MoveNext:Prior, Next Move:MoveBy AddNew:append Update:Post Close:close

---- Delete加Update:delete,所有对数据表的修改均须用Update使操作有效,这与Delphi不同

Fields[FieldNo]:Fields[FieldNo]Fields['FieldName']:FieldByName('FieldName')

 

----   3.其它常见对象(与Delphi对应的对象):

----

ADODB.Field:TField ADODB.Parameter:TPara ADODB.Error:EDBEngineError ADODB.Command:无 ADODB.Property:无

 

----   下面来看一个应用例子,听别人说总不如自己看实际的例子来体会。在这个例子中,将演示如何利用ADO对象来对一个数据表进行查询、增加记录、修改记录和删除记录操作。具体的用法请参见程序中的注释,如果有点Delphi数据库编程经验,相信不难理解。

----   在我们的例子使用的数据库为Test.MDB,其中有一个数据表为wfjcommu,有五个字段AName、Portable、Tel、BP、PostAddress,分别表示姓名、手机号、电话号码、呼机号码和通信地址。

----

procedure TForm1.Button1Click(Sender: TObject);{*****************************************************

 

---- 用ADO操作ODBC数据库本程序中,将创建一个临时的ODBC系统数据源,指向一个MsAccess数据库,然后对其中的数据表进行显示、增加、修改、删除和查询操作注意:请在Uses语句中包含ComObj单元

*****************************************************}const{ 一些常量声明,详细请参见adovbs.inc }{ ---- CommandType的常量说明 ---- } adCmdUnknown = 0008;//未知,需要系统来判断,速度慢,为缺省值 adCmdText = 0001;//命令语句如SQL语句 adCmdTable = 0002;//数据表名称 adCmdStoredProc = 0004;//存储过程名称{ ---- CursorType的常量说明 ---- } adOpenForwardOnly = 0;//只能由前向后单向访问,为缺省值 adOpenKeyset = 1;//可见其他用户对数据的修改,但对其它用户的增加和删除不可见 adOpenDynamic = 2;//其他用户对数据的增加修改和删除均可见 adOpenStatic = 3;//其他用户对数据的增加修改和删除均不可见{---- LockType的常量说明 ---} adLockReadOnly = 1;//只读,为缺省值 adLockPessimistic = 2;//在修改时,按单个记录锁定 adLockOptimistic = 3;//在修改后更新时,按单个记录锁定 adLockBatchOptimistic = 4;//在成批更新时记录锁定var AConnection, ARecordSet : variant; longintTemp : integer; strTemp : string; intIndex : integer;begin {创建一个临时的ODBC数据源, 指向一个MsAccess数据库, 并利用此DSN建立一个数据库连接} AConnection := CreateOleObject('ADODB.Connection'); AConnection.Open('Driver={Microsoft Access Driver (*.mdb)};DBQ=C:\inetpub\wwwroot\test'); {建立一个数据集对象,并从数据表中提取数据} ARecordSet := CreateOleObject('ADODB.RecordSet'); ARecordSet.open( 'wfjcommu',AConnection, adOpenStatic,adLockOptimistic,adCmdTable ); memo1.lines.clear; memo1.lines.add('********数据表原有的内容如下********'); {显示各个域的域名} strTemp := ''; for intIndex := 0 to ARecordSet.Fields.count - 1 do strTemp := strTemp + ARecordSet.Fields[intIndex].name+';'; memo1.lines.add( strTemp ); {显示各个域的内容} while not ARecordSet.eof do begin strTemp := ''; for intIndex := 0 to ARecordSet.Fields.count - 1 do strTemp := strTemp + ARecordSet.Fields [intIndex].value+';'; memo1.lines.add( strTemp ); ARecordSet.MoveNext;//移到下条,Next end; {增加一个记录} ARecordSet.AddNew;//增加,Append ARecordSet.Fields['AName'] := '1'; //以FieldByName的方式存取 ARecordSet.Fields['Portable'] := '2'; ARecordSet.Fields(2) := '3'; //以Fields[index]的方式存取 ARecordSet.Fields(3) := '4'; ARecordSet.Fields(4) := '5'; ARecordSet.Update;//更新,Post ARecordSet.MoveFirst;//移到首条,First memo1.lines.add('********增加了一条 记录后的数据表的内容如下********'); {显示各个域的内容} while not ARecordSet.eof do begin strTemp := '';for intIndex := 0 to ARecordSet. Fields.count - 1 do strTemp := strTemp + ARecordSet.Fields[intIndex].value+';'; memo1.lines.add( strTemp ); ARecordSet.MoveNext;//移到下条,Next end; {修改最后一条记录} ARecordSet.MoveLast; ARecordSet.Fields['AName'] := '11'; //以FieldByName的方式存取 ARecordSet.Fields['Portable'] := '22'; ARecordSet.Fields(2) := '33'; //以Fields[index]的方式存取 ARecordSet.Fields(3) := '44'; ARecordSet.Fields(4) := '55'; ARecordSet.Update;//更新,Post ARecordSet.MoveFirst;//移到首条,First memo1.lines.add('********修改了最后一条 记录后的数据表的内容如下********'); {显示各个域的内容} while not ARecordSet.eof do begin strTemp := '';for intIndex := 0 to ARecordSet.Fields.count - 1 do strTemp := strTemp + ARecordSet.Fields[intIndex].value+';'; memo1.lines.add( strTemp ); ARecordSet.MoveNext;//移到下条,Next end; {删除最后一条记录} ARecordSet.MoveLast;//移到末条,Last ARecordSet.delete;//删除,delete ARecordSet.Update;//更新,在Delphi不需要 ARecordSet.MoveFirst;//移到首条,First memo1.lines.add('********删除了最后一条 记录后的数据表的内容如下********'); {显示各个域的内容} while not ARecordSet.eof do begin strTemp := ''; for intIndex := 0 to ARecordSet.Fields.count - 1 do strTemp := strTemp + ARecordSet. Fields[intIndex].value+';'; memo1.lines.add( strTemp ); ARecordSet.MoveNext;//移到下条,Next end; ARecordSet.Close;{关闭数据集} {用SQL语句进行查询,查询姓名为“张三”的记录} {注意,在SQL语句中,字符串应该用单引号包括起来} ARecordSet.open( 'select * from wfjcommu where AName = ''张三''', AConnection,adOpenStatic,adLockOptimistic, adCmdText ); memo1.lines.add('********张三的内容如下********'); memo1.lines.add( '共有' + IntToStr ( ARecordSet.RecordCount ) + '条匹配的记录' ); {显示各个域的内容} while not ARecordSet.eof do begin strTemp := ''; for intIndex := 0 to ARecordSet.Fields.count - 1 do strTemp := strTemp + ARecordSet.Fields [intIndex].value+';'; memo1.lines.add( strTemp ); ARecordSet.MoveNext;//移到下条,Next end; {关闭数据集和数据库连接} ARecordSet.close; AConnection.close;end;

 

---- 以上程序在PWIN98+DELPHI3.0+PWS(Personal Web Server)4.0下调试通过.

---- 关于ADO对象的详细资料,请参见ASP帮助文件或Interdev帮助文件或OFFICE2000的有关文档.


作者: 0758河台小赵    时间: 2004-9-5 13:41
轻轻松松在DELPHI3.0中实现三态按钮

---- 在许多新的软件中都用到三态按钮。所谓的三态按钮就是当鼠标还末移到时,按钮显示一种平面图像(FLAT);当鼠标移到按钮时,按钮呈现凸立体(UP);当鼠标在按钮上按下时,按钮呈现凹立体(DOWN)。

---- 由于DELPHI中有图像按钮,能够实现UP和DOWN两种状态,因此只需增加FLAT状态即可。笔者经过研究,发现有以下两种方法。

---- 1. 修改BITBTN上的GLYPH属性.

---- (1)当处于FLAT状态时,GLYPH属性设置为图像文件1,为了让按钮只是平面地显示,必须让图像文件1的尺寸大于按钮的实际尺寸,按钮就呈现平面状,可以在 FORM的ONMOUSEMOVE事件上用以下函数实现:

Bitbtn1.glyph.loadfromfile(‘文件名1’);

---- (2)当处于UP和DOWN状态时,GLYPH设置为图像文件2。由于BITBTN构件本身就具有按钮的特性,所以对图像大小没有特殊要求。可以在BITBTN1的ONMOUSEMOVE事件上用以下函数实现:

Bitbtn1.glyph.loadfromfile(‘文件名2’);

---- 用这种方法实现的三态按钮有一个明显的不足,由于BITBTN1不断地从图像文件LOAD图像数据,因此图像一直闪烁不定,不但影响运行速度而且效果不佳。

---- 2.修改IMAGE构件和BITBTN构件的VISIBLE属性

---- 在FORM的同一个位置设置大小完全相等的两个构件IMAGE1和BITBTN1,由于一起动FORM时,显示FLAT状态,因此把IMAGE1的VISIBLE属性初值设为TRUE;把BITBTN1的VISIBLE属性设为FALSE。

---- (1)当处于FLAT状态时,只显示IMAGE1构件。即把IMAGE1的VISIBLE属性设为TRUE,把BITBTN1的VISIBLE属性设为FALSE。于是FORM的OMMOUSEMOVE事件上调用如下语句:

IMAGE1.VISIBLE:=TRUE; BITBTN1.VISIBLE:=FALSE;

---- (2)当处于UP或DOWN状态时,把IMAGE1的VISIBLE属性设为FALSE;把BITBTN1的VISIBLE属性设为TRUE。因此在IMAGE1和BITBTN1的 ONCLICK事件上分别调用如下语句:

IMAGE1.VISIBLE:=FALSE; BITBTN1.VISIBLE:=TRUE;

---- 使用该方法虽然多用了一个构件,但是不必频繁地装载图像数据,因此运行速度快,效果也很好。

---- 以上是我在实践的过程中发现的两种比较简单的方法,当然还有许多其它的方法也可以实现,愿与各位探讨。


作者: 0758河台小赵    时间: 2004-9-5 13:42
Delphi中TApplication类的巧用 ---- Delphi是一种面向对象的编程语言,由于它采用完全集成OOP的优点,因此 使它成为目前十分流行的Windows开发工具。在Delphi包含的众多类中,TApplic ation是一个有着十分重要作用的类。TApplication类是用于描述Delphi编制的应 用程序的一个类。通过对这个类的灵活应用可以编制许多有特点的程序。下面我 们就举几个这方面的例子。 ---- 1 检测当前Windows程序是否被激活: ---- Tapplication类有一个属性——Active,这个属性就可以描述当前运行的程 序是否被激活,成为Windows的焦点。检测的代码如下: If Application.Active=False then ShowMessage(’当前窗口没有被激活’); ---- 2 取得当前程序的名称: ---- Tapplication类的EXEName属性可以返回这个可执行程序的完整文件名(包 含路径)。实现的代码如下所示: ---- ShowMessage(Application.ExeName); ---- 3 改变程序极小化时的标题 ---- 如果您细心观察可以发现,一些程序的标题和程序的名称并不一致,尤其是 一些英文程序,窗体的标题栏比较长,可以容纳比较多的文字,而在最小化时, 往往变成了很少的几个字母。这中间起作用的就是Tapplication类的Title属性。 这个属性决定了程序最小化时的标题,而窗口中标题栏的标题是由Form的Captio n属性来决定的。其代码如下: Form1.Caption:=’ 窗口的标题’; Application.Title:=’程序的标题’; ---- 其实我们也可以在在程序设计时指定Tapplication类的Title属性值。操作 的方法是在开发环境中拉下Project菜单,选择Options菜单时弹出如图1 (略)的对 话框。在这个对话框中的Title栏中填写程序的标题一样也可以达到这种效果。并 且因为一般的工程文件都是以英文命名的,所以程序运行过程中弹出的消息框中 的标题是英文。但在指定了这个属性之后,这个程序的所有消息窗口的标题都变 为Title的值。这就使得程序看起来更加完整。 ---- 4 指明程序的主窗口 ---- Windows系统中的界面都是窗口,但一般来讲有一个主窗口。Tapplication 的MainForm属性就可以返回程序的主窗口。 ---- 5 显示消息框 ---- Delphi有许多显示消息框的函数与过程,比较常用的是ShowMessage,它用 起来虽然十分方便,但是却有一个问题,那就是这个消息框的按钮是以英文显示 的。如果要生成一个含有中文显示的按钮就要求助于Tapplication的MessageBox 函数了。这个函数的原形如下: ---- function MessageBox(Text, Caption: Char; Flags: Longint): Integer ; ---- 在这个函数中,前两项分别是显示的提示信息和消息窗口的标题,Flags是 一个长整值,用来指定按钮的个数及功能。熟悉Delphi的用户可能会注意到,这 个函数和Delphi 3所提供的同名函数有一点不同,那不是这个版本中字符串参数 都以字符的形式给出,而不再要求将其转化成指针。我们在使用时要注意加以区 别。 ---- Application.MessageBox('需要存盘吗?','提示信息',MB_OKCANCEL); 这 个语句在运行时显示的样式如图2 (略) 所示。 ---- 最后就这个函数的返回值作一些说明,实际上这个函数返回的是一个整型的 数值,而这个数值被系统指定了具体的含义,比如:按下“确定”按钮时返回的 值是“1”,而其它按钮的值列在表 1 中。 ---- 表 1 按钮的意义及系统中对其定义的值 按钮的意义 按下此按钮时函数返回的值 IDABORT 3 IDCANCEL 2 IDIGNORE 5 IDNO 7 IDOK 1 IDRETRY 4 IDYES 6 ---- 6 控制窗口的尺寸 ---- 一般可以用窗口手柄来调整窗口的尺寸,但是也可以用Application的事件 来调整。实现的方法是用以下两个过程: Application.Minimized; Application.Restore; ---- 前一个过程用来将程序的主窗口最小化,而后一个过程用来将最小化的窗口 恢复到原来的尺寸。 ---- 7 链接联机帮助文件 ---- Application的CurrentHelpFile属性能够指定当前程序所用的联机帮助文件 的文件名。这个属性经常与另一个方法联合在一起使用。举例如下: Application.HelpFile := '联机帮助文件名'; Application.HelpJump('联机帮助文件的主题’) ---- 通过这一命令组合,我们就能使系统弹出一个显示某主题的联机帮助文件。 ---- 8 在程序运行时动态地创建窗口 ---- 一般情况下,窗口是在设计时加入到工程项目中的,但是有时也需要我们在 程序运行时动态地加入窗口,这就要用到Application 的CreateForm过程,举例 如下: Form3:Tform3; //声明窗口类 Application.CreateForm(TForm3, Form3); //创建窗口 ---- 9 结束程序 ---- 虽然我们可以用关闭主窗口的方法来关闭一个程序,但是更好的办法是用A pplication的Terminate过程。它能够起到更彻底地关闭程序的效果。 ---- 10 Destroy 属性. ---- 虽然Delphi提供了这一属性,但是并不提倡使用它,如果要终结程序就要调用 Terminate过程,而Destroy过程一般是用来在程序发生悬挂时来退出程序时才调 用,有些类似Windows中的结束任务功能。它不仅能关闭程序实例本身,而且还能 释放程序所占用的资源,能够达到将程序彻底清除出系统的目的。


作者: 0758河台小赵    时间: 2004-9-5 13:44
Delphi 中自做动态显示的控件

---- Delphi以其优秀的界面和简单的用法深受广大程序员的喜爱.笔者经过摸索,自做了一个具有动态显示特性的控件。只需在主程序中调用该控件的一个方法即可实现动态显示。在动态显示的同时,为了不影响主程序做其他的事情,笔者采用了比较流行的线程技术。

---- 一. 方案

---- 自做一个父类为TEdit的控件,应该有一个Text属性,能自由地输入要动态显示的内容; 并且有一个MoveShow方法,使的Text的内容能动态的显示。在主程序中创建一个线程,启动线程时,调用该控件的MoveShow方法。

---- 二. 制作控件

---- 启动New Component,选Tedit为父类,建立L_Tedit1类,并创建L_edit.pas. 再编写L_edit.pas 如下:

unit L_Edit;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;type L_TEdit1 = class(TEdit) private { Private declarations } protected { Protected declarations } public { Public declarations } constructor Create(AOwner:TComponent); override; procedure MoveShow; published { Published declarations } property Text; end;procedure Register;implementationconstructor L_TEdit1.Create(AOwner:TComponent);begininherited create(aowner);color:=clblue;font.Color:=clyellow;font.Size:=12;font.Name:= '@仿宋_GB2312';tabstop:=false;update;end;procedure L_TEdit1.MoveShow;var edit_length,i:integer; edit_char:char; chars: string;begin chars:=''; if (length(text)=0) then text:=’Welcom you to use the software!’; edit_length:=length(text); for i:=1 to edit_length do begin edit_char:=text[1]; if (Ord(edit_char) >127) then if length(chars) >1 then begin text:=copy(text,2,edit_length-2)+chars; chars:=''; end else begin chars:=copy(text,1,2); text:=copy(text,2,edit_length-1); end else begin text:=copy(text,2,edit_length-1)+edit_char; end; update; sleep(100); end;end;procedure Register;begin RegisterComponents('Samples', [L_TEdit1]);end;end.再保存该文件。

---- 启动Image Editor 创建L_Edit.dcr , 选New- >Bitmap,自己做一个图标,保存名为L_TEDIT1(与新建的类同名)。注意L_Edit.dcr 与L_Edit.pas 要在同一个目录中(缺省为\delphi\lib目录中。再单击Install Component. 选Into new package属性页,填上L_Edit.pas 的路径和文件名,并在该路径下新建L_Edit1.dpk 文件。之后一直单击OK即可。此时我们可以在Delphi 的工具栏Sample 一项中看到自己创建的图标。

---- 三. 编写主程序

---- 在主窗体Form1中放一自己创建的控件,在Text的属性中填上要显示的文字(中英文都可)。与该窗体对应的L_unit1.pas内容如下:

unit L_Unit1;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, L_Edit;type Tmythread=class(TThread) protected procedure Execute; override; end; TForm1 = class(TForm) L_TEdit11: L_TEdit1; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end;var Form1: TForm1; MyThread1:TMyThread;implementation{$R *.DFM}Procedure TMyThread.Execute;begin while true do form1.L_TEdit11.MoveShow;end;procedure TForm1.FormCreate(Sender: TObject);beginMyThread1:=TMyThread.Create(false);end;procedure TForm1.Button1Click(Sender: TObject);beginshowmessage('Welcome You!');end;end.

---- 该程序在Delphi4.0 for win95 下编译运行通过。


作者: 0758河台小赵    时间: 2004-9-5 13:45
DELPHI 中 自 适 应 表 单 的 实 现

---- 我 们 知 道, 屏 幕 分 辨 率 的 设 置 影 响 着 表 单 布 局, 假 设 你 的 机 器 上 屏 幕 分 辨 率 是800*600, 而 最 终 要 分 发 应 用 的 机 器 分 辨 率 为640*480, 或1024*768, 这 样 你 原 先 设 计 的 表 单 在 新 机 器 上 势 必 会 走 样。 这 时 你 一 定 希 望 表 单 能 自 己 适 应 不 同 的 分 辨 率, 下 面 就 有 两 种 方 法 可 供 你 参 考。

---- 一、 根 据 新 的 分 辨 率 自 动 重 画 表 单 及 控 件

---- 先 在 表 单 单 元 的Interface 部 分 定 义 两 个 常 量, 表 示 设 计 时 的 屏 幕 的 宽 度 和 高 度( 以 像 素 为 单 位)。 在 表 单 的Create 事 件 中 先 判 断 当 前 分 辨 率 是 否 与 设 计 分 辨 率 相 同, 如 果 不 同, 调 用 表 单 的SCALE 过 程 重 新 能 调 整 表 单 中 控 件 的 宽 度 和 高 度。

ConstOrignwidth=800;Orignheight=600;procedure TForm1.FormCreate(Sender: TObject);beginscaled:=true;if (screen.width<>orignwidth) thenbeginheight:=longint(height)*longint(screen.height) div orignheight;width:=longint(width)*longint(screen.width) div orignwidth;scaleby(screen.width , orignwidth);end;end;

---- SCALE 过 程 在 调 整 控 件 宽 度 和 高 度 的 同 时, 也 自 动 调 整 控 件 字 体 的 大 小, 以 适 应 新 的 分 辨 率, 但 美 中 不 足 的 是 它 并 不 改 变 控 件 的 顶 点 坐 标 位 置, 也 就 是 说, 该 过 程 不 改 变 控 件 之 间 的 相 对 位 置 关 系。 要 想 调 整 控 件 之 间 的 选 队 相 对 位 置, 还 需 要 自 己 编 程 实 现, 有 兴 趣 的 读 者 可 试 一 试。

---- 二、 将 机 器 分 辨 率 更 改 为 设 计 时 的 分 辨 率

---- 这 种 方 法 不 改 变 表 单 本 身, 而 是 将 屏 幕 分 辨 率 更 改 为 与 表 单 设 计 时 用 到 的 分 辨 率 相 同。 它 需 要 用 到WINDOWS API 函 数EnumDisplaySettings 和ChangeDisplaySettings, 前 者 取 当 前 显 示 模 式 信 息, 后 者 则 更 改 显 示 设 置, 具 体 参 数 的 含 义 请 参 见 DELPHI 帮 助。 设 计 时 宽 度 常 量 和 高 度 常 量 的 定 义 如 方 法 一。

procedure TForm1.FormCreate(Sender: TObject);vardevmode:tDevicemode;beginif screen.width<>orignwidth then begin if EnumDisplaySettings(nil,0,devmode) then begindevmode.dmfields:=dm_pelswidth OR dm_pelsheight ;devmode.dmpelswidth:=orignwidth; {宽度}devmode.dmpelsheight:=orignheight;{高度}ChangeDisplaySettings(devmode,0); {更改设置}end;end;end;

---- 以 上 两 种 方 法 在WINDOWS 95+DELPHI 3.0 环 境 下 均 已 通 过, 二 者 相 比, 前 者 是 主 动 适 应, 后 者 则 是 被 动 适 应。


作者: 0758河台小赵    时间: 2004-9-5 13:46
在Delphi 中 利 用 Tbatch 组 件 完 成 数 据 批 处 理

---- 在 数 据 库 应 用 系 统 中, 常 常 要 对 数 据 进 行 成 批 的 如 追 加、 删 除、 更 改 等 操 作, 这 种 批 量 操 作 在 专 门 的 数 据 库 开 发 工 具 如VFP 中 用APPEND 、COPY 命 令 带 上 相 应 的 命 令 子 句 就 能 轻 易 完 成。 但 在 其 它 开 发 工 具 中 并 没 有 类 似 的 命 令, 而 是 提 供 能 完 成 类 似 功 能 的 控 件 或 对 象, 如 在PowerBuilder 中 就 是 利 用 Pipe Line( 数 据 管 道) 来 完 成 两 个 或 同 构 或 不 同 构 的 表 之 间 的 数 据 批 处 理。 本 文 要 介 绍 的 是Delphi 中 用 来 完 成 数 据 批 处 理 任 务 的 组 件TBatchMove。TBatchMove 组 件 能 够:

将 一 个 数 据 集 中 的 数 据 追 加 到 一 个 表 中。. 从 一 个 表 中 删 除 满 足 条 件 的 记 录。 按 旧 表 结 构 生 成 一 个 新 表, 若 欲 生 成 的 新 表 已 存 在, 则 覆 盖。

 

---- 具 体 的 操 作 要 通 过 设 置TBatchMove 的Mode 属 性 后 再 调 用Execute 方 法 来 完 成。 为 举 例 说 明 问 题, 我 们 在 别 名 数 据 库DBDEMOS 中 先 创 建 两 个dBase 格 式 的 表Test1.dbf 和Test2.dbf。 二 者 的 结 构 如 下 表:

Test1.dbf Test2.dbf Name C 10 Name C 10 Code C 3 Code C 3

 

---- 其 中 表Test2.dbf 在 字 段code 上 建 立 有 唯 一 索 引。 同 时 假 设 表 单 中 已 有 两 个 TABLE 控 件Tsource 和Tdest 和 一 个TbatchMove 组 件batchmove1。Tsource 和Tdest 的DatabaseName 属 性 均 设 为DBDEMOS。batchmove1 的source 属 性 设 为Tsource,destination 属 性 设 为Tdest。 ---- 在 使 用TbatchMove 组 件 时, 必 须 牢 记: 所 有 的 操 作 都 是 以 源 表 为 标 准 针 对 目 的 表 进 行 的, 下 面 就 分 别 举 例 说 明TbatchMove 的 各 种 操 作 模 式: batAppend 追 加 模 式 将 源 表 中 的 数 据 追 加 到 目 的 表 中, 目 的 表 必 须 事 先 存 在。 这 是 缺 省 模 式。 batchmove1.source=Tsource; batchmove1.destination=Tdest2 ; batchmove1.Mode:=batCopy; batchmove1.Execute; batUpdate 更 新 模 式 用 源 表 中 匹 配 目 的 表 的 记 录 替 换 目 的 表 中 的 相 应 记 录。 目 的 表 必 须 事 先 存 在 且 有 一 已 定 义 的 索 引 用 来 匹 配 源 表 中 的 记 录。 Tdest.IndexFieldNames:='code'; batchmove1.source=Tsource; batchmove1.destination=Tdest ; batchmove1.Mode:=batUpdate; batchmove1.Execute; batAppendUpdate 追 加 更 新 模 式 如 果 源 表 中 有 与 目 的 表 匹 配 的 记 录, 则 替 换 目 的 表 记 录, 否 则, 直 接 追 加 到 目 的 表 中。 目 的 表 必 须 事 先 存 在 且 有 一 已 定 义 的 索 引 用 来 匹 配 源 表 中 的 记 录。 Tdest.IndexFieldNames:='code'; batchmove1.source=Tsource; batchmove1.destination=Tdest ; batchmove1.Mode:=batAppendUpdate; batchmove1.Execute; batCopy 拷 贝 模 式 按 源 表 结 构 生 成 新 表, 源 表 中 的 数 据 同 时 拷 贝 到 目 的 新 表 中。 如 果 要 生 成 的 新 表 已 存 在, 则 覆 盖。 // 按Test1.dbf 生 成 新 表xxx.dbf // 如 果 不 指 定 扩 展 名dbf, 生 成 的 新 表 将 是Paradox 格 式 的xxx.db。 Tdest.TableName:='xxx.dbf'; batchmove1.source=Tsource; batchmove1.destination=Tdest ; batchmove1.Mode:=batCopy; batchmove1.Execute; batDelete 删 除 模 式 删 除 目 的 表 中 与 源 表 匹 配 的 记 录。 目 的 表 必 须 事 先 存 在 且 有 一 已 定 义 的 索 引 用 来 匹 配 源 表 中 的 记 录。 Tdest.IndexFieldNames:='code'; batchmove1.source=Tsource; batchmove1.destination=Tdest ; batchmove1.Mode:=batDelete; batchmove1.Execute;

 

---- TBatchMove 还 有 一 个 重 要 属 性ChangedTableName, 在 实 际 运 用 中, 通 过 指 定 ChangedTableName 属 性 可 以 创 建 一 个Paradox 表, 该 表 用 来 保 存 目 的 表 中 被 更 改 数 据 的 原 始 备 份, 有 了 这 个 备 份 表 就 可 以 确 保 恢 复 目 的 表 中 的 数 据。

---- 顺 便 提 一 句, 如 果 要 删 除 某 一 个 表 中 的 全 部 记 录, 可 以 采 用Table 组 件 的 EmptyTable 方 法, 例 如Tdest.EmptyTable 将 清 空Tdest 所 指 定 的 表test2.dbf。

---- 本 文 中 是 以 同 构 的dbf 表 进 行 的 示 例, 在 实 际 运 用 中, 源 表 和 目 的 表 可 能 同 购, 也 可 能 异 构, 异 构 时,Delphi 的BDE 会 自 动 进 行 类 型 和 长 度 上 的 转 换, 具 体 类 型 间 的 关 系 可 以 有 关BDE 的 帮 助。 本 文 中 各 种 操 作 模 式 的 实 际 结 果 均 可 以 从Delphi 的Database Desktop 中 查 看 到。


作者: 0758河台小赵    时间: 2004-9-5 13:47
如何在注册表中注册BDE

只拷贝BDE文件是不行的,还要写注册表: 必需的注册表项目包括: 1. BDE动态连接库文件位置设置 Key : "HKEY_LOCAL_MACHINE\Software\Borland\Database Engine" Item : "DLLPATH" Value : BDE动态连接库文件所在位置,如"C:\Program Files\Borland\Common Files\BDE" (打开"C:\Program Files\Borland\Common Files\BDE\BDE32.hlp", 查找"Core Files"即可了解BDE各动态连接库文件的作用) 2. BDE语言驱动文件路径设置 Key : "HKEY_LOCAL_MACHINE\Software\Borland\BLW32" Item : "BLAPIPATH" Value : BDE语言驱动文件所在路径,如"C:\Program Files\Borland\Common Files\BDE" (BDE语言驱动就是那些*.BLL文件) 3. 指定可用的BDE语言驱动文件 Key : "HKEY_LOCAL_MACHINE\Software\Borland\BLW32" Item : "LOCALE_LIB#" (#表示数字, 如"LOCALE_LIB1"、"LOCALE_LIB3"等) Value : 指定各BDE语言驱动文件,如"C:\Program Files\Borland\Common Files\BDE\USA.BLL" (一般必需的语言驱动文件有"USA.BLL","EUROPE.BLL"和"FAREAST.BLL",为保险起 见,建议将所有语言驱动都设置上。在安装了Delphi3的机器上,用Regedit打开注册 表,一看你就明白了怎么设了)


作者: 0758河台小赵    时间: 2004-9-5 13:50
CGI技术及其开发(一)

作为Internet上最主要的信息管理和组织手段,WWW由一系列相应的技术及应用构 成,其组成技术包括HTTP、HTML、URL以及CGI等。WWW服务器本身提供一些基本功 能,以完成客户端的请求和自身的管理。但不同的用户有不同的功能要求,其中许 多功能是WWW服务器本身 不能提供的(比如在线查询等),它必须提供一种扩展手 段,以允许用户编写扩展应用程序来扩展服务器的功能。CGI(CommonGatewayInterface, 即通用网关接口)就是这样的一种标准扩展技术。下面就CGI的基本技术及其开发 进行讨论。 一、CGI技术 1.1CGI的提出 CGI是外部扩展应用程序与WWW服务器交互的一个标准接口。按照CGI标准编写的外 部扩展应用程序可以处理客户端(一般是WWW浏览器)输入的协同工作数据,完成 客户端与服务器的交互操作。这在实际应用中非常有用,如可以编写CGI外部扩展 程序来访问外部数据库,客户端用户可以通过它和WWW服务器来进行数据查询。CGI 一般分两种:标准CGI和缓冲CGI。所有的WWW服务器均应支持标准CGI,按标准CGI 编写的程序与具体的WWW服务器无关。而按缓冲CGI编写的程序与WWW服务器有关。 1.2CGI的工作原理 1.标准CGI 客户端、服务器、CGI接口与外部程序间的关系可用图1-1表示:如上图所示,服 务器是客户端(如浏览器)与扩展程序之间的通道。当客户端的用户完成了一定 输入工作(比如填充完HTML文档中的FORM表)之后向服务器发出HTTP请求(称为CGI 请求),服务器守护进程接收到该请求后,就创建一个子进程(称为CGI进程)。 该CGI子进程将CGI请求的有关数据设置成环境变量,在外部CGI程序与服务器间建 立两条数据通道(标准I/O),然后启动URL指定的CGI程序,并与该子进程保持同 步,以监测CGI程序的执行状态。子进程通过标准输出流将处理结果传递给服务器 守护进程,守护进程再将处理结果作为应答消息回送到客户端。外部CGI程序通过 环境变量、命令行参数、标准输入输出与WWW服务器进行通讯,传递有关参数和处 理结果。*环境变量:当服务器守护进程创建子进程运行CGI程序时,设置相应的 环境变量和命令行参数,以传递客户端和服务器的有关信息给该子进程。*命令行 参数:命令行参数仅在有HTML文档中有ISINDEX查询的情况下使用。*标准输入输 出:当HTTP请求模式采用POST方式时,CGI程序通过标准输入流和有关环境变量来 获取客户端传输数据;如采用GET方式时,CGI程序直接通过环境变量获取客户端传 输数据。当CGI程序要返回处理结果(一般为HTML文档)给客户端时,它通过标准 输出流将该结果数据传递给服务器守护进程。 2.缓冲CGI 标准CGI使用Stdin/Stdout来进行数据通讯,这是由其最初开发环境(Unix操作 系统)所决定的。但是许多Windows环境下的编程工具(如VB和Delphi等)是不支 持这种I/O方式的,这时就不能用它们来开发基于标准CGI的应用程序。于是有些 服务器提出了缓冲CGI的概念。缓冲CGI亦称为WinCGI。此时CGI扩展程序与服务器 间通过缓冲CGI而不是标准CGI进行通讯,而缓冲CGI与服务器间的通讯还是通过标 准CGI接口。后者由WWW服务器的内置缓冲处理程序实现。这几部分的关系可用图 1-2表示:缓冲CGI的工作原理与标准CGI相似,不同的是当服务器守护进程接收 到客户端的CGI请求时,所建立的CGI子进程将CGI请求的有关数据设置成环境变量 外,还将它们保存在输入缓冲区中;通过缓冲处理程序在外部CGI程序与服务器间 建立两条数据通道(输入/输出缓冲区)。CGI子进程通过输出缓冲区将处理结果 传递给服务器守护进程。此处外部CGI程序通过环境变量和输入/输出缓冲区与WWW 服务器进行通讯,传递有关参数和处理结果。此处环境变量的意义同上,不过这 些环境变量及其相应值保存在输入缓冲区中。此外,输入缓冲区中还存放客户端 的传输数据(如采用POST模式的话)。输出缓冲区用来存放扩展程序的处理结果。 3.标准CGI与缓冲CGI的区别 对CGI扩展程序而言,最主要差别在于数据的I/O不同:对缓冲CGI,服务器与CGI 扩展程序间的数据交换是通过缓冲区;而标准CGI是通过标准I/O。使用缓冲CGI可 选择更多的开发工具,可以开发Windows95和WindowsNT下的GUI扩展程序;而使用 标准CGI所选用的开发工具必须支持标准I/O。只有少数几种WWW服务器支持缓冲CGI, 因此基于它的扩展程序兼容性不如标准CGI好。 1.3CGI与其他WWW技术的关系 CGI作为WWW服务器的标准扩展技术,由上面CGI的基本原理可知,它和许多其它的 WWW技术密切相关,如HTTP、HTML、MIME和URL等,下面主要就它与前两种技术的关 系进行研究。 1.CGI与HTTP协议 CGI通过HTTP协议在客户端和服务端进行通讯:*客户端用户代理向服务器发送的 请求是HTTP请求消息。该消息中含有处理用户输入的CGI扩展程序的URL值。*CGI 扩展程序在处理结束后,返回给客户端的应答是HTTP应答消息。因此CGI程序的输 出数据必须符合HTTP应答消息的语法格式,这在基于CGI标准的开发中非常重要。 2.CGI与HTML语言 CGI扩展程序的输出数据(HTTP应答消息)一般有两种:符合MIME类型的文档(最 普遍的是HTML文档,表示为text/html);指向其它文档的URL链接。这两种方式 都与HTML语言有关,数据的组织须符合HTML语法格式。 1.4CGI开发的几个问题 基于WWW的人机交互一般有两种情况:本地交互和通过网络传输的交互。前者是指 客户端用户的输入数据在客户端本地进行处理,然后将处理结果返回给用户,常 见的开发工具有JavaScript(Netscape开发)和VBScript(Microsoft开发);后 者是指客户端用户输入的数据通过网络传输到WWW服务器,服务器处理结束后将处 理结果返回给客户端用户,常见的开发技术是WWW服务器扩展技术(如CGI,API等)。 此处主要讨论基于标准CGI技术的通过网络进行数据传输的交互实现。对这种人机 交互的实现,主要有三个环节需要解决:如何获取客户端传输的数据,如何提取有 效数据并处理这些数据,如何向客户端返回应答。下面分别结合有关技术,谈谈这 三方面问题的解决。 1.客户端传输数据的获取 由第三章CGI的原理可知,当服务端守护进程接收到客户端用户代理(如浏览器) 提交的CGI请求时,所创建的CGI子进程会设置与CGI请求内容有关的环境变量,并 建立服务器与外部CGI程序之间通讯的通道(即标准I/O)。CGI程序可以通过环境 变量,标准I/O或命令行参数获取客户端用户输入的数据。数据的获取与请求所采 用的HTTP方法(Method)和用户所使用的请求方式有关。用户通过CGI请求数据一 般有三种方式:HTMLFORM表,ISINDEX,可点击图片(ISMAP或Imagemaps)。后两 种方式是通过命令行参数传递用户的输入数据;在C语言中(下面的举例亦然), CGI程序可以用argc和argv[int]获得这些参数值。而前一种方式则取决于HTTP请 求方法;但不管采用何种方法,都将用到环境变量来传递有关请求内容。 ●获取环境变量 环境变量的类别很多,包含客户端和服务端的详细信息。在一般CGI程序开发中, 下述几个环境变量在数据传递中起着重要作用。 *GATEWAY—INTERFACE CGI程序所使用的CGI标准接口的版本号。如使用的CGI1.1版,该变量表示为 “CGI/1.1” *REQUEST—METHOD HTTP请求方法。根据该变量值可判断CGI请求所采用的请求方法,以决定是通过Stdin 还是通过环境变量QUERY—STRING获取客户端传输数据。 *QUERY—STRING QUERY—STRING是CGI程序URL中″?″之后的数据。当使用ISINDEX查询或FORM表使 用GET方法时,客户端传输数据可以通过读取该变量而获得。 *CONTENT—LENGTH CONTENT—LENGTH表示客户端传输数据的字节数。 *CONTENT—TYPE CONTENT—TYPE表示客户端传输数据的数据编码类型。 利用—environ(int)函数可以获得所有的环境变量及其值; 利用getenv(constchar*)函数可以获得指定环境变量的相应值。 ●HTTP请求方法 客户端用户代理提交的CGI请求是HTTP请求,其中包括HTTP请求方法。HTTP协议定义 的请求方法中常用的主要有GET和POST。 客户端FORM表的METHOD属性用来设置请求方法,其缺省值为GET。如果在FORM中使用 GET方法,CGI程序通过环境变量QUERY—STRING获取客户端传输数据。如果在FORM中 使用POST方法,CGI程序通过通过CONTENT—LENGTH获取客户端传输数据的字节数, 通过Stdin读取客户端传输数据。 2.有效数据的提取和处理 通过上述方式获取的客户端传输数据的一般格式为: name[1]=value[1]&name[2]=value[2]&...name[i] =value[i]...name[n]=value[n] (1Ι=iΙ=n) 其中name[i]表示变量名,它是在FORM表中某输入域的名字;value[i]表示变量 值,它是用户在FORM表中某输入域中输入的值。客户端传输数据的每对″Name=Value″ 串由′&′字符分隔,其数据编码类型可以从环境变量CONTENT—TYPE获取。CGI/1.1 版仅支持“application/x-www-form-urlen?coded”编码方式。这种编码方式和 URL的编码方式一样,遵循两个规则:数据中的空格(ASCII码值32)编码成′+′号; 保留字符编码成″%XX″形式,″XX″是该字符ASCII值的十六进制表示,比如″$″ 的编码为″%24″,″?″的编码为″%3F″。因此,要获取客户端用户的输入数据, 必须对上述获取的数据进行分离和解码等处理。利用函数strtok()、strchr()等 可以实现数据分离处理,而数据的解码则需要对整个数据串进行扫描,将数据串中的 ″%XX″复原为对应的ASCII码。在提取到有效数据后,还可能进行许多其他的处理, 如数据库查询等。这种处理与普通编程相同。 3.向客户端返回应答 CGI程序处理结束后,通过标准输出流将应答信息传递给服务器,再由服务器返回给发 出请求的客户端。其输出的应答信息是HTTP应答消息,它一般由两部分组成:应答头 和应答数据。常见的应答头包括三种头域:Content—Type(数据编码类型,用MIME类 型表示),Location(特定文档的URL,这种情况不直接向客户端输出内容而输出该URL) 和Status(处理结果的状态码和状态描述)。HTTP应答头由几行格式相同的文本构成, 每行的基本格式为:″头域名:该域内容″。应答头和应答体之间用一空行加LF(或 CR/LF)分隔。应答体为CGI扩展程序的输出数据,其数据类型应该与Content—Type 值相一致。CGI程序的输出可以用printf()、puts()等标准I/O函数来实现。 4.CGI程序的开发及其一般流程 在开发CGI程序过程中,可根据实际情况(服务器提供的接口、实际需求和程序员经验 等)选择编程语言,如C/C++,Perl,TCL,AnyUnixshell,VB,AppleScript。如 果选用C/C++等语言,必须编译成可执行文件;如果选用Perl等解释语言,服务器 必须安装相应的解释器。 二、CGI与其它扩展技术的比较 除CGI标准扩展技术外,常见的扩展技术还有API(ApplicationProgrammingInterface) 和SSI(ServerSideIncludes),这两种技术都与具体的WWW服务器有关。下面先对这两 种技术简要说明,然后再对这三种技术作比较。SSI技术:当服务器守护进程接收到客 户端请求时,其子进程扫描客户端所请求的文档,以获取数据插入标志,再插入相关动 态数据,然后返回给客户端。这种技术简单,但效率不高。API技术:不同的WWW服务器 提供的API可能不同,比如O′ReillyWebsite提供的是WSAPI;PurveyorWebserver和Microsoft IIS提供的是ISAPI。利用这些API编写程序的流程和最后生成的文件类型也不一样;比 如用ISAPI,编写程序时必须依照它的特定框架,最后建立的文件可以是EXE文件和DLL 文件。下表(图3-3)列出了CGI、SSI和API三种技术在主要性能方面的比较:SSI CGI API 实现的灵活性 差 好 好 可实现的功能 差 强大 强大对程序员的要求 低 一般 较高 开发与测试时间 短 一般 较长 花费 低 一般 较高操作的风险性 低 低 较大移植性 较好 较好 差 CPU的负载 高 高 较低CGI和API都需要编程实现,利用它们可访问更 多的数据源;而SSI不需编程。利用API开发的扩展软件,其运行速度比CGI快,功能也 较CGI强;但其操作有一定的风险,出现错误时可能使系统崩溃(CGI程序不会),并 且它非常依赖于具体的服务器而移植性太差,开发周期较长。CGI在操作的风险性、软 件移植性、软件开发难度等方面较API有优势;其缺点在于CPU负载较高,特别是同时 发生的CGI请求很多时,将影响服务器的综合性能。综合比较而言,CGI比其它两种技 术更优秀,在实际应用中也最为普遍。


作者: 0758河台小赵    时间: 2004-9-5 13:56
CGI技术及其开发(二)

教 学 纲 要 在 上 一 讲 中, 我 们 设 置 了 用 于 开 发 CGI 程 序 的 系 统。 今 天, 我 们 进 入: 第 二 部 分、 CGI 程 序 设 计 的 概 念 …… 第 二 部 分、 CGI 程 序 设 计 的 概 念 1.0 、 CGI 程 序 的 功 能:     首 先, 什 么 是 公 共 网 关 接 口( CGI ) 呢? CGI 是 一 个 用 于 定 义 WEB 服 务 器 与 外 部 程 序 之 间 通 信 方 式 的 标 准, 使 得 外 部 程 序 能 生 成 HTML 、 图 象 或 者 其 他 内 容, 而 服 务 器 处 理 的 方 式 与 那 些 非 外 部 程 序 生 成 的 HTML 、 图 象 或 者 其 他 内 容 的 处 理 方 式 是 相 同 的。 因 此, CGI 程 序 不 仅 使 你 能 生 成 静 态 内 容, 而 且 能 生 成 动 态 内 容。 使 用 CGI 的 原 因 在 于 它 是 一 个 定 义 良 好 并 被 广 泛 支 持 的 标 准。 虽 然, Java 、 ActiveX 等 可 以 完 成 CGI 程 序 的 功 能, 但 并 不 是 所 有 浏 览 器 都 支 持 它 们。 相 反, 所 有 浏 览 器 都 支 持 CGI , 如: Lynx 、 IE 、 Netscape 等。     然 而, 和 其 他 技 术 一 样, CGI 也 有 它 的 局 限 性。 本 节 我 就 讲 述 CGI 程 序 的 功 能、 优 点 与 不 足。 1.1 、 CGI 功 能     有 许 多 任 务, CGI 是 最 佳 的 是 唯 一 的 选 择, 这 些 任 务 可 分 为 三 类: 初 级 任 务、 中 级 任 务 和 高 级 任 务。 初 级 任 务 是 一 些 不 用 怎 么 编 程 的 任 务, 如: 文 本 型 计 数 器 生 成 简 单 的 HTML 的 程 序 少 于 50 行 用 Perl 语 言、 Shell 脚 本、 C 语 言 或 C++ 语 言 编 写 的 程 序     这 样 的 任 务 用 CGI 来 写 至 少 有 三 点 好 处: 第 一、 CGI 运 行 最 快, 而 Java 等 开 销 太 大; 第 二、 CGI 标 准 于 当 前 浏 览 器 最 兼 容, 这 一 点 在 前 面 已 经 提 到; 第 三、 CGI 资 源 丰 富, 您 在 Internet 上 可 以 找 到 成 千 上 万 的 CGI 代 码。     中 级 任 务 是 包 括 图 象 映 象 和 其 他 一 些 稍 复 杂 的 程 序 设 计 任 务。 在 中 级 任 务 中, 用 CGI 和 Java 来 编 写 程 序 的 难 易 程 度 差 别 不 大。     此 类 任 务 包 括: 图 象 映 象 生 成 整 页 的 HTML 的 CGI 脚 本 动 画     很 有 特 点 的 是, 对 于 高 级 任 务, 用 CGI 比 用 Java 编 程 要 简 单 得 多。 此 类 任 务 有: 后 端 数 据 库 操 作 搜 索 引 擎 多 重 动 态 页 面     其 中, 后 端 数 据 库 操 作( 存 取 数 据 库 的 应 用 程 序) 体 现 了 CGI 的 优 越 性。 CGI 有 一 定 的 历 史, 其 中 很 多 有 用 的 功 能 都 在 CGI 的 库 中 由 别 人 做 好 了; 同 时, 许 多 大 公 司 提 供 了 用 CGI 承 虿 僮 髌 涫 ? 菘 獾 姆 椒ā6 ? 遥琂 ava 是 一 种 程 序 设 计 语 言, 而 CGI 是 网 关 程 序 的 功 能 规 范。 如 果 Java 有 较 大 改 变, 您 得 重 写 整 个 程 序; 而 CGI 有 较 大 变 化 的, 您 只 要 升 级 CGI 库 程 序 即 可。     然 而, CGI 在 有 些 方 面 还 是 有 局 限 性 的。 1.2 、 CGI 的 局 限 性     在 图 象 映 象 和 动 画 方 面, CGI 程 序 不 如 Java 程 序 开 发 方 便。 现 在 Java 越 来 越 流 行, CGI 程 序 则 越 来 越 适 合 编 写 简 短 杂 乱 的 程 序 和 数 据 库 应 用 程 序。 1.3 、 CGI 程 序 功 能     CGI 程 序 的 最 大 特 点 是 可 以 用 任 何 一 种 语 言 编 制, 可 运 行 在 任 何 一 种 平 台 上, 只 要 它 符 合 CGI 的 规 范 即 可。 下 表 是 一 个 比 较: 任 务 CGI+HTML HTML 处 理 表 单 Yes No 创 建 WEB 页 面 上 非 静 态 内 容 Yes No 处 理 图 象 映 象 文 件 Yes Yes 在 WEB 页 面 和 文 档 中 搜 索 Yes No 创 建 表 单 Yes Yes 创 建 平 台 无 关 的 文 档 Yes Yes 创 建 聊 天 室 等 交 互 应 用 程 序 Yes No 页 面 动 态 生 成 Yes No 按 用 户 需 要 进 行 页 面 文 档 裁 剪 Yes No     下 面, 我 们 用 一 系 列“ Hello World ” 程 序 结 束 本 讲: Perl : Require "cgi-lib.pl"; print &PrintHeader; print "\n"; print "Hello World\n"; print &PrintEnv; exit;     此 文 件 存 储 在 C:\HTTPD\CGI-BIN 目 录 下, 文 件 名 为 2_1.pl 。 在 浏 览 器 中 用 地 址 http://localhost/cgi-bin/2_1.pl 调 用。 注 意, 此 时 OmniHTTPD 应 在 运 行。 如 果 一 切 正 常, 您 可 以 在 浏 览 器 中 看 见“ Hello World ” 和 环 境 变 量。 C : #include #include "html-lib.h" #include "cgi-lib.h" int main() {     html_header();     html_begin("Test CGI");     h1("CGI Program");     printf(" ------------------------------------------------------------------------------ -- \n");     h2("CGI Environment Variables");     print_cgi_env();     html_end();     return 0; }     编 译 后 将 可 执 行 文 件 复 制 到 C:\HTTPD\CGI-BIN 下, 改 名 为 2_1.cgi , 用 地 址 http://localhost/cgi-bin/2_1.cgi 调 用。


作者: 0758河台小赵    时间: 2004-9-5 13:57
如何在标题栏上增加按钮

---- 大家在使用某些软件的过程中,有没有注意到有些软件有一些很有趣的东西。比如说在主窗口的标题栏上居然有一个按钮。在Internet中随处可见这样的小控件。按钮怎么可以加入到非客户区(Client)呢?

---- 在这里,最关键的一点就是,大家不要被传统知识误导:真的认为它是一个按钮。有名柄(handle)的控件当然不能放在标题栏上了。有经验的程序员用Spy++跟踪一下的话,马上就会发现其中的秘密。它并不是一个按钮,只不过是处理成按钮的样子罢了。

---- 既然知道了所以然,那么我们为什么不能自己来做一个呢,当然没问题,下面我们就用Delphi来实现它,讲注意我的注解。

---- 在具体实例之前,我们应该知道几个关于标题栏的重要的消息:

---- WM_NCPAINT:重画标题栏消息。我们必须截住它,可以在这里重画按钮;

---- WM_NCLBUTTONDOWN:在标题栏上按下鼠标左键消息。我们可以截住它,在标题栏上画出按钮按下的样子,并且可以在其中进行自已的单击事件的处理,使得它像一个按钮;

---- WM_NCLBUTTONUP:在标题栏上释放鼠标左键消息。我们可以截住它,在标题栏上画出按钮弹起的样子;

---- WM_NCLBUTTONDBLCLK:在标题栏上双击鼠标左键消息。我们可以截住它,当在按钮区域双击时,我们就该使其无效,从而避免窗体执行最大化和还原操作。

---- WM_NCRBUTTONDOWN:在标题栏上按下鼠标右键消息。我们可以截住它,当在按钮区域双击时,我们就该使其无效,从而避免弹出窗体按制菜单。

---- WM_NCMOUSEMOVE:在标题栏上移动鼠标消息。我们可以截住它,当鼠标移出按钮区域时,我们就必须画出按钮没有被按下,即凸起时的样子。

---- WM_NCACTIVATE:当标题栏在激活与非激活之间切换时收到该消息。我们可以截住它,当该窗口处理激活状态时,我们可以做一些事情,比如说将我们的标题栏按钮上的字体变灰或变黑来指示该窗口的当前状态。下面我没有加入该项功能,如果大家感兴趣的话,可以自己完成。

---- (大家从这里可以发现,标题栏的消息都是WM_NC开头的)

---- 实例文件可下载 5KB

---- 知道了原理之后,相信大家一定可以做出更漂亮的按钮来。


作者: 0758河台小赵    时间: 2004-9-5 13:58
用Delphi实现壁纸更换

  在Windows95/98中,都是使用注册表对系统数据进行管理,有关壁纸的设置数据保存在Hkey_Current_User\Control Panel\Desktop的Wallpaper和TileWallpaper 等键值中,只要成功修改了这两个键值,然后发消息给Windows即可更换壁纸。在本例的程序中,使用了一个Tform;两个Tspeedbutton(Speedbutton1用于接受用户的浏览命令,Speedbutton2用于接受用户的更换壁纸命令);一个Timage(用于显示图片)。另外,还用到一组文件控件:Tfilelistbox,Tdrivecombobox,Tdirectorylistbox,用于选择图片文件,可以设置FileListBox的mask属性,筛选显示在FileListBox 中的文件类型(如只显示.bmp文件)。下面的两个程序段是实现浏览图片和更换壁纸的关键代码。 Procedure Tform1.SpeedButton1Click(Sender:Tobject); Begin If (filelistbox1.FileName= ′′) Then {判断Filelistbox1中文件有没有被选中}   Messagedlg(′请先选择一幅位图′,mtInformation,[mbOK],0) Else Image1.Picture.LoadFormFile(Filelistbox1.FileName);{加载图片文件并显示} End; ProcedureTform1.SpeedButton2Click(Sender:TObject); Var Reg:Tregistry;{Tregistry 对象在Registry 单元中声明,需用Uses令引用Registry单元} } Begin If (Filelistbox1.FileName=′′) Then Messagedlg(′请先选择一幅位图′,mtinformation,[mbOK],0) Else Begin Reg:=Tregistry.Create;{创建Tregistry对象的实例} Reg.Rootkey:= Hkey_Current_User;{设置根键名称} Reg.OpenKey′Control Panel\Desktop′,False); {打开Control Panel\Desktop 路径对应的主键} Reg.WriteString (′TileWallPaper′, ′0′); Reg.WriteString ′Wallpaper′,fileli? stbox1.FileName);{向TileWallpaper 和Wallpaper串覆盖写入新值} Systemparametersinfo(SPI_SETDESKWallpaper,0,Nil,SPIF_SendChange);{向Windows发送消息,通知Windows更换壁纸} Reg.CloseKey;{将更改内容写入注册表并关闭} Reg.Free;{释放对象} End; End;   代码中用到的一些函数可以察看Delphi的联机帮助。需要注意的是:调用打开子键的函数OpenKey时,第二个参数一定要设为False。

本文出自:《电脑报》


作者: 0758河台小赵    时间: 2004-9-5 14:00
在Delphi中获取和修改文件的时间

  本文介绍了在Delphi中利用系统函数和Windows API函数调用来获取和修改文件的时间信息的方法。 熟悉Windows 95/98的朋友一定经常会用单击鼠标右键的方法来查看所选定的文件的属性信息。在属性菜单中会列出该文件的创建时间、修改时间和访问时间。这些信息常常是很有用的,它们的设置一般都是由操作系统(也就是由Dos/Windows等等)自动完成的,不会让用户轻易修改。 这里,我向大家介绍在Delphi中如何实现文件时间的获取和修改方法。Delphi中提供了很完备的Windows API函数的调用接口,可以方便的进行高级Windows编程。利用Delphi中的FindFirst函数可以得到一个文件的属性记录,该记录中的FindData域中就记载了详细的文件时间信息。然而遗憾的是,FindData中的时间信息是不能直接得到的。因此,本人编写了一个转换函数来完成文件时间格式的转换。下面给出了具体的实现方法,仅供参考: function CovFileDate(Fd:_FileTime):TDateTime; { 转换文件的时间格式 } var Tct:_SystemTime; Temp:_FileTime; begin FileTimeToLocalFileTime(Fd,Temp); FileTimeToSystemTime(Temp,Tct); CovFileDate:=SystemTimeToDateTime(Tct); end; 有了上面的函数支持,我们就可以获取一个文件的时间信息了。以下是一个简单的例子: procdeure GetFileTime(const Tf:string); { 获取文件时间,Tf表示目标文件路径和名称 } const Model='yyyy/mm/dd,hh:mm:ss'; { 设定时间格式 } var Tp:TSearchRec; { 申明Tp为一个查找记录 } T1,T2,T3:string; begin FindFirst(Tf,faAnyFile,Tp); { 查找目标文件 } T1:=FormatDateTime(Model, CovFileDate(Tp.FindData.ftCreationTime))); { 返回文件的创建时间 } T2:=FormatDateTime(Model, CovFileDate(Tp.FindData.ftLastWriteTime))); { 返回文件的修改时间 } T3:=FormatDateTime(Model,Now)); { 返回文件的当前访问时间 } FindClose(Tp); end; 设置文件的时间要复杂一些,这里介绍利用Delphi中的DataTimePicker组件来辅助完成这一复杂的操作。下面的例子利用了四个DataTimePicker组件来完成文件创建时间和修改时间的设置。注意:文件的访问时间用修改时间来代替。使用下面的例子时,请在您的Form上添加四个DataTimePicker组件。其中第一和第三个DataTimePicker组件中的Kind设置为dtkDate,第二个和第四个DataTimePicker组件中的Kind设置为dtkTime. procedure SetFileDateTime(const Tf:string); { 设置文件时间,Tf表示目标文件路径和名称 } var Dt1,Dt2:Integer; Fs:TFileStream; Fct,Flt:TFileTime; begin Dt1:=DateTimeToFileDate( Trunc(Form1.DateTimePicker1.Date) + Frac(Form1.DateTimePicker2.Time)); Dt2:=DateTimeToFileDate( Trunc(Form1.DateTimePicker3.Date) + Frac(Form1.DateTimePicker4.Time)); { 转换用户输入在DataTimePicker中的信息 } try FS := TFileStream.Create(Tf, fmOpenReadWrite); try if DosDateTimeToFileTime(LongRec(DT1).Hi, LongRec(DT1).Lo, Fct) and LocalFileTimeToFileTime(Fct, Fct) and DosDateTimeToFileTime(LongRec(DT2).Hi, LongRec(DT2).Lo, Flt) and LocalFileTimeToFileTime(Flt, Flt) then SetFileTime(FS.Handle, @Fct, @Flt, @Flt); { 设置文件时间属性 } finally FS.Free; end; except MessageDlg('日期修改操作失败!', mtError, [mbOk], 0); { 因为目标文件正在被使用等原因而导致失败 } end; end; 以上简单介绍了文件时间属性的修改方法,请注意:修改文件时间的范围是从公元1792年9月19日开始的,上限可以达到公元2999年或更高。另外,请不要将此技术用于破坏他人文件等非正当途径。


作者: 0758河台小赵    时间: 2004-9-5 14:01

[ 本文仅供参考 http://leonyxl.yeah.net/ ] 题目:任何动态改变/添加网络设置中的 TCP/IP 的 DNS 地址 例如,把 DNS Server的地址添加为192.0.0.1和192.1.1.0,可调用: SetTCPIPDNSAddresses('192.0.0.1 192.1.1.0') ; // 各地址之间用一个空格隔开 1. SetTCPIPDNSAddresses 定义如下: procedure SetTCPIPDNSAddresses( sIPs : string ); begin // // if using Windows NT // SaveStringToRegistry_LOCAL_MACHINE( 'SYSTEM\CurrentControlSet' + '\Services\Tcpip\Parameters', 'NameServer', sIPs ); // // if using Windows 95 // SaveStringToRegistry_LOCAL_MACHINE( 'SYSTEM\CurrentControlSet' + '\Services\VxD\MSTCP', 'NameServer', sIPs ); end; 2. 其中 SaveStringToRegistry_LOCAL_MACHINE 定义: uses Registry; procedure SaveStringToRegistry_LOCAL_MACHINE( sKey, sItem, sVal : string ); var reg : TRegIniFile; begin reg := TRegIniFile.Create( '' ); reg.RootKey := HKEY_LOCAL_MACHINE; reg.WriteString( sKey, sItem, sVal + #0 ); reg.Free; end; //====================================


作者: 0758河台小赵    时间: 2004-9-5 14:02
让彩色光标出现在Delphi程序中

 在Delphi中用Loadcursor()得到的光标只有黑白两色,怎样在程序中得到彩色光标呢?笔者尝试制作了以下程序:   方法一 用Loadcursorfromfile()从外部调入图标作为光标   Loadcursorfromfile()函数可以读*?CUR,*?ICO,*?ANI为后缀的文件作为光标,其中ICO为彩色图标格式(可用Image Editor制作),ANI为动画光标格式。以下为打开一图标作为光标的演示程序段,当光标移动到测试区域内光标会变成选定的图案;   {设:opendialog1:Topendialog;Bitbtn1:Tbitbtn}   procedure TForm1.BitBtn1Click(Sender:TObject);   var tt:pchar;size:integer;s:string;   begin   if opendialog1.Execute then   begin   size:=length(opendialog1.filename);   getmem(tt,size);   s:=opendialog1.filename;   strpcopy(tt,s);   screen.cursors[2]:=loadcursorfromfile(tt);   bf.cursor:=2;   freemem(tt,size);   end;   end;   方法二 从资源文件加载彩色光标   用方法一发送程序时必须包含*?CUR文件,因而从资源文件中加载彩色光标是更可行的方法。用图标存放彩色光标,使用时把图标存入临时文件,用Loadcursorfromfile()从临时文件读出彩色光标。   程序段:   procedure ZloadfromResourse(screenindex:integer;name:Pchar);   var td:ticon;   begin   try   td:=ticon.Create;   td.Handle:=LoadIcon(Hinstance,name);   td.SaveToFile(′temp.cur′);   screen.Cursors[screenindex]:=loadcursorfromfile(′temp.cur′);   deletefile(′temp.cur′);   finally   td.free;   end;   end;   此程序把名字为name的图标变为序号为screenindex的光标;   例:   ZloadfromResourse(2,′myicon′);   Form1.cursor:=2;   注意:′myicon′这个图标一定要在资源文件中,否则会出现异常。  


作者: 0758河台小赵    时间: 2004-9-5 14:03
面向组件的系统开发方法

应用软件的开发所面临的最大问题是变化的需求,这种变化可能来自下面几个方面: 用户对系统本身认识的变化。用户对系统本身的认识在系统设计初期和系统接近完成时期是完全不同的, 在系统规划初期,用户对系统只能提出大概的想象,这种想象在系统实际的开发过程中会不断的完整和深化。 实际应用环境的变化。在大型项目开发中表现得犹为明显,由于大型项目开发的时间较长,所涉及的子系统 和外界因素较多,在开发过程中实际的应用环境会有大量的更改,甚至可能根本不复存在。 开发技术和开发机构本身的变化。由于技术的发展和开发机构本身的调整可能会导致开发工具和开发方案的 修改。 对系统的扩展。在系统投入运行后,可能会有新的要求被提出,新的数据被处理。 不考虑那种导致系统重新规划和设计的需求更改,在那种情况下,唯一能做的就是完全开发新的系统。在基 于同样的设计框架的基础上,这种更改可以划分为下面的层次: 界面的变化:主要分为两个层次,首先是指界面的观感的变化,指界面的颜色、布局、字体等视觉效果。 其次,是指界面逻辑的变化,例如,操作的步骤,选择的顺序、界面元素的表示方式、界面隐喻等。 数据的变化:例如,增加新的数据项目、增加新的统计内容、将已有的处理逻辑扩展到新的数据对象上等。 处理的变化:例如,增加新的处理逻辑,更改业务逻辑的部分内容。 在变化的需求和变化的技术本身这个环境下,必须采用相对独立于需求,独立于软件的应用环境的开发方 法和模型。由于需求和数据的可变性,我们的焦点应该在系统的业务逻辑上,而对于特定业务领域,业务逻 辑应该是相对较为固定的。例如,对于机场信息管理系统,基本的业务类型应该包括: 基本信息的定义、录入、和修改 固定计划的生成 动态信息的获取和检索 资源使用的监视 资源的分配和回收 采用面向组件的开发方法,我们将应用软件的开发看成组件的开发和组件的组合,对应于应用的不同层次, 我们的组件层可以分为: 业务逻辑层:对应于非可视组件,独立于具体的数据源,抽象出基本的数据处理的逻辑,包括 数据获取和处理(从任意的数据库中取出需要的数据,并进行处理) 网络通讯(独立于位置的网络通讯) 系统功能和实现。 在该层次中,可以有不同的组件相互作用,协作完成任务。 界面模型层:对应于可视组件 按照习惯的界面模型,收集和制作与用户的操作习惯相一致的界面基本元素,如计划列表、资源查看列表等。


作者: 0758河台小赵    时间: 2004-9-5 14:03
COM/DCOM中如何传递数组:

因为COM/DCOM对象都不在Client程序运行的内存空间(内进程COM对象除外,即便如此,为了统一接口,内进程的COM也不得传递指针),而且在Win32中所有的程序都有自己独立的2GB的内存空间,程序与程序之间传递指针(内存地址)是毫无意义的,而数组、字符串等大量的数据在程序中都是分配一定的内存空间,然后用指针加内存偏移量来存取数据的,这时,如何在COM/DCOM对象中如何传递呢? 在Win32中引入了一新变量Variant,可以通过Variant传递数组。具体的实现方法,用Delphi实现为:

Server(COM/DCOM程序)端: procedure TTestDCOM.Send4(Size: Integer; D1: OleVariant); type TData=array [0..999] of Byte; Var Data:TData; i:Integer; begin for i:=0 to Size-1 do begin Data:=D1; end; end;

Cleint端:

Var D1:OleVariant; begin D1:=VarArrayCreate([0,99],varByte);

{ D1[1]:=45; .... //将值存入D1中

} S.Send4(99,D1); //S是TestDCOM对象 end;


作者: 0758河台小赵    时间: 2004-9-5 14:04
COM/DCOM的区别与联系

其实这种提法本身就及不科学,DCOM本身就是COM的一种表现形式,但是由于大家听见COM一般就把它当成在本地执行的COM,而DCOM当然就是分布的COM,在网络上的另一台计算机上执行.于是就诞生了这篇COM与DCOM的区别与联系. 区别: COM有两种存在形式,动态连接库和可执行程序,但DCOM必须是可执行程序.因为DCOM不可能在客户程序的内存空间运行,所以不能是动态连接库. COM(动态连接库形式)可以不用RPC通信,而DCOM必须使用RPC远程调用. COM(动态连接库形式)与客户共同存在于同一内存空间,调用速度快,DCOM的速度只有COM的万分之一. COM(动态连接库形式)的安全性不高,客户程序可以造成服务COM发生错误,DCOM安全性高,原因也是COM与客户程序共用内存空间造成的. COM程序配置简单,DCOM配置较复杂.毕竟DCOM牵涉到网络和安全性. 联系: 客户程序不必知道COM的存在形式,有统一的接口调用方式,客户程序甚至不知道COM对象的位置,可能在同一台计算机上,也可以在半个地球的另一面; 由于DCOM本身就是COM的一种存在形式,具有许多共同点.


作者: 0758河台小赵    时间: 2004-9-5 14:06
《 定制Delphi应用程序的系统菜单 》

  我们使用Delphi编制应用程序,编译运行后,在主界面的左上角出现一小图标,用鼠标单击此图标,会 出现一下拉式菜单,这就是系统菜单。系统菜单包括[还原]、[移动]、[大小]、[最小化]、[最大化]和[关 闭]六项。系统菜单是Delphi自动给每个应用程序加上的,不用特意设计。但在我们的应用程序中,有时为达 到一定目的,不希望在主界面上有主菜单存在,这时就可以在系统菜单上做点文章,将自己的菜单选项加入 到系统菜单中,以实现主界面的整洁。   下面是具体的实现方法。例如,我们要将[新建]和[保存]两选项加入到系统菜单中。先将一PopupMenu组 件加入表单,双击此组件进入PopupMenu设计器,设置[新建]和[保存]菜单项,后单击表单空白处,再选中 Objector Inspector的Event选项卡,双击OnCreate事件,进入单元窗口,编写如下代码:   Procedure Tform1,FormCreate(Sender:TObject);   Begin   With PopupMenul do   For I:=1 do   AppendMenu(getsystemmenu(self,handle,false),mf-popup,items,handle,pchar(items,caption));   在变量中添加:Var I:Integer;   编译运行后就会看到系统菜单中多了[新建]和[保存]两项。   下面我们来完成系统菜单项的响应。在Tform1的类定义中的Public部分插入如下代码:   Procedure WMSysCommand(var Msg:Tmessage);   message WM-SysCommand;   其中WMSysCommand为用户定义的响应函数。   Procedure WMSysCommand(var Msg:Tmessage);   Var   Item:Tmenuitem;   Begin   Inherited;   Item:=popupmenu1.Finditem(msg.wparam,fkcommand);   If not(item=nil) then   Item.click;   End   这样,系统菜单项就可以调用原有菜单项的click函数。


作者: 0758河台小赵    时间: 2004-9-5 14:10
《 用Delphi制作动态菜单 》

  所谓动态菜单是指菜单项随着程序的操作变化而变化。现在,我们用Delphi来实现这一功能,具体步骤如下:   1.首先,确定动态菜单的数据来源,即要确定动态菜单标题是来自Windows的系统注册表,还是来自一个数据库,或者是来自一个子目录,主要由程序的功能而定。这里假设主窗口名为MainForm,上面已有主菜单,其动态菜单的数据源是一个String(字符串)类型的变量,名称为SubMenuItemSource。   2.确定生成的动态菜单的功能,即定义动态菜单的OnClick()事件,例如,动态菜单标题来自一个磁盘文件名时,那么程序在响应OnClick()事件时,可能的操作是要打开选中的文件。因此,对菜单所在的主窗口模块的单元程序的数,据我们需要定义Type后添加一个自定义的事件MyClick()。   然后,需要编写如下MyClick()事件的具体内容:   procedure TMainForm.MyClick(Sender: TObject);//动态菜单OnClick事件响应   begin   Show.Message(TMenuItem(Sender).Caption);//显示选中的动态菜单标题,   end;   这里调用的ShowMessage标准例程(在Dialogs.pas中)显示TMenuItem(Sender).Caption,它就是选择的菜单项的Caption,类似用TMenuItem(Sender).Name则是选择菜单项的Name。   3.编写程序将动态菜单标题添加到指定的菜单顶下,并将其与OnClick()事件联系起来。将以下程序段添加到MainForm的OnCreate事件过程中,可在程序启动时完成动态菜单的动态生成:   procedure TMainForm.FormCreate(Sender: TObject);   var   addSubItem:TMenuItem;   i:Integer;   begin   for i:=0 to N do //N等于要添加的动态菜单数目,需事先定义为数值型变量,并赋值   begin   addSubItem:= TMenuItem.Create(Self);   addSubItem.Name := ′A′+IntToStr(i);   addSubItem.Caption := SubMenuItemSource; // 步骤1的SubMenuItemSource应先赋值   FileOpenItem.Add(addSubItem); //在名称为FileOpenItem的菜单项下添加子菜单   addSubItem.OnClick:=MyClick; // 步骤2的MyClick(),自定义菜单要响应的事件   end   end;
作者: 0758河台小赵    时间: 2004-9-5 14:13
开 发 基 于ORACLE7 数 据 库 的 管 理 信 息 系 统

---- 1 前 言

---- 开 发 高 水 平 的“ 管 理 信 息 系 统”, 选 择 性 能 优 越 的 数 据 库 是 最 重 要 的 一 环, 我 们 经 过 多 方 面 的 调 研 和 分 析, 选 择 了ORACLE7 数 据 库, 成 功 地 开 发 了 本 系 统。 实 践 证 明, 本 系 统 设 计 科 学、 合 理、 运 行 稳 定, 本 文 将 具 体 阐 述 一 下 系 统 中 应 用ORACLE7 数 据 库 的 方 法 和 技 术。

---- 2 系 统 的 开 发、 运 行 环 境

---- 本 系 统 在CLIENT/SERVER 结 构 上 运 行,SERVER 为CDC 4360 小 型 机, 和 快 速FDDI 环 网 相 接, 内 装 有UNIX 操 作 系 统 和ORACLE7 数 据 库, 系 统 总 体 网 络 协 议 为TCP/IP 。

---- CLIENT 端 为486 以 上 微 机,16M 以 上 内 存, 硬 盘 足 够 大, 通 过HUB、 路 由 器、MODEM 和SERVER 连 接。 开 发、 运 行 平 台 是WIN95, 安 装 了 网 络 软 件ONNET、ORACLE CDE 产 品 SQL*NET V2。 开 发 工 具 是POWERBULDER5.0( 以 下 简 称PB5)、VB4 等。

---- 3 ORACLE7 在 系 统 中 的 各 种 应 用

---- 3.1 一 般 性 的 数 据 管 理

---- 一 般 性 的 数 据 管 理 用 数 据 窗 口 管 理 最 方 便, 可 以 在 数 据 窗 口 中 进 行 表 的 增、 删、 改、 查 询 等 操 作, 下 边 是 一 些 具 体 例 子(PB5):

---- 3 .1 .1 连 通ORACLE 库, 并 将 数 据 装 入 数 据 窗 口:

dw_1.SetTransObject(sqlca) dw_1.Retrieve()

---- 3 .1 .2 增 加 一 条 记 录

dw_1.InsertRow(dw_1.GetRow( ) + 1)

---- 3 .1 .3 删 除 一 条 记 录( 当 前 记 录)

dw_1.DeleteRow(0)

---- 3 .1 .4 将 数 据 提 交 入 库( 存 盘)

dw_1.Update( ) commit;

---- 3 .1 .5 打 印 数 据 窗 口( 表) 中 的 数 据

dw_1.print()

---- 3 .2 文 字 类 数 据 管 理

---- 3 .2 .1 文 本 入 库 和 查 询

---- 文 本 入 库 和 查 询 可 采 用PB5 的MLE( 多 行 编 辑 器) 作 界 面, 编 辑 完 成 后 存 入ORACLE7 的LONG 字 段 中, 查 询 时 从LONG 字 段 中 取 出, 放 入MLE 中 查 询, 下 边 是 一 个 例 子:

//文本的预处理(以去除文本文件中的回车换行符为例说明)//将文件读入BLOB型变量text中fn=fileopen(txtname,streammode!)if fn< > -1 thenfileread(fn,text)fileclose(fn)// 并 转 换 为 文 本article=string(text)s=len(article)for v=1 to st=pos(article,char(13)+char(10),v) if t >0 thenarticle=replace(article,t,2,"")elseend ifnext mle_1.text=article//将处理后的文件c:\bb.txt存盘,文件中的回车换行符已全部去掉text1=blob(article)filname="c:\bb.txt"fn=fileopen(filname,streammode!,write!,lockwrite!,replace!) if fn< >-1 thenfilewrite(fn,text1) fileclose(fn) end if//文本入库nr1=blob(mle_1.text)updateblob gljwj set nr=:nr1 where bh=:pass_parm and zwrq=:fsj and wjbs=:fl5 using sqlca;commit;// 放 入MLE 中 查 询selectblob nr into :nr1 from gljwj where bh=:pass_parm and wjbs=:fl5 and zwrq=:fsj using sqlca;mle_1.text=blob(nr1)

---- 3 .2 .2 从 库 中 重 新 生 成 文 本 文 件filename.txt 并 存 盘

select nr into :filen from fwgs where bh=:bh1 and lwrq=:zwrq1 using sqlca;fname="c:\filename.txt"fh=fileopen(fname,streammode!,write!,lockwrite!,replace!) if fh< >-1 thenfilewrite(fh,filen) fileclose(fh)end if

---- 3 .3 处 理 图 象 文 件( 大 的 二 进 制 文 件)

---- 图 象 文 件( 一 般 为BMP 位 图 文 件) 是 二 进 制 文 件, 将 其 以 数 据 流 方 式 存 入ORACLE7 的LONG 字 段 中, 查 询 时 从LONG 字 段 中 取 出, 放 入 图 象 框( 如p_1) 中 查 询, 下 边 是 一 个 例 子:

// 将 图 象 文 件 读 入BLOB 型 变 量pict 中fn=fileopen(picname,streammode!)if fn< > -1 thenfileread(fn,pict)fileclose(fn)// 将 图 象 放 入 图 象 框p_1 内 查 看setpicture(p_1,pict)end if// 将 图 象 存 入 表pic 的LONG 字 段bmpt 中updateblob pic set bmpt=:pict ;commit;

---- 较 大 的 图 象 文 件 一 次 不 能 入 库, 可 采 取 分 割 图 形 的 方 式, 分 块 存 入, 因 为LONG 字 段 所 存 放 的 数 据 大 小 一 般 是 没 限 制 的( 可 存 放2G 的 内 容)。

---- 4 开 发 应 用 经 验

---- 4 .1 建 议CLIENT 端 通 过SQL*NET V2 进 行ORACLE 数 据 通 信( 不 用SQL*NET TCP V1 产 品)

---- 因 为 在ORACLE7 推 出 以 后,SQL*NET V1 就 没 有 做 一 些 改 进 工 作, 继 续 支 持 到ORACLE7.2, ORACLE7.3 以 后 的 产 品 将 不 支 持SQL*NET TCP V1, 所 以,ORACLE7 用 户 应 立 即 改 用SQL*NET V2, 不 然 会 影 响 到 库 的 运 行 稳 定 性。

---- ORACLE CDE2 和Developer 2000 提 供 了CLIENT 端ORACLE 产 品 的 安 装 程 序ORAINST.EXE, 运 行 该 文 件 来 安 装SQL*NET V2, 选 择 的 产 品 有:

a ORACLE TCP/IP ADPTER 2.1.4.1.3 b sql*net 2.1.4.1.4

---- 在WIN95 下, 网 络 软 件 产 品(Tcp/IP Vendor) 选 择Microsoft windows NT Tcp/IP 3.1 , 按 提 示 说 明 装 入 就 可 以 了, 另 外 还 要 做 以 下 工 作:

---- 将SERVER 上 的tnsnames.ora 文 件 复 制 到CLIENT 端c:\orawin\network\admin 目 录 下:

ora7=(DESCRIPTION= (ADDRESS= (PROTOCOL=TCP) (HOST=111.1.1.1) (PORT=1521) ) (CONNECT_DATA=(SID=ora7)))

---- 可 在SQLPLUS 下 键 入 连 接 命 令scott/tiger@ora7 测 试 连 接 情 况。

---- 首 先 要 作 好 这 三 件 工 作:

---- 4 .2 采 取 数 据 加 密 技 术

---- 对 用 户 来 说, 查 询 信 息 是 有 权 限 的, 若 想 查 询 某 项 保 密 数 据, 需 正 确 地 键 入 密 码, 才 能 查 到。 面 对 同 一 台 微 机, 谁 能 正 确 地 键 入 密 码, 谁 就 能 做 查 询, 该 系 统 通 过 自 定 义 一 些 复 杂 的 函 数 运 算 产 生 密 码, 从 表(TABLE) 中 找 不 到 密 码 数 据, 通 过 这 种 精 密 的 设 计 处 理, 达 到 了 数 据 保 密 要 求。 下 边 是 密 码 修 改 和 识 别 的 一 段 程 序(PB5) :

password=sle_1.texta8=pos(sle_1.text,"/")if a8 >=1 thenpassword=left(sle_1.text,a8 - 1)newpassword=mid(sle_1.text,a8+1,len(sle_1.text) - a8)end ifselect dwbm into :dm from dw where mm=:password;sle_1.text=""if sqlca.sqlcode< >0 then messagebox(" 警 告:"," 口 令 错 !")pw=pw+1if pw >=3 thenclose(w_bg_main)end ifelse mm=dm if a8 >=1 thena7=messagebox("提示信息","确定要修改口令吗(y/n)?",information!,YesNo!,2)if a7=1 thenselect dwbm into :a9 from dw where mm=:newpassword;if sqlca.sqlcode< >100 or newpassword="" thenmessagebox(" 提 示 信 息"," 新 口 令 错 !")goto end1 elseupdate dw set mm=:newpasswordwhere mm=:password;messagebox("请记住新口令",string(newpassword))commit;end ifend ifend if

---- 4 .3 用EXCEL 输 出 精 美 表 格

---- 用VC 或PB5 将ORACLE 库 中 的 数 据 生 成 文 本 或EXCEL 文 件, 再 通 过EXCEL 的 数 据 链 接, 将 对 应 数 据 调 入 事 先 定 义 好 的EXCEL 标 准 输 出 表 中, 按 用 户 的 要 求 输 出。

---- PB5 生 成EXCEL 格 式 文 件 的SCRIPT 语 句 举 例 如 下:

dw_1.SaveAs("c:\glxx.xls",excel!,true)

---- 4 .4 正 确 使 用 日 期 型 数 据

---- 在 库 操 作 过 程 中, 若 日 期 变 量 的 值 定 义 错 了, 将 提 示SQL 语 句 出 错 信 息, 错 误 现 象 非 常 隐 蔽, 不 好 察 觉, 这 是 编 程 过 程 中 的 常 见 错 误, 在 此 特 别 强 调 一 下。 举 一 个 例 子:

---- 若 日 期 数 据 为 常 量, 要 按 下 列 格 式 赋 值( 用 一update 语 句 说 明):

update tab set rq='1-Feb-96'; commit;

---- 5 结 束 语

---- 该 系 统 的 开 发 和 应 用, 使 我 们 更 加 体 会 到 了ORACLE 数 据 库 的 优 越 性, 本 系 统 的 开 发 成 功 与 此 是 分 不 开 的, 我 们 将 做 进 一 步 探 索, 用 先 进 的 开 发 工 具 和 升 级 的ORACLE8 开 发 面 向 网 络 的 和 多 媒 体 的“ 管 理 信 息 系 统”。

[此贴子已经被作者于2004-9-5 14:14:06编辑过]

作者: 0758河台小赵    时间: 2004-9-5 14:16
用Delphi 实 现 自 定 义 颜 色 对 话 框 及 其 构 件

---- 在 开 发 证 券 分 析 软 件 中, 经 常 要 绘 制 各 种 股 票 的 分 析 曲 线。 为 了 使 得 软 件 的 功 能 更 加 方 便. 灵 活, 用 户 希 望 能 够 按 照 自 己 的 喜 好 自 定 义 各 种 曲 线 的 颜 色。 在 W O R D97 的[ 格 式] 菜 单 下 的 字 体 对 话 框 中 有 类 似 的 功 能。 当 用 户 单 击 字 体 对 话 框 中 的 颜 色 下 拉 框 时, 各 种 颜 色 的 简 单 图 案 和 字 体 的 颜 色 名 称 一 起 显 示 出 来, 这 样 处 理 的 结 果 显 然 比 只 提 供 一 个 装 有 颜 色 名 称 的 下 拉 框 效 果 要 好 的 多。

---- 一、 自 定 义 颜 色 对 话 框 的 实 现

---- 在Delphi 中, 我 们 可 以 使 用TComboBox 实 现 类 似 的 功 能。 在TcomboBox 构 件 中 有 一 个Style 属 性, 决 定TcomboBox 的 显 示 属 性。 通 常 可 选 取csDropDown, csSimple, csDropDownList, csOwnerDrawFixed, csOwnerDrawVariable 等。 其 中 当 选 取csOwnerDrawFixed 时 表 示 创 建 一 个 自 画 下 拉 框, 下 拉 框 的 每 一 项 的 高 度 由ItemHeight 属 性 决 定。 并 且 必 须 在TcomboBox 的OnDrawItem 事 件 中 响 应 自 画 过 程。 OnDrawItem 的 定 义 为:

property OnDrawItem: TDrawItemEvent; TDrawItemEvent = procedure(Control: TWinControl; Index: Integer Rect: TRect; State: TOwnerDrawState) of object; 其 中 的 三 个 参 数 的 含 义 为: Control:   包 含 下 拉 框 的TComboBox Index: 自 画 的 下 拉 框 在TComboBox 的Items 属 性 中 的 索 引 号 Rect: 自 画 的 位 置

---- 因 此, 知 道 了 需 要 自 画 的 矩 形 的 位 置(Rect 参 数) 和 在TComboBox 中 的 索 引 号 (Index 参 数), 我 们 可 以 使 用TcomboBox 的Canvas 属 性 在 其 画 布 上 自 画。

---- 具 体 的 实 现 过 程 如 下:

---- 1 . 新 建 一 个 工 程 文 件, 设 置 其 默 认 窗 体 的 有 关 属 性 为:

---- Caption 自 定 义 下 拉 框

---- Name Form1

---- Position poScreenCenter

---- 2 . 在 窗 体 中 放 置 两 个TcomboBox 构 件, 设 置 其 属 性 如 下:

---- Name Style ItemHeight OnDrawItem

---- ColorCombo1 csOwnerDrawFixed 20 ColorComboDrawItem

---- ColorCombo2 csOwnerDrawFixed 30 ColorComboDrawItem

---- 3 . 双 击ColorCombo1 和ColorCombo2 的Items 属 性 旁 的 圆 点 按 纽, 在"String List Editor" 对 话 框 中 输 入

---- 黑 色

---- 蓝 色

---- 蓝 绿

---- 鲜 绿

---- 红 色

---- 黄 色

---- 等 各 种 颜 色 的 名 称

---- 4 . 在ColorCombo1 的OnDrawItem 事 件 中 加 入 如 下 代 码

procedure TForm1.ColorComboDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: OwnerDrawState); var TempColor :TColor; // 自 画 颜 色 TempBrushColor :TColor; // 临 时 颜 色 begin with (Control as TComboBox) do // 在Combo 的Canvas 上 自 画 begin TempBrushColor:=Canvas.Brush.Color; // 保 存 原 来 的 的 颜 色 Canvas.FillRect(Rect); case Index of // 根 据Index 的 不 同, 定 义 不 同 自 画 的 颜 色 0: // 黑 色 TempColor:=clBlack; 1: // 蓝 色 TempColor:=clBlue; 2: // 蓝 绿 TempColor:=clAqua; 3: // 鲜 绿 TempColor:=clLime; 4: // 红 色 TempColor:=clRed; 5: // 黄 色                            TempColor:=clyellow; // 可 以 在 此 加 入 对 其 它 颜 色 的 响 应 end; Canvas.Brush.Color:=TempColor; // 自 画 颜 色 矩 形 Canvas.Rectangle(Rect.Left+4, Rect.Top+1, (Rect.Right+Rect.Left) div 3, Rect.Bottom-1); Canvas.Brush.Color:=TempBrushColor; // 显 示 与 颜 色 对 应 的 字 符 串 Canvas.TextOut((Rect.Left+Rect.Right) div 2, Rect.Top+1, Items[Index]); end; end;

---- 5 . 保 存, 运 行 文 件, 我 们 可 以 看 到 和 W O R D 中 颜 色 下 拉 框 相 同 的 效 果 ---- 有 兴 趣 的 读 者, 可 以 在 文 中 所 示 的 位 置 加 入 对 其 它 颜 色 处 理。

---- 以 上 程 序 在Delphi 3.0,4.0 上 通 过。

---- 二、 自 定 义 颜 色 对 话 框 构 件 的 编 写

---- 对 许 多Delphi 程 序 员 来 说, 如 何 编 写 自 己 的Delphi 构 件 还 是 比 较 陌 生 的, Delphi 构 件 实 际 上 是 从Tcomponent 类 继 承 发 展 而 来, 编 写 构 件 实 际 就 是 编 写 特 殊 的 类。 下 面 我 们 就 以 自 定 义 颜 色 对 话 框 为 例 介 绍 构 件 的 编 写。

---- 下 面TColorComboBox 是 从TcomboBox 类 继 承 来 的, 当 点 击 右 边 的 下 拉 箭 头 时 弹 出 和 下 拉items 对 应 的 各 种 颜 色 自 画 框。

---- 1. 选 中Component 菜 单 项 中 的New Component 选 项。 在Ancestor Type 框 中 选TcomboBox, 在Class Name 框 中 填 入TColorComboBox, 在Palette Page 框 中 选Samples, 在Unit File Name 框 中 填 入 ColorComboBox.pas, 然 后 点 击OK 按 钮。

---- 2. 选 中Component 菜 单 项 中 的Install Component 选 项, 点 击Into new package, 在package name 框 中 写 入 路 径 和ColorComboDpk.dpk, 点 击ok, 生 成ColorComboDpk.bpl 文 件。

---- 3. 使 用Tools 菜 单 中 的Image Editor 来 创 建 编 辑 文 件ColorComBox.dcr, 为TColorComboBox 类 建 立 位 图。

---- 4. 在Create 中 加 入 对 字 体 大 小 高 度 的 规 定 及 对 控 件 的Style 属 性( 设 成 csOwnerDrawFixed) 的 规 定, 在Create 后 执 行 的CreateWnd 中 初 始 化 颜 色 的items, 如 果 不 需 要 那 么 多 颜 色 项, 可 以 以 后 在 生 成 控 件 的items 属 性 中 直 接 删 除 不 需 要 的 颜 色。

---- 5. 在DrawItem 事 件 中 加 入 颜 色 自 画 程 序, 此 事 件 在On DrawItem 之 前 发 生。

---- 实 现 程 序 如 下:

unit ColorComboBox;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;type TColorComboBox = class(TComboBox) private { Private declarations } FOnDrawItem : TDrawItemEvent; procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);override; protected { Protected declarations } public { Public declarations } constructor Create(AOwner : TComponent);override; procedure CreateWnd;override; published { Published declarations } property OnDrawItem : TDrawItemEvent Read FOnDrawItem write FOnDrawItem; end;procedure Register;implementationprocedure Register; // 注 册 构 件begin RegisterComponents('Samples', [TColorComboBox]);end;constructor TColorComboBox.Create(AOwner : TComponent); // 构 件 的 初 始 化 begin inherited Create(AOwner); Style := csOwnerDrawFixed; // 构 件 的 初 始 类 型 ItemHeight := 20; Font.Size := 10;end;procedure TColorComboBox.CreateWnd; // 颜 色 构 件 的Items 属 性 初 始 化begin inherited CreateWnd; Items.Clear; Items.Add(' 黑 色'); Items.Add(' 蓝 色'); Items.Add(' 蓝 绿'); Items.Add(' 鲜 绿'); Items.Add(' 粉 红'); Items.Add(' 红 色'); Items.Add(' 黄 色'); Items.Add(' 白 色'); Items.Add(' 深 蓝'); Items.Add(' 青 色'); Items.Add(' 绿 色'); Items.Add(' 紫 色'); Items.Add(' 深 红'); Items.Add(' 深 黄'); Items.Add(' 深 灰'); Items.Add(' 银 色');

---- // 若 不 需 要 这 么 多 颜 色 可 在 构 件 的items 属 性 中 删 除 不 需 要 的 颜 色

---- end;

---- // 重 载DrawItem 过 程

procedure TColorComboBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);var TempColor :TColor; // 自 画 颜 色 TempBrushColor :TColor; // 临 时 颜 色begin // 本 构 件 的 默 认 自 画 设 置 TempBrushColor:=Canvas.Brush.Color; // 保 存 原 来 的 的 颜 色 Canvas.FillRect(Rect); if Items[index]=' 黑 色' then TempColor := clBlack else if Items[index]=' 蓝 色' then TempColor := clBlue else if Items[index]=' 蓝 绿' then TempColor := clAqua else if Items[index]=' 鲜 绿' then TempColor := clLime else if Items[index]=' 粉 红' then TempColor := clFuchsia else if Items[index]=' 红 色' then TempColor := clRed else if Items[index]=' 黄 色' then TempColor := clYellow else if Items[index]=' 白 色' then TempColor := clWhite else if Items[index]=' 深 蓝' then TempColor := clNavy else if Items[index]=' 青 色' then TempColor := clTeal else if Items[index]=' 绿 色' then TempColor := clGreen else if Items[index]=' 紫 色' then TempColor := clPurple else if Items[index]=' 深 红' then TempColor := clMaroon else if Items[index]=' 深 黄' then TempColor := clOlive else if Items[index]= ' 深 灰' then TempColor := clGray else if Items[index]=' 银 色' then else TempColor := clSilver; Canvas.Brush.Color:=TempColor; // 自 画 颜 色 矩 形 Canvas.Rectangle(Rect.Left+4, Rect.Top+1, (Rect.Right+Rect.Left) div 3, Rect.Bottom-1); Canvas.Brush.Color:=TempBrushColor; // 显 示 与 颜 色 对 应 的 字 符 串 Canvas.TextOut((Rect.Left+Rect.Right) div 2, Rect.Top+1, Items[Index]); end;end.

---- 此 控 件 可 以 在 所 有 需 要 颜 色 选 项 的 程 序 中 使 用 而 且 非 常 方 便 和 美 观, 并 且 使 编 程 节 省 很 多 时 间, 增 加 了 程 序 可 靠 性 和 可 读 性。

---- 三、 自 定 义 颜 色 对 话 框 构 件 的 使 用

---- 当 注 册 完 自 定 义 颜 色 构 件 后, 可 以 从Delphi 构 件 模 板 的Sample 页 中 选 择 自 定 义 颜 色 构 件, 和 使 用Delphi 本 身 构 件 没 有 区 别。


作者: 0758河台小赵    时间: 2004-9-5 14:18
[本文摘自BBS, 不能保证绝对正确, 仅供参考] 题目: 如何把文件删除到回收站中 例子如下:// Delphi program del; uses ShellApi; { 利用ShellApi中: function SHFileOperation(const lpFileOp: TSHFileOpStruct): Integer; stdcall; } Var T:TSHFileOpStruct; P:String; begin P:='C:\Windows\System\EL_CONTROL.CPL'; With T do Begin Wnd:=0; wFunc:=FO_DELETE; pFrom:=Pchar(P); fFlags:=FOF_ALLOWUNDO End; SHFileOperation(T); End. 注意: 1. 给出文件的绝对路径名,否则可能不能恢复; 2. MS的文档说对于多个文件,每个文件名必须被#)字符分隔,而整个字符串必须用两个#0结束。
作者: 0758河台小赵    时间: 2004-9-5 14:21
用修改文件时间的方法来加密文件

---- [摘要]:本文介绍了在Delphi中利用系统函数和Windows API函数配合Delphi中的DataTimePicker组件来获取和修改文件的时间信息的方法,以达到软件信息的简单加密。

---- 谈到文件加密已经有很多方法了,但传统的文件型加密方法都存在一些不足。例如:让人头痛的密码技术、复杂的全文加/解密算法、会产生垃圾文件的暗贴技术等等。这里我向大家介绍一种新的文件加密思路。在Win 95/98中选定一个文件后单激鼠标右键可以查看文件的属性。其中会列出该文件的创建时间、修改时间和访问时间。这些信息的设置一般都是由操作系统(也就是由Dos/Windows等等)自动完成的,不会让用户轻易修改。利用这一特性就可以实现很隐蔽的加密技术。

---- 加密原理:用特定的时间信息替换原来的文件时间信息。

---- 解密原理:获取已加密文件的时间信息与特定时间信息比较,如相同则说明该文件是合法的,如不同则说明该文件属于过期或盗版软件。

---- 以上简单介绍了文件时间属性的修改方法,利用这种方法可以起到简单的软件加密。例如:假设某个软件或游戏执行完后存储了一些存档文件,则操作系统会自动设置该文件的修改时间,那么稍有经验的用户就可以用Windows中的“查找文件”功能找到最后被修改的文件。如果该文件是记录密码或用户信息的文件(实际上很多情况都是这样),后果简直不堪设想。另外,如果适当设置文件的创建、修改时间和访问时间,例如:保持三者之间为一定的时间间隔就可以作为加密的一种好手段。运行主软件时只要动态的检测一下文件时间是否满足特定的要求就知道该软件是否过期或属于盗版软件,从而达到加密和保护软件的目的,并且不会产生垃圾文件。

---- 以下介绍具体实现方法:

---- 利用Delphi中的FindFirst函数可以得到一个文件的属性记录,该记录中的FindData域中就记载了详细的文件时间信息。FindData中的时间信息不能直接得到利用本文源程序中的CovFileDate函数可以完成文件时间格式的转换。设置文件的时间要复杂一些,利用Delphi中的DataTimePicker组件来辅助完成这一复杂的操作。可以利用四个DataTimePicker组件来完成文件创建时间和修改时间的设置。注意:文件的访问时间用修改时间来代替。使用下面的例子时,请在您的Form上添加四个DataTimePicker组件。其中第一和第三个DataTimePicker组件中的Kind设置为dtkDate,第二个和第四个DataTimePicker组件中的Kind设置为dtkTime,DateMode设置为dmUpDown。

---- 备注:修改文件时间的范围是从公元1792年9月19日开始的,上限可以达到公元2999年或更高。

另外,请不要将此技术用于破坏他人文件等非正当途径。


作者: 0758河台小赵    时间: 2004-9-5 14:22
资 源 文 件 在DELPHI 中 的 使 用

资 源 是 存 放 在 扩 展 名.RES 的 文 件 里 的 二 进 制 数 据 结 构, 在DELPHI 中 资 源 文 件 可 以 使 用 图 象 编 辑 器 来 制 作(IMAGE EDITOR), 或 者 使 用 其 他 的 工 具。 如:BORLAND 公 司 提 供 的RAD PACK FOR DELPHI 中 的RESOURCE WORKSHOP 来 创 建。 资 源 文 件 中 通 常 存 放 的 是 应 用 程 序 可 以 随 时 存 取 的 一 些 对 象, 包 括:ICON、CURSOR、BITMAP、FONT 等 近 十 种。 大 部 分 的 资 源 在 通 常 的 情 况 下 可 以 保 留 在 磁 盘 当 中, 直 到 程 序 需 要 使 用 它 们 时 才 将 其 调 入, 可 以 大 大 的 节 省 内 存 资 源, 同 样, 资 源 文 件 也 是 可 以 共 享 的, 即: 多 个 程 序 可 以 共 享 一 个 资 源 文 件, 进 而 减 少 了 在 应 用 程 序 之 间 代 码 重 复 的 现 象, 使 程 序 的 代 码 得 到 很 大 的 优 化, 因 此 在 应 用 程 序 中 使 用 资 源 文 件 有 独 立 制 作、 方 便、 随 时 修 改 而 不 需 要 对 应 用 程 序 代 码 做 任 何 修 改 的 好 处。

一 般 来 说, 一 个 应 用 程 序 的 所 有 资 源 都 存 放 在 一 个RES 文 件 里, 然 后 在DELPHI 进 行 编 译 的 阶 段 将 资 源 文 件 的 内 容 与 最 终 的EXE 文 件 合 并 在 一 起, 因 此 编 译 后 的RES 文 件 并 没 有 什 么 作 用, 仅 仅 提 供 用 来 查 阅 使 用, 在 分 发 应 用 时 不 必 把RES 文 件 分 发 给 最 终 用 户。 当 然, 不 同 的 资 源 可 以 分 别 放 在 不 同 的 资 源 文 件 当 中, 而 且 资 源 文 件 越 小 调 入 内 存 的 速 度 越 快。 在 这 里 还 要 说 明 的 一 点 是: 在 修 改 了 原 来 的 资 源 文 件 之 后, 在 原 来 编 译 的EXE 文 件 中 加 入 的 资 源 不 会 随 之 而 更 新, 只 有 在 重 新 进 行 编 译 以 后, 才 能 将 新 的 资 源 加 入 到 新 的EXE 文 件 当 中 去。

下 面 我 们 通 过 两 个 例 子 来 说 明 在DELPHI 中 如 何 使 用 资 源 文 件( 在 这 里 我 们 不 讲 述 资 源 文 件 的 制 作 方 法)。

一、 如 何 在DELPHI 中 使 用 定 制 的 光 标。

在 使 用DELPHI 进 行 编 程 时, 有 一 个 很 重 要 的 对 象 ─ ─TSCREEN, 它 是 用 来 管 理 和 操 纵 运 行 时 期 屏 幕 的 不 可 视 构 件。 它 的CURSOR 属 性 是 用 来 指 定 各 个 不 同 的 构 件 光 标 形 状, 声 名 为:

PROPERTY CURSORS[INDEX:INTEGER]:HCURSOR;

这 个 只 读 的 特 性 返 回 应 用 程 序 支 持 的 光 标 组 成 的 一 个HCURSOR 类 型 的 数 组, 它 存 储 了 屏 幕 上 所 有 的 鼠 标 光 标 的 身 份 代 码(HCURSOR 就 是 光 标 的HANDLE 句 柄), 数 组 下 标 从0 开 始, 在DELPHI 预 定 义 了 一 些 代 表 不 同 光 标 的 常 量, 它 的 值 是 从0 到-17, 您 可 以 直 接 指 定 程 序 使 用 的 光 标。 如:

FORM1.CURSOR:=-3 表 示FORM1 采 用 的 光 标 是CRCROSS( 十 字)。

大 家 可 能 都 会 发 现 构 件 的CURSOR 的 属 性 最 多 提 供 十 八 种 常 用 的CURSOR 值, 这 在 很 多 的 情 况 下 是 不 够 的, 如: 当 光 标 进 入 一 个PANEL 面 板 时 光 标 的 形 状 为 一 只 手, 那 么PANEL 的CURSOR 就 不 能 满 足 这 种 要 求, 这 时 就 需 要 我 们 自 定 义 一 个 手 的 光 标 并 将 其 赋 给PANEL 的CURSOR 属 性。 如 何 实 现 则 可 以 按 以 下 步 骤 进 行: 使 用 资 源 文 件 编 辑 器(IMAGE EDITOR 或 者RESOURCE WORKSHOP) 编 写 资 源 文 件。 定 义 一 个 光 标 常 量, 注 意 这 个 常 量 不 能 与DELPHI 中 提 供 的 光 标 常 量 相 冲 突。 在FORMCREATE 事 件 中 使 用WINDOWS API 当 中 的LOADCURSOR 函 数 来 载 入 自 定 义 的CURSOR。 在 程 序 中 将 自 定 义 的CURSOR 分 配 给PANEL 的CURSOR 属 性。

下 面 说 明 如 何 将 自 定 义 的 一 只 手 的 鼠 标 光 标 赋 给PANEL1 的CURSOR 属 性。 首 先 使 用IMAGE EDITOR 建 立 一 个HAND.RES 的 文 件。 之 后 按 如 下 书 写 程 序 代 码:

implementation{$R *.DFM}constCrhand=2;procedure TForm1.FormCreate(Sender: TObject);beginscreen.cursors[crhand]:=loadcursor(Hinstance,'hand');panel1.cursor:=crhand;end;

除 了 编 写 上 面 的 代 码 以 外, 我 们 还 需 要 做 的 一 项 工 作 是 将 资 源 文 件 加 入 到 项 目 文 件 当 中 去, 编 译 指 令 中 的{$R filename} 伪 指 令 让 我 们 来 增 加 资 源 文 件, 让 我 们 来 看 一 看 项 目 文 件 的 代 码。

program PCUR;uses Forms, HAND in 'HAND.pas' {Form1};

{$R *.RES}// 这 里 的* 意 义 为 在 程 序 编 译 以 后 会 产 生 一 个 与 项 目 文 件 同 名 的 资 源 文 件, 在 这 里 为PCUR.RES 文 件, 这 部 分 是 自 动 产 生 的。

{$R hand.res}// 这 部 分 是 我 们 自 己 加 入 的 自 定 义 资 源 文 件, 这 两 个 资 源 文 件(HAND.RES 和//PCUR.RES 中 的 资 源 都 会 附 加 在 可 执 行 文 件PCUR.EXE 的 后 面。

begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run;end.二、 资 源 文 件 在 编 写 动 画 程 序 中 的 应 用

上 面 的 例 子 使 用 的 是 在 资 源 文 件 中 存 储 的CURSOR 资 源 , 在 下 面 的 例 子 中 我 们 将 使 用 的 是 在 资 源 文 件 中 提 供 的ICON 资 源 来 编 写 一 个 小 小 的 动 画 程 序。 在 这 里 动 画 的 产 生 是 利 用 定 时 器 在 一 定 的 时 间 间 隔 内 产 生TIMER 事 件 将 存 储 在 资 源 文 件 中 的ICON 依 次 的 绘 制 在FORM 的 同 一 处 而 产 生 的。 这 时 要 用 到 画 布CANVAS 的DRAW 方 法, 其 声 明 如 下:

procedure Draw(X, Y: Integer; Graphic: TGraphic);

在 这 个 方 法 当 中 的 参 数GRAPHIC 可 以 为:BITMAPS、ICONS、METAFILES。 具 体 的 实 现 方 法 为: 建 立DEMO.RES 文 件, 其 中 含 有 名 为ICON1 —ICON6 的ICON。 并 将DEMO.RES 加 到 项 目 原 代 码 中 去( 如: 上 面 例 子 的 方 法)。

动 画 程 序 的 具 体 代 码 如 下:

unit donghua;interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls;type TForm1 = class(TForm) Image1: TImage; Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); private { Private declarations } public { Public declarations } end;var Form1: TForm1;implementationvarwicon:array[0..5]of Ticon; // 建 立TICON 类 型 的 数 组 存 储ICON 文 件idx:integer;{$R *.DFM}procedure TForm1.FormCreate(Sender: TObject);variconname:string;piconame:pchar;beginpiconame:=stralloc(7); // 建 立PCHAR 类 型 的 字 符 串for idx:=0 to 5 dobeginwicon[idx]:=ticon.create;// 建 立TICON 型 对 象iconname:='icon'+inttostr(idx);strpcopy(piconame,iconname); // 将STRING 类 型 转 换 成PCHAR 类 型wicon[idx].handle:=loadicon(hinstance,piconame); // 调 用WINDOWS API 中 的LOADICON 函 数 // 载 入 资 源 中 的ICONend;strdispose(piconame);//PCHAR 类 型 的 删 除form1.canvas.draw(3,3,wicon[1]); // 调 用DRAW 的 方 法 在FORM 上 画 出ICON1idx:=1;form1.setbounds(0,0,100,100); // 固 定FORM 的 大 小 和 位 置end;procedure TForm1.Timer1Timer(Sender: TObject); // 形 成 动 画 的 定 时 器 事 件beginidx:=idx+1;if idx=6then idx:=1;form1.canvas.draw(3,3,wicon[0]);form1.canvas.draw(3,3,wicon[idx]);end;end.

以 上 可 以 作 为 一 个 通 用 的 动 画 程 序, 我 们 只 需 要 修 改 不 同 的ICON 以 及 增 加IDX 的 大 小 就 可 以 编 出 不 同 的 动 画 应 用( 同 样 在 资 源 中 可 以 有 其 他 形 式 的 图 形 如:BITMAPS 这 时 需 要 动 态 创 建 的 是TBITMAPS 对 象 而 不 是TICON 对 象)。 在 两 个 例 子 中 我 们 都 用 到 了WINDOWS API 函 数, 这 些 函 数 在WINDOWS 单 元 中 均 有 说 明 在 这 里 不 加 赘 述。 以 上 的 两 个 例 子 只 是 资 源 文 件 的 一 点 点 应 用, 要 真 正 的 掌 握 资 源 文 件 在 程 序 设 计 中 的 强 大 作 用, 还 要 靠 自 己 在 实 践 中 不 断 的 总 结。

以 上 程 序 在WINDOWS95 下 的DELPHI2.0 中 编 译 通 过。


作者: 0758河台小赵    时间: 2004-9-5 14:23
控 制 系 统 菜 单

---- WINDOWS 附 带 的 时 钟 程 序 有 这 样 一 个 特 点: 它 的"Always on top" 选 项 是 加 在 系 统 菜 单 中 的, 这 一 技 巧 为 该 程 序 增 色 不 少, 同 时 也 增 加 了 其 神 秘 感。 我 们 在 程 序 设 计 时 能 否 把 自 己 的 菜 单 项 加 入 系 统 菜 单 呢 ? 回 答 是 肯 定 的, 笔 者 用Delphi 方 便 的 实 现 了 这 一 功 能。

---- 为 实 现 这 一 功 能, 需 要 解 决 两 个 问 题: ①、 如 何 把 用 户 菜 单 项 加 入 系 统 菜 单, ②、 如 何 才 能 响 应 这 一 菜 单 项。

---- 要 解 决 第 一 个 问 题, 就 需 要 获 取 系 统 菜 单 的 句 柄, 这 一 点 可 用 API 函 数 getsystemmenu() 来 获 取(getmenu() 只 能 获 取 用 户 菜 单 句 柄), 有 了 系 统 菜 单 句 柄, 便 可 以 用 API 函 数appendmenu() 向 系 统 菜 单 中 加 入 用 户 菜 单 选 项 了。

---- 要 解 决 第 二 个 问 题, 需 要 重 载 WM_SYSCOMMAND 或WM_MENUSELECT 消 息。 我 们 知 道, 当 用 户 从 菜 单 中 选 一 项 时, 系 统 便 会 发 出 WM_COMMMAND 消 息, 而 对 于 系 统 菜 单, 则 会 发 出 WM_SYSCOMMAND 消 息, 重 载 这 个 消 息, 并 判 断 选 中 菜 单 的 ID 值 是 否 为 用 户 设 定 值 便 可 以 了。Delphi 为 我 们 提 供 了 这 方 面 的 机 制, 使 我 们 能 方 便 的 实 现 这 一 功 能。 当 然, 为 实 现 这 一 功 能 我 们 还 可 以 利 用 子 类 或 为 系 统 加 消 息 钩 子 的 方 法 来 解 决。

---- 为 了 便 于 实 现, 在 这 里, 我 们 采 用 重 载 WM_SYSCOMMAND 消 息 和 填 写 WM_MENUSELECT 消 息 结 构 的 方 法 来 实 现 这 一 功 能。

---- 下 面 为 笔 者 为 实 现 这 一 功 能 而 开 发 的 实 例。

---- 程 序 在Delphi ver 1.0 下 调 试 通 过。

program Psysmenu;uses Forms, Sysmenu in '\SYSMENU.PAS' {Form1};{$R *.RES}begin Application.CreateForm(TForm1, Form1); Application.Run;end.unit Sysmenu;interfaceuses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,Forms, Dialogs;type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); private procedure user_sysmenu(var msg:twmmenuselect); message wm_syscommand; public { Public declarations } end;var Form1: TForm1;implementation{$R *.DFM}procedure TForm1.user_sysmenu(var msg:TWMMENUSELECT);begin if msg.iditem=100 then showmessage(' 响应系统菜单!') { 也 可 以setwindowpos()来实现处于最前端功能} else inherited; { 作缺省处理,必须调用这一过程}end;procedure TForm1.FormCreate(Sender: TObject); var hmenu:integer;begin hmenu:=getsystemmenu(handle,false); {获取系统菜单句柄} appendmenu(hmenu,MF_SEPARATOR,0,nil); appendmenu(hmenu,MF_STRING,100,'加入系统菜单'); {加入用户菜单}end;end.
作者: 0758河台小赵    时间: 2004-9-5 14:23
用Dephi 程 序 维 护Paradox 数 据 表 的 索 引

---- 在 数 据 库 编 程 中, 索 引 文 件 对 于 改 善 数 据 查 询 速 度 有 着 举 足 轻 重 的 作 用, 充 分 使 用 索 引 文 件 可 以 极 大 改 善 数 据 库 应 用 程 序 的 性 能, 这 一 点 恐 怕 是 难 以 否 认 的.

---- 在 应 用 过 程 中, 用 户 的 查 询 条 件 可 能 是 多 种 多 样 的, 如 果 能 根 据 用 户 查 询 建 立 和 选 择 索 引, 对 于 保 证 应 用 程 序 的 性 能, 无 疑 是 很 有 帮 助 的.

---- 另 外, 由 于 停 电 等 意 外 事 故 很 容 易 造 成 数 据 库 中 的 索 引 文 件 未 及 时 更 新 甚 至 于 损 坏, 此 时 如 果 应 用 程 序 再 出 几 个 错 误 信 息, 无 疑 将 使 用 户 的 处 境 雪 上 加 霜.

---- 因 而, 动 态 维 护 数 据 库 索 引 文 件, 将 使 你 的 数 据 库 应 用 程 序 更 有 稳 定 性 和 可 靠 性. 笔 者 将 以Delphi 编 程 中 常 用 的Paradox 数 据 库 为 例, 介 绍 数 据 库 索 引 文 件 的 动 态 维 护.

---- Paradox 数 据 表 索 引 分 为 主 索 引(Primary Index) 即 关 键 字(Primary Key) 索 引 和 次 索 引(Secondary Index), 其 中 主 索 引 对 应.PX 文 件, 次 索 引 对 应.XG* 和.YG* 文 件.

一. 创 建 表 索 引

---- (1) 用Table.AddIndex 来 实 现 ---- 方 法:AddIndex( IndexName,FieldNames,Options ) ---- 其 中:( 详 见Delphi 帮 助) ---- IndexName: 索 引 名 称, 仅 在 指 定 次 索 引 时 有 作 用. ---- FieldNames: 索 引 域, 可 指 定 多 个 域, 各 域 之 间 用 分 号 隔 开, 如'Field1;Field2;Field3' ---- Options: 索 引 选 项, 可 为[ixPrimary, ixUnique, ixDescending, ixCaseInsensitive, ixExpression] ---- 其 中: ---- ixPrimary : 建 立 的 索 引 为 主 索 引( 不 适 用 于dBase 数 据 表). ---- ixUnique : 不 允 许 重 复 值 的 索 引. ---- ixDescending: 按 降 序 索 引. ---- ixCaseInsensitive: 索 引 排 序 时 按 忽 略 大 小 写( 不 适 用 于dBase 数 据 表). ---- ixExpression: 建 立 表 达 式 索 引( 适 用 于Delphi3.0, 仅 适 用 于dBase 数 据 表). ---- ixNonMaintained: 是 否 不 需 要BDE 自 动 维 护( 适 用 于Delphi1.0).

---- 下 面 是 一 个 例 子:

---- 假 设 有 一 个 存 放 通 讯 录 数 据 表MyComm.DB( 类 型 为Paradox) 存 放 于 本 地 目 录d:\mynote 下, 现 建 立 一 个 主 索 引( 索 引 域 为 编 号ID) 和 一 个 次 索 引( 索 引 域 为 编 号ID 和 姓 名Name, 索 引 名 称 为NameIndex).

with table1 do begin close; Exclusive := true; DatabaseName := 'd:\MyNote'; TableName := 'MyComm.DB'; Open; {建立主索引 } AddIndex('','ID',[ixPrimary]); {建立次索引 } AddIndex('NameIndex','ID;Name',[]); close; end; (2)用SQL来实现 对Paradox数据表来说,用SQL只能建立次索引. 在SQL语法中,用来建立索引的语句是: Create Index IndexName On TableName (IndexField1,IndexField2,..) 其中: IndexName为一个次索引的名称,如MySecIndex1等. TableName为对应数据表的名称,如MyTable等. TableName后面为索引域列表,所有索引域有圆括号括起来, 各索引域之间用逗号隔开.

 

---- 下 面 是 一 个 例 子:

---- 假 设 有 一 个 存 放 通 讯 录 数 据 表MyComm.DB( 类 型 为Paradox) 存 放 于 本 地 目 录

---- d:\mynote 下, 现 建 立 一 个 次 索 引( 索 引 域 为 编 号ID 和 姓 名Name, 索 引 名 称 为NameIndex).

with query1 do begin close; DatabaseName := 'd:\MyNote';{建立次索引NameIndex} sql.clear; sql.add( 'Create Index NameIndex On MyComm(ID,Name)' ); execSql; end;

 

二. 删 除 表 索 引

---- (1) 用Table.DeleteIndex 来 实 现 ---- DeleteIndex 只 能 删 除 次 索 引 名 称. ---- 方 法:DeleteIndex( IndexName ) ---- 其 中:( 详 见Delphi 帮 助) ---- IndexName: 次 索 引 名 称.

---- 下 面 是 一 个 例 子:

---- 假 设 有 一 个 存 放 通 讯 录 数 据 表MyComm.DB( 类 型 为Paradox) 存 放 于 本 地 目 录

---- d:\mynote 下, 现 有 一 个 次 索 引( 索 引 域 为 编 号ID 和 姓 名Name, 索 引 名 称 为NameIndex), 将 删 除 之.

with table1 do begin close; Exclusive := true; DatabaseName := 'd:\MyNote'; TableName := 'MyComm.DB'; Open; {删除次索引} DeleteIndex('NameIndex'); close; end;

 

---- (2) 用SQL 来 实 现 ---- 在SQL 语 法 中, 用 来 删 除 索 引 的 语 句 是: ---- Drop Index TableName.IndexName ---- 要 删 除 次 索 引 时,IndexName 为 一 个 次 索 引 的 名 称, 如'MyTable.MySecIndex1' 等. ---- 要 删 除 主 索 引 时,IndexName 为'primary', 如'MyTable.primary'; 值 得 注 意 的 是, 在 删 除 主 索 引 成 功 后, 数 据 表 的 所 有 次 索 引 也 自 动 删 除.

---- 下 面 是 一 个 例 子: ---- 假 设 有 一 个 存 放 通 讯 录 数 据 表MyComm.DB( 类 型 为Paradox) 存 放 于 本 地 目 录 ---- d:\mynote 下, 已 定 义 一 个 主 索 引( 索 引 域 为 编 号ID) 和 一 个 次 索 引( 索 引 域 为 编 号ID 和 姓 名Name, 索 引 名 称 为NameIndex). ---- 现 在 因 为 索 引 损 坏, 要 删 除 索 引, 以 便 重 新 索 引.

with query1 do begin close; DatabaseName := 'd:\MyNote'; {删除次索引NameIndex } sql.clear; sql.add( 'Drop Index MyComm.NameIndex' ); execSql; {删除主索引 } sql.clear; sql.add( 'Drop Index MyComm.Primary' ); execSql; end;

 

三. 注 意 事 项:

---- (1) 在 索 引 更 改 时, 应 保 证 对 应 的 数 据 表 可 以 以 独 占 方 式(Exclusive=true) 打 开, 否 则 会 引 起 错 误. ---- (2) 上 述 方 法 略 加 修 改 后, 也 可 用 于dBase,Oracle 等 其 它 数 据 库 的 数 据 表. ---- (3) 如 果 需 要 重 新 对 索 引 文 件 进 行 索 引, 请 参 考BDE 的Dbi 函 数 说 明: ---- RegenIndex, RegenIndexes. ---- (4) 以 上 程 序 在Delphi3.0 下 测 试 通 过。


作者: 0758河台小赵    时间: 2004-9-5 14:24
用Delphi实现无边界窗体的移动 宋爱平

  在用Delphi制作Windows程序的窗体时,窗体的边界有四种选择:对话框式(bsDialog), 单边固定式(bsSingle),双边可变式(bsSizeable),无边界式(bsNone)。当设置为 bsNone时,窗体也就没有标题条,很显然,程序运行以后就无法移动窗体了。事实上,无边界 窗体是很有用的,例如,象Word里面的浮动式工具箱其实就是无边界窗体,它可以大大节约屏 幕空间。那么,如何用Delphi实现这个功能呢?显然,这需要修改Windows的内部消息,也就 是说,需要把“MouseDownonForm”这个消息改为“MouseDownonCaption”,这其中有三个关键: 捕捉MouseDown消息、判断光标位置、发送MouseDown消息。如果光标在窗体中,则发送 MouseDownonCaption消息。   在Delphi的对象巡检器中列出的所有事件是不能捕捉到Windows消息的,因为这些都是已 经发出的消息,无法修改了。捕捉Win?dows消息有两种办法:一个就是增加一个消息处理句 柄,直接处理Windows消息;另一个是对消息进行过滤,滤出所需消息。第二个办法比较常用, 适用于各种情况,下面就是移动无边界窗体程序片断,加注释部分是手动加入的:   unitUnit1;   :   type   TForm1Κclass(TForm)   procedureFormCreate(Sender:TObject);   :   public   {申明消息过滤过程}   procedureAppMessage(varMsg:TMsg;varHandled :Boolean);   :   implementation   procedureTForm1.FormCreate(Sender:TObject) ;   begin   {捕捉消息:将程序的收到消息事件与消息过滤过程 关联起来}   Application.OnMessage:ΚAppMessage;   end;   procedureTForm1.AppMessage(varMsg:TMsg;var Handled:Boolean);   begin   {如果鼠标左键按下的话}   ifMsg.messageΚWM—LButtonDownthen   begin   {判断光标是否在用户工作区内}   ifDefWindowProc(Handle,WM—NCHitTest,0,Get MessagePos)ΚHTClientthen   begin   {发出鼠标在用户标题栏内被按下的消息}   SendMessage(Handle,WM—NCLButtonDown,   HTCaption,GetMessagePos);   Handled:Κtrue;{消息处理完毕,窗体不再接受M ouseDown及Click事件,如果为false,程序的运行稍微有 些不正常。}   end;   end;   end;   end.   程序在Delphi1.0、中文Windows3.2下运行通过。






欢迎光临 千家论坛_智能建筑与智能家居技术交流社区 (http://bbs.qianjia.com/) Powered by Discuz! X3.2