有人说过“不会开发控件的
Delphi
程序员不是真正的程序员”。
Delphi
正是由于高度的可扩展性和大量的第三方控件的支持才能吸引无数程序员挑剔的目光。即使是由于工作需要使用其他开发工具的开发者也常常怀念和
Delphi
度过的日日夜夜。接触
Delphi
已经一年多了,从当初对着
Delphi
组件面板上上百个控件不知所措,到现在已经可以根据需要开发一些有一定难度的控件,其中走过的路是十分艰辛的,所以特此写下这篇文章,将自己的经验留给后来者,也算是献给“同门师弟”的一份厚礼吧!
需要说明的一点是:在写这篇文章之前我假设读者已经对面向对象的基本知识有一定的了解,所以对于文章中面向对象相关的概念将不再展开讲述。
一、牛刀小试-
TURLLabel
控件
我们从一个能够添加超链接的标签控件开始我们的控件开发之旅吧!
既然是
Label
我们就从
Tlabel
派生这个控件吧
(
其实从
TcustomLabel
派生最好,不过出于简单的目的我们这里先从
Tlabel
派生
)
!
1
、选择“
File
”-
>
“
New
”-
>
“
Component
”
,
将弹出如下的对话框:
在
Ancestor type
中选择
Tlabel
,
ClassName
中填入
TURLLabel(
名字可以任意取,但是要以
T
开头,否则的话会出现注册控件时候的问题
)
。这里
Ancestor type
代表控件的基类,
TURLLabel
代表控件的名称。
2
、超链接的视觉效果是带下划线的文字,所以我们覆盖父类的构造函数,在构造函数里修改控件的字体属性。
constructor TUrlLabel.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
Cursor:=crHandPoint;
Font.Style:= [fsUnderline];
end;
代码解释:
(1)
inherited Create(AOwner);
这句的意思是执行父类的构造函数。我们制作控件的时候,如果覆盖了父类的构造函数,那么在新的构造函数中一定要首先调用父类的构造函数,否则会引起错误。这是很多初学控件开发的人常常遇到的问题。当您把自己开发的控件从面板上拖放到窗体时,如果跳出一个“
Access Violent
”的错误对话框的话,那么十有八九是因为您忘了调用父类的构造函数。
(
2
)
Cursor:=crHandPoint;
Font.Style:= [fsUnderline];
这三句的意思是修改标签的视觉效果。
Cursor:=crHandPoint;
是设定当鼠
标移动到控件上时鼠标的形状为“手型”;
Font.Style:= [fsUnderline];
是设定文字的下划线效果。
3
、既然是超链接控件,那么我们肯定要能使用户在使用控件的时候能在“
Object Inspector
”中对超链接的
URL
进行修改,所以我们应该为控件增加一个
Url
属性。
属性是访问控件字段的接口。通过属性,控件使用者可以间接读或者写控件的内部字段改变控件的状态。组件属性的声明需要以下几部分:属性名、属性类型、读方法(或读字段)、写方法(或写字段。如果没有写方法或写字段,则该属性为只读属性)。属性在控件类声明的
Published
部分声明。在
Published
中声明的属性可以在设计期通过“
Object Inspector
”对属性值进行修改。如果声明在
Public
部分则不可以在设计期通过“
Object Inspector
”对属性值进行修改,但是可以在运行时通过代码进行读写。
在类声明的
Private
访问区域中添加如下字段声明:
FUrl: String;
在类声明中添加
Published
访问区域,并添加如下代码
property Url: String read FUrl write FUrl;
这段声明的意思是为控件添加一个
Url
属性,属性的类型是
string
,在读
Url
属性时返回
Furl
的值,在写
Url
属性时设定
Furl
的值。
4
、超链接的视觉效果有了,下面使它点击时调用浏览器打开
Url
指定的网址。
在
Delphi
控件的事件处理中很多事件都有对应的一个调度方法(这是设计模式中模板模式的典型应用)。比如在鼠标点击控件时,控件会首先调用
Click
方法,由
Click
方法进行相应的处理,而绝大多数调度方法都会引发一个事件句柄(关于事件句柄我们后边有深入的介绍)。比如
Tlabel
控件中在用户用点击
Label
时会首先调用控件的
Click
方法(被声明为
Protected
级别),
Click
方法再触发
OnClick
事件。所以我们只要覆盖
Tlabel
的
Click
方法进行我们自己的处理就可以了。
在
Protected
部分添加如下的声明:
procedure Click;override;
在实现部分为
Click
方法写如下的代码:
procedure TUrlLabel.Click;
begin
ShellExecute(Application.Handle, nil, PChar(Url), nil, nil,SW_NORMAL);
inherited;
end;
代码解释:
(1)
ShellExecute
的作用是用默认的程序打开第三个参数指定的文件。所以当第三个参数为一个
URL
时,则用浏览器打开这个网址。关于
ShellExecute
其他参数的使用方法可以查阅
MSDN
或其他相关资料。
(2)
Inherited;
的作用是调用父类的
Click
方法来由父类来对鼠标单击事件做其他的处理。
5
、源代码。
下面给出这个控件的全部源代码:
unit UrlLabel;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, StdCtrls,Shellapi,
Graphics, Forms;
type
TUrlLabel = class(TLabel)
private
FUrl:AnsiString;
protected
procedure Click;override;
public
constructor Create(AOwner:TComponent);override;
published
property Url:AnsiString read FUrl write FUrl;
end;
procedure Register;
implementation
constructor TUrlLabel.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
Cursor:=crHandPoint;
Font.Style:=[fsUnderline];
end;
procedure TUrlLabel.Click;
begin
ShellExecute(Application.Handle, nil, PChar(Url), nil, nil,SW_NORMAL);
inherited;
end;
procedure Register;
begin
RegisterComponents('Linco', [TUrlLabel]);//
控件生成向导生成的注册控件用代码
end;
end.
6
、为控件添加图标。
如果没有给自定义的控件定义图标,出现在控件面板上的自定义图标的图标是默认的图标,很没有“个性”,也不容易被用户与其他控件区别开来,所以我们需要给组件指定一个图标。
首先利用
Delphi
的
Image Editor
创建一个
24*24
的位图,并把它保存到一个
DCR
文件中。创建了一个位图后,就需要给位图命名了。位图的名称必须和控件的类名相同,且为大写,而
DCR
文件的名字则必须与控件所在单元的单元名相同。如我们上边定义的控件,位图的名字应该为
TURLLABEL
,
DCR
文件的名字应该是
UrlLabel.dcr
,此
DCR
文件应该与组件的单元文件放在同一个目录下。
打开
Image Editor,
选择
”File”
-
>
“
New
”
-
>
“
Component Resource File(.dcr)
”,如下图:
在“
Contents
”上单击鼠标右键,选择“
New
”-
>
“
BitMap
”:
在
Width,Height
中都填入
24
,点“
OK
”即可。
可以在
Bitmap1
上点右键选择“
Rename
”为位图重命名为
TURLLABEL
,然后双击
TURLLABEL
,就可以像使用“画图”一样为您的控件设计图标了。
7
、注册组件。
点击
Componet
-
>Install Componet
进行自定义组件安装,此时将出现组件安装对话框。
在
Unit FilName
中输入控件单元文件的文件名(包括路径),点击“
OK
”
,
在弹出的
Package Editor
中按下
Install
按钮。如果安装成功系统就会提示安装成功。关闭
Package Editor
时,会提示您是否保存修改,点击
Yes
即可。
安装成功,建立一个测试程序。将
URLLabel
控件放到窗体上,设定
Url
属性为
http://www.sohu.com
运行程序,点击此
Label
,就会弹出浏览器打开
http://www.sohu.com
这个网址。
可以在tools/image editor下实现。
用Delphi做过数据库编程的朋友肯定熟悉Query控件,这个控件实现的功能是执行一条SQL语句或一个SQL脚本,在我们进行数据库开发中使用的频率非常高。笔者在多年的使用过程中发现用好这个控件有两点要非常注意。
第一点是:区分好Query控件的Open方法和ExecSQL方法。这两个方法都可以实现执行SQL语句,但要根据不同情况分别使用。如果这条SQL语句将返回一个结果集,必须使用Open方法,如果不返回一个结果集,则要使用ExecSQL方法。例如:
……
Query1:Tquery
Query2:Tquery
……
Query1.Close;
Query1.SQL.Clear;
Query1.SQL.Add('select * from AA');
Query1.Open;
……
Query2.Close;
Query2.SQL.Clear;
Query2.SQL.Add('delete AA');
Query2.ExecSQL;
……
上述的例子中,Query1所执行的SQL语句将返回一个结果集,因此必须用Open方法;而Query2所执行的是一条删除表记录语句,不返回结果集,因此用ExecSQL方法。
第二点是:如果Query控件用Open方法执行SQL语句,并且所用的SQL语句访问的是一张或几张频繁使用的表,在执行完SQL语句后,一定要调用SQL的FetchAll方法,能大大地减少死锁发生的概率。例如:
……
Query1:Tquery
……
Query1.Close;
Query1.SQL.Clear;
Query1.SQL.Add('select * from AA');
Query1.Open;
Query1.FetchAll;
……
在上述的例子中,如果AA是一张被频繁访问的表,在对这个表执行这一条select语句的同时,如果恰好有其他人对这张表执行删除或更新操作,便有可能发生死锁。Query1.FetchAll这条语句实现的功能是释放加在表AA上的锁,这样死锁的发生概率可以大大减少。避免死锁,对我们将来进行大型数据库开发尤为重要。"
select a.id , a.key , a.time , a.nt1 , ( TRUNC(( a.nt1 - a.time )*24*3600) ) as interval
from
(
select t1.id , t1.key , t1.time ,
(
select time
from table
where rownum = 1 and key > t1.key
) as nt1
from table t1
) a
木马是随计算机或Windows的启动而启动并掌握一定的控制权的,其启动方式可谓多种多样,通过注册表启动、通过System.ini启动、通过某些特定程序启动等,真是防不胜防。其实只要能够遏制住不让它启动,木马就没什么用了,这里就简单说说木马的启动方式,知己知彼百战不殆嘛。
一、通过"开始\程序\启动"
隐蔽性:2星
应用程度:较低
这也是一种很常见的方式,很多正常的程序都用它,大家常用的QQ就是用这种方式实现自启动的,但木马却很少用它。因为启动组的每人会会出现在“系统配置实用程序”(msconfig.exe,以下简称msconfig)中。事实上,出现在“开始”菜单的“程序\启动”中足以引起菜鸟的注意,所以,相信不会有木马用这种启动方式。
二、通过Win.ini文件
隐蔽性:3星
应用程度:较低
应用案例:Asylum
同启动组一样,这也是从Windows3.2开始就可以使用的方法,是从Win16遗传到Win32的。在Windows3.2中,Win.ini就相当于Windows9x中的注册表,在该文件中的[Windows]域中的load和run项会在Windows启动时运行,这两个项目也会出现在msconfig中。而且,在Windows98安装完成后这两项就会被Windows的程序使用了,也不很适合木马使用。
三、通过注册表启动
1、通过HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run,
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run和
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices
隐蔽性:3.5星
应用程度:极高
应用案例:BO2000,GOP,NetSpy,IEthief,冰河……
这是很多Windows程序都采用的方法,也是木马最常用的。使用非常方便,但也容易被人发现,由于其应用太广,所以几乎提到木马,就会让人想到这几个注册表中的主键,通常木马会使用最后一个。使用Windows自带的程序:msconfig或注册表编辑器(regedit.exe,以下简称regedit)都可以将它轻易的删除,所以这种方法并不十分可靠。但可以在木马程序中加一个时间控件,以便实时监视注册表中自身的启动键值是否存在,一旦发现被删除,则立即重新写入,以保证下次Windows启动时自己能被运行。这样木马程序和注册表中的启动键值之间形成了一种互相保护的状态。木马程序未中止,启动键值就无法删除(手工删除后,木马程序又自动添加上了),相反的,不删除启动键值,下次启动Windows还会启动木马。怎么办呢?其实破解它并不难,即使在没有任何工具软件的情况下也能轻易解除这种互相保护。
破解方法:首先,以安全模式启动Windows,这时,Windows不会加载注册表中的项目,因此木马不会被启动,相互保护的状况也就不攻自破了;然后,你就可以删除注册表中的键值和相应的木马程序了。
2、通过HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce,
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce和
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce
隐蔽性:4星
应用程度:较低
应用案例:Happy99
这种方法好像用的人不是很多,但隐蔽性比上一种方法好,它的内容不会出现在msconfig中。在这个键值下的项目和上一种相似,会在Windows启动时启动,但Windows启动后,该键值下的项目会被清空,因而不易被发现,但是只能启动一次,木马如何能发挥效果呢?
其实很简单,不是只能启动一次吗?那木马启动成功后再在这里添加一次不就行了吗?在Delphi中这不过3、5行程序。虽说这些项目不会出现在msconfig中,但是在Regedit中却可以直接将它删除,那么木马也就从此失效了。
还有一种方法,不是在启动的时候加而是在退出Windows的时候加,这要求木马程序本身要截获WIndows的消息,当发现关闭Windows消息时,暂停关闭过程,添加注册表项目,然后才开始关闭Windows,这样用Regedit也找不到它的踪迹了。这种方法也有个缺点,就是一旦Windows异常中止(对于Windows9x这是经常的),木马也就失效了。
破解他们的方法也可以用安全模式。
另外使用这三个键值并不完全一样,通常木马会选择第一个,因为在第二个键值下的项目会在Windows启动完成前运行,并等待程序结束会才继续启动Windows。
四、通过Autoexec.bat文件,或winstart.bat,config.sys文件
隐蔽性:3.5星
应用程度:较低
其实这种方法并不适合木马使用,因为该文件会在Windows启动前运行,这时系统处于DOS环境,只能运行16位应用程序,Windows下的32位程序是不能运行的。因此也就失去了木马的意义。不过,这并不是说它不能用于启动木马。可以想象,SoftIce for Win98(功能强大的程序调试工具,被黑客奉为至宝,常用于破解应用程序)也是先要在Autoexec.bat文件中运行然后才能在Windows中呼叫出窗口,进行调试的,既然如此,谁能保证木马不会这样启动呢?到目前为止,我还没见过这样启动的木马,我想能写这样木马的人一定是高手中的高手了。
另外,这两个BAT文件常被用于破坏,它们会在这个文件中加入类似"Deltree C:\*.*"和"Format C:/u"的行,这样,在你启动计算机后还未启动Windows,你的C盘已然空空如也。
五、通过System.ini文件
隐蔽性:5星
应用程度:一般
应用案例:尼姆达
事实上,System.ini文件并没有给用户可用的启动项目,然而通过它启动却是非常好用的。在System.ini文件的[Boot]域中的Shell项的值正常情况下是"Explorer.exe",这是Windows的外壳程序,换一个程序就可以彻底改变Windows的面貌(如改为Progman.exe就可以让Win9x变成Windows3.2)。我们可以在"Explorer.exe"后加上木马程序的路径,这样Windows启动后木马也就随之启动,而且即使是安全模式启动也不会跳过这一项,这样木马也就可以保证永远随Windows启动了,名噪一时的尼姆达病毒就是用的这种方法。这时,如果木马程序也具有自动检测添加Shell项的功能的话,那简直是天衣无缝的绝配,我想除了使用查看进程的工具中止木马,再修改Shell项和删除木马文件外是没有破解之法了。但这种方式也有个先天的不足,因为只有Shell这一项嘛,如果有两个木马都使用这种方式实现自启动,那么后来的木马可能会使前一个无法启动,呵呵以毒攻毒啊。
六、通过某特定程序或文件启动
1、寄生于特定程序之中
隐蔽性:5星
应用程度:一般
即木马和正常程序捆绑,有点类似于病毒,程序在运行时,木马程序先获得控制权或另开一个线程以监视用户操作,截取密码等,这类木马编写的难度较大,需要了解PE文件结构和Windows的底层知识(直接使用捆绑程序除外)。
2、将特定的程序改名
隐蔽性:5星
应用程度:常见
这种方式常见于针对QQ的木马,例如将QQ的启动文件QQ2000b.exe,改为QQ2000b.ico.exe(Windows默认是不显示扩展名的,因此它会被显示为QQ2000b.ico,而用户会认为它是一个图标),再将木马程序改为QQ2000b.exe,此后,用户运行QQ,实际是运行了QQ木马,再由QQ木马去启动真正的QQ,这种方式实现起来要比上一种简单的多。
3、文件关联
隐蔽性:5星
应用程度:常见
应用案例:广外女生
通常木马程序会将自己和TXT文件或EXE文件关联,这样当你打开一个文本文件或运行一个程序时,木马也就神不知鬼不觉的启动了。
这类通过特定程序或文件启动的木马,发现比较困难,但查杀并不难。一般地,只要删除相应的文件和注册表键值即可。
摘要: 32位Delphi程序中可利用TRegistry对象来存取注册表文件中的信息。 一、创建和释放TRegistry对象 1.创建TRegistry对象。为了操作注册表,要创建一个TRegistry对象:ARegistry := TRegistry.Create; 2.释放TRegistry对象。对注册表操作结束后,应释放TRegistry对象所占内存:ARegistry.Destr...
阅读全文
Delphi的TRegistry注册表类方法详解
●GetDataInfo方法
Function GetDataInfo(const ValueName:String;Var Value:TRegDataInfo):Boolean;
TregDataType=(rdunknown,rdstring,rdexpandstring,rdexpandstring,rdinterger,rdbinary);
TregDataInfo=record
Regdata:TRegDataType;数据类型
dataSize:integer;数据大小
end
valuename:和当前键关联的数据值名称
value:返回数据的信息,如为rdstring和rdexpandstring类型,则数据大小包括字符串未尾的空结束字符。
如果成功返回True,失败返回False,并且Value的值为zeros
rdexpandstring:是一个包含环境变量的字符串;如“%PATH%”。
●CreateKey方法
Function CreateKey(const Key:string):Boolena;
新建一个名为Key的键,Key可以为绝对的或相对的名字,绝对名用反斜杠“\”开头,相对名是新建一个当前键的子键。新建没有值。
成功返回True,否则返回False,如果该键已存在将不产生效果。
●DeleteKey方法
Function DeleteKey(const Key:string):Boolean;
删除一个键及相关联的数据,在win95中子键也将被删除,NT中子键必须一个个删除。
●DeleteValue方法
Function DeleteValue (const Name:string):Boolean;
删除当前键中指定的一个数据值name。
●GetDataSize方法
Function GetDataSize(const ValueName:string):integer;
返回当前键中一个指定数值ValueName数据的大小。
●GetDataType方法
Function GetDataType(const Valuename;string):TRegDataType;
返回当前键中一个指定数值Valuename数据的类型。
●GetKeyInfo方法
Function GetKeyInfo(var value:TRegkeyinfo):Boolean;
返回当前键的信息,在于value中。
TRegkeyinfo=record
maxsubkeylen:integer;子键名的最长值(字节)
numvalues:integer;键值的数量
maxvaluelen;最长的键值名的长度
Filetime:TFileTime;最后一次更改的时间
end;
●Getkeynames方法
Procedure Getkeynames(strings:Tsrtings);
返回当前键所有子键的名子列表串。
●Getvaluenames
Procedure Getvaluenames(strings:Tstrings);
返回当前键所有键值名的列表串。
●Hassubkeys方法
Function hassubKeys:Boolean;
判断当前键是否有子键,有返回True,否则返回False。
●keyExists方法
Function KeyExists(const Key:string):Boolean;
判断指定的键是否存在。
●LoadKey方法
Function LoadKey(const Key,fileNmae:string):Boolean;
在根键下新建
从一个文件中加载注册信息到子键中,文件注册信息中包含数据值名、子键和数据。
LoadKey使创建一个键单一化,子键,键值和数据在一人操作中完成,所有这些称为一组,和单独地创建它们不同应用程序可以在一个文件中读取一组数据,这在用户运行中重新设置有特别的用处。
Key为要创建子键的名子
FileName:为文件的位置,所指定的文件必须为以前用SaveKey函数或RegSaveKey API函数所建立的,文件名不能包括扩展名。
●OpenKey方法
Function OpenKey(const Key:string;cancreate:Boolean):Boolean;
使用该函数可以指定一个键作为当前键,如果键为nil,则当前键 将设置为根键。
Cancreate决定是否在指定键不存在时创建该键,该函数创建的键的键值将不确定。
如果成功地打开或创建,该函数返回True。
●OpenKeyReadOnly方法
function OpenKeyReadOnly(const Key: String): Boolean;
以只读的方式打开Key值指定的键。
●CloseKey方法
procedure CloseKey;
当不再使用一个键时应用该方法关闭该键。
●MoveKey方法
procedure MoveKey(const OldName, NewName: String; Delete: Boolean);
该方法移动或复制一个键到一个新的位置,并把键的名子改为NewName。
在Win95/98下该的子键和数据将被一起移动或复制到新的位置,在NT下子键必须用MoveKey明确的移动或自制。
●读取数据的方法
function ReadBinaryData(const Name: String; var Buffer; BufSize: Integer):Integer;
function ReadBool(const Name: String): Boolean;
function ReadCurrency(const Name: String): Currency;
function ReadDate(const Name: String): TDateTime;
function ReadDateTime(const Name: String): TDateTime;
function ReadFloat(const Name: String): Double;
function ReadInteger(const Name: String): Integer;
function ReadString(const Name: String): String;
function ReadTime(const Name: String): TDateTime;
以上方法从当前主键读取相应数据类型的键值的数据,如果类型不匹配将产生一个异常。
●RegistryConnect方法
function RegistryConnect(const UNCName: String): Boolean;
与另一台计算机的注册表建立连接,在建立连接前应将Rootkey属性设为HKEY_USERS或HKEY_LOCAL_MACHINE。
UNCName是另一台计算机的名子。格式如:\\computername
假如UNCName为nil,将打开本地计算机。
在Windows XP系统下,运行“msconfig”后,系统提示找不到该文件。但是该文件明明存在于系统分区中,而且可以双击打开。
这是因为msconfig.exe存在于 %systemroot%\PCHealth\HelpCtr\Binaries 目录中,而不是
%systemroot% 或 %systemroot%\system32
,无法省略其路径而直接运行文件名打开。我们平时之所以能够直接运行msconfig打开该程序,是因为在注册表中的
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
键下有msconfig.exe的相关路径,起到导向功能。如果没有了msconfig.exe相关路径或者路径错误,就会导致无法直接运行文件名打开。解决方法:运行“regedit”,找到
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
在右边窗口中,右击空白处,依次选择【新建】→【项】,将其名改为“MSCONFIG.EXE”。然后选中“MSCONFIG.EXE”,再在右边窗口中,双击字符串值【默认】,把数值改为“C:\Windows\PCHealth\HelpCtr\Binaries\MSConfig.exe”(根据系统所在分区自行更改)。修改后,我们就可以像以前一样直接运行msconfig打开该程序啦。
如何用程序设定服务的启动类型是自动、手动还是禁用?
用ControlService API函数只能控制服务的启动、暂停、恢复、停止
修改
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ServerName]
"Start"=dword:00000002
2为自动,3为手动.
(一) 使用动态创建的方法
首先创建 Excel 对象,使用ComObj:
var ExcelApp: Variant;
ExcelApp := CreateOleObject( 'Excel.Application' );
1) 显示当前窗口:
ExcelApp.Visible := True;
2) 更改 Excel 标题栏:
ExcelApp.Caption := '应用程序调用 Microsoft Excel';
3) 添加新工作簿:
ExcelApp.WorkBooks.Add;
4) 打开已存在的工作簿:
ExcelApp.WorkBooks.Open( 'C:\Excel\Demo.xls' );
5) 设置第2个工作表为活动工作表:
ExcelApp.WorkSheets[2].Activate;
或
ExcelApp.WorksSheets[ 'Sheet2' ].Activate;
6) 给单元格赋值:
ExcelApp.Cells[1,4].Value := '第一行第四列';
7) 设置指定列的宽度(单位:字符个数),以第一列为例:
ExcelApp.ActiveSheet.Columns[1].ColumnsWidth := 5;
8) 设置指定行的高度(单位:磅)(1磅=0.035厘米),以第二行为例:
ExcelApp.ActiveSheet.Rows[2].RowHeight := 1/0.035; // 1厘米
9) 在第8行之前插入分页符:
ExcelApp.WorkSheets[1].Rows[8].PageBreak := 1;
10) 在第8列之前删除分页符:
ExcelApp.ActiveSheet.Columns[4].PageBreak := 0;
11) 指定边框线宽度:
ExcelApp.ActiveSheet.Range[ 'B3:D4' ].Borders[2].Weight := 3;
1-左 2-右 3-顶 4-底 5-斜( \ ) 6-斜( / )
12) 清除第一行第四列单元格公式:
ExcelApp.ActiveSheet.Cells[1,4].ClearContents;
13) 设置第一行字体属性:
ExcelApp.ActiveSheet.Rows[1].Font.Name := '隶书';
ExcelApp.ActiveSheet.Rows[1].Font.Color := clBlue;
ExcelApp.ActiveSheet.Rows[1].Font.Bold := True;
ExcelApp.ActiveSheet.Rows[1].Font.UnderLine := True;
14) 进行页面设置:
a.页眉:
ExcelApp.ActiveSheet.PageSetup.CenterHeader := '报表演示';
b.页脚:
ExcelApp.ActiveSheet.PageSetup.CenterFooter := '第&P页';
c.页眉到顶端边距2cm:
ExcelApp.ActiveSheet.PageSetup.HeaderMargin := 2/0.035;
d.页脚到底端边距3cm:
ExcelApp.ActiveSheet.PageSetup.HeaderMargin := 3/0.035;
e.顶边距2cm:
ExcelApp.ActiveSheet.PageSetup.TopMargin := 2/0.035;
f.底边距2cm:
ExcelApp.ActiveSheet.PageSetup.BottomMargin := 2/0.035;
g.左边距2cm:
ExcelApp.ActiveSheet.PageSetup.LeftMargin := 2/0.035;
h.右边距2cm:
ExcelApp.ActiveSheet.PageSetup.RightMargin := 2/0.035;
i.页面水平居中:
ExcelApp.ActiveSheet.PageSetup.CenterHorizontally := 2/0.035;
j.页面垂直居中:
ExcelApp.ActiveSheet.PageSetup.CenterVertically := 2/0.035;
k.打印单元格网线:
ExcelApp.ActiveSheet.PageSetup.PrintGridLines := True;
15) 拷贝操作:
a.拷贝整个工作表:
ExcelApp.ActiveSheet.Used.Range.Copy;
b.拷贝指定区域:
ExcelApp.ActiveSheet.Range[ 'A1:E2' ].Copy;
c.从A1位置开始粘贴:
ExcelApp.ActiveSheet.Range.[ 'A1' ].PasteSpecial;
d.从文件尾部开始粘贴:
ExcelApp.ActiveSheet.Range.PasteSpecial;
16) 插入一行或一列:
a. ExcelApp.ActiveSheet.Rows[2].Insert;
b. ExcelApp.ActiveSheet.Columns[1].Insert;
17) 删除一行或一列:
a. ExcelApp.ActiveSheet.Rows[2].Delete;
b. ExcelApp.ActiveSheet.Columns[1].Delete;
18) 打印预览工作表:
ExcelApp.ActiveSheet.PrintPreview;
19) 打印输出工作表:
ExcelApp.ActiveSheet.PrintOut;
20) 工作表保存:
if not ExcelApp.ActiveWorkBook.Saved then
ExcelApp.ActiveSheet.PrintPreview;
21) 工作表另存为:
ExcelApp.SaveAs( 'C:\Excel\Demo1.xls' );
22) 放弃存盘:
ExcelApp.ActiveWorkBook.Saved := True;
23) 关闭工作簿:
ExcelApp.WorkBooks.Close;
24) 退出 Excel:
ExcelApp.Quit;
(二) 使用Delphi 控件方法
在Form中分别放入ExcelApplication, ExcelWorkbook和ExcelWorksheet。
1) 打开Excel
ExcelApplication1.Connect;
2) 显示当前窗口:
ExcelApplication1.Visible[0]:=True;
3) 更改 Excel 标题栏:
ExcelApplication1.Caption := '应用程序调用 Microsoft Excel';
4) 添加新工作簿:
ExcelWorkbook1.ConnectTo(ExcelApplication1.Workbooks.Add(EmptyParam,0));
5) 添加新工作表:
var Temp_Worksheet: _WorkSheet;
begin
Temp_Worksheet:=ExcelWorkbook1.
WorkSheets.Add(EmptyParam,EmptyParam,EmptyParam,EmptyParam,0) as _WorkSheet;
ExcelWorkSheet1.ConnectTo(Temp_WorkSheet);
End;
6) 打开已存在的工作簿:
ExcelApplication1.Workbooks.Open (c:\a.xls
EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,0)
7) 设置第2个工作表为活动工作表:
ExcelApplication1.WorkSheets[2].Activate; 或
ExcelApplication1.WorksSheets[ 'Sheet2' ].Activate;
8) 给单元格赋值:
ExcelApplication1.Cells[1,4].Value := '第一行第四列';
9) 设置指定列的宽度(单位:字符个数),以第一列为例:
ExcelApplication1.ActiveSheet.Columns[1].ColumnsWidth := 5;
10) 设置指定行的高度(单位:磅)(1磅=0.035厘米),以第二行为例:
ExcelApplication1.ActiveSheet.Rows[2].RowHeight := 1/0.035; // 1厘米
11) 在第8行之前插入分页符:
ExcelApplication1.WorkSheets[1].Rows[8].PageBreak := 1;
12) 在第8列之前删除分页符:
ExcelApplication1.ActiveSheet.Columns[4].PageBreak := 0;
13) 指定边框线宽度:
ExcelApplication1.ActiveSheet.Range[ 'B3:D4' ].Borders[2].Weight := 3;
1-左 2-右 3-顶 4-底 5-斜( \ ) 6-斜( / )
14) 清除第一行第四列单元格公式:
ExcelApplication1.ActiveSheet.Cells[1,4].ClearContents;
15) 设置第一行字体属性:
ExcelApplication1.ActiveSheet.Rows[1].Font.Name := '隶书';
ExcelApplication1.ActiveSheet.Rows[1].Font.Color := clBlue;
ExcelApplication1.ActiveSheet.Rows[1].Font.Bold := True;
ExcelApplication1.ActiveSheet.Rows[1].Font.UnderLine := True;
16) 进行页面设置:
a.页眉:
ExcelApplication1.ActiveSheet.PageSetup.CenterHeader := '报表演示';
b.页脚:
ExcelApplication1.ActiveSheet.PageSetup.CenterFooter := '第&P页';
c.页眉到顶端边距2cm:
ExcelApplication1.ActiveSheet.PageSetup.HeaderMargin := 2/0.035;
d.页脚到底端边距3cm:
ExcelApplication1.ActiveSheet.PageSetup.HeaderMargin := 3/0.035;
e.顶边距2cm:
ExcelApplication1.ActiveSheet.PageSetup.TopMargin := 2/0.035;
f.底边距2cm:
ExcelApplication1.ActiveSheet.PageSetup.BottomMargin := 2/0.035;
g.左边距2cm:
ExcelApplication1.ActiveSheet.PageSetup.LeftMargin := 2/0.035;
h.右边距2cm:
ExcelApplication1.ActiveSheet.PageSetup.RightMargin := 2/0.035;
i.页面水平居中:
ExcelApplication1.ActiveSheet.PageSetup.CenterHorizontally := 2/0.035;
j.页面垂直居中:
ExcelApplication1.ActiveSheet.PageSetup.CenterVertically := 2/0.035;
k.打印单元格网线:
ExcelApplication1.ActiveSheet.PageSetup.PrintGridLines := True;
17) 拷贝操作:
a.拷贝整个工作表:
ExcelApplication1.ActiveSheet.Used.Range.Copy;
b.拷贝指定区域:
ExcelApplication1.ActiveSheet.Range[ 'A1:E2' ].Copy;
c.从A1位置开始粘贴:
ExcelApplication1.ActiveSheet.Range.[ 'A1' ].PasteSpecial;
d.从文件尾部开始粘贴:
ExcelApplication1.ActiveSheet.Range.PasteSpecial;
18) 插入一行或一列:
a. ExcelApplication1.ActiveSheet.Rows[2].Insert;
b. ExcelApplication1.ActiveSheet.Columns[1].Insert;
19) 删除一行或一列:
a. ExcelApplication1.ActiveSheet.Rows[2].Delete;
b. ExcelApplication1.ActiveSheet.Columns[1].Delete;
20) 打印预览工作表:
ExcelApplication1.ActiveSheet.PrintPreview;
21) 打印输出工作表:
ExcelApplication1.ActiveSheet.PrintOut;
22) 工作表保存:
if not ExcelApplication1.ActiveWorkBook.Saved then
ExcelApplication1.ActiveSheet.PrintPreview;
23) 工作表另存为:
ExcelApplication1.SaveAs( 'C:\Excel\Demo1.xls' );
24) 放弃存盘:
ExcelApplication1.ActiveWorkBook.Saved := True;
25) 关闭工作簿:
ExcelApplication1.WorkBooks.Close;
26) 退出 Excel:
ExcelApplication1.Quit;
ExcelApplication1.Disconnect;
(三) 使用Delphi 控制Excle二维图
在Form中分别放入ExcelApplication, ExcelWorkbook和ExcelWorksheet
var asheet1,achart, range:variant;
1)选择当第一个工作薄第一个工作表
asheet1:=ExcelApplication1.Workbooks[1].Worksheets[1];
2)增加一个二维图
achart:=asheet1.chartobjects.add(100,100,200,200);
3)选择二维图的形态
achart.chart.charttype:=4;
4)给二维图赋值
series:=achart.chart.seriescollection;
range:=sheet1!r2c3:r3c9;
series.add(range,true);
5)加上二维图的标题
achart.Chart.HasTitle:=True;
achart.Chart.ChartTitle.Characters.Text:=’ Excle二维图’
6)改变二维图的标题字体大小
achart.Chart.ChartTitle.Font.size:=6;
7)给二维图加下标说明
achart.Chart.Axes(xlCategory, xlPrimary).HasTitle := True;
achart.Chart.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text := '下标说明';
8)给二维图加左标说明
achart.Chart.Axes(xlValue, xlPrimary).HasTitle := True;
achart.Chart.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text := '左标说明';
9)给二维图加右标说明
achart.Chart.Axes(xlValue, xlSecondary).HasTitle := True;
achart.Chart.Axes(xlValue, xlSecondary).AxisTitle.Characters.Text := '右标说明';
10)改变二维图的显示区大小
achart.Chart.PlotArea.Left := 5;
achart.Chart.PlotArea.Width := 223;
achart.Chart.PlotArea.Height := 108;
11)给二维图坐标轴加上说明
achart.chart.seriescollection[1].NAME:='坐标轴说明';
(三) 数据库
1.存储过程
先执行如下存储过程
EXEC sp_addlinkedserver
'ExcelSource',
'Jet 4.0',
'Microsoft.Jet.OLEDB.4.0',
'C:\Documents and Settings\Administrator\桌面\xinxi3.xls',
NULL,
'Excel 5.0'
EXEC sp_addlinkedsrvlogin ExcelSource, FALSE, NULL, NULL
然后执行下面这个存储过程
EXEC sp_tables_ex ExcelSource //显示几张表
这时会返回几个表的名称(个数与excel中sheet的个数一致)
然后你用以下语句:
select * from ExcelSource...Sheet1$
就可以查出来excel中的数据,然后就可以进行倒入的操作了
导入完毕记得执行以下两个存储过程:
--EXEC sp_droplinkedsrvlogin ExcelSource, NULL
--EXEC sp_dropserver ExcelSource
以上所有的操作可以先在查询分析器中test一下,然后你可以写存储过程来实现
2.ADO
procedure TForm1.BitBtn1Click(Sender: TObject);
var
a,b,c,FileName,SheetName,SqlStr,ConnStr :string ;
begin
FileName :='D:\abc.xls' ;
SheetName :='Sheet1' ;
ADOQuery1.Close ;
ADOQuery1.SQL.Clear ;
ConnStr :='Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + FileName + ';Extended Properties=Excel 8.0;Persist Security Info=False';
ADOQuery1.ConnectionString :=ConnStr ;
SqlStr :='Select * from [' + SheetName + '$]' ;
ADOQuery1.SQL.Add(SqlStr) ;
ADOQuery1.Prepared ;
ADOQuery1.Open ;
while not ADOQuery1.Eof do
begin
a :=ADOQuery1.Fields[0].AsString ;
b :=ADOQuery1.Fields[1].AsString ;
c :=ADOQuery1.Fields[2].AsString ;
end ;
end;