delphi的一些小知识,备忘

来源:互联网 发布:unity3d 国际象棋 编辑:程序博客网 时间:2024/04/30 08:48

1、静待数组与动态数组

动态数组名为一个指针,,是数组首地址。静态数组名为一个变量,是数组首元素的值arr[0];

larr: array[0..10] of char;

larrd: array of char;

静态数组取首地址可以使用@larr或者@larr[0],而动态数组可以用@larrd[0]或larrd; 


var

  a: array [1..20] of Char;

  b: array of char;

  ptr : PChar; //PChar 可以看作 ^Char

begin

  setlength(b,20);

  fillchar(a, length(a),#0);

  fillchar(b, length(b),#0);

  ptr := 'abcdeftghijklmn';

  strCopy(@a, ptr);

  StrCopy(@b[0], ptr); //这里如果使用strCopy(@b,ptr),将报错

  //ptr := @a;

  ptr := ''; //这里对pchar类型的变量赋空字符串后,必须重新申请内存空间才能再使用strcopy对变量进行赋值;

  GetMem(ptr,length(b));

  StrCopy(ptr, @b[0]);//这里如果写成strcopy(ptr,@b); 将无法把数组b的内容正确拷贝给ptr 

  showmessage(ptr);

  freememory(ptr);

  ptr := @a;

  Inc(ptr); // 这句等价于 C 的 ptr++;

  Inc(ptr, 2); //这句等价于 C 的 ptr+=2;

  showmessage(ptr);

end;

--------------------------------------------------------------------------------------

2、move、copymemory

  Move和CopyMemory本来是同一个东西,参数稍变结果你就调错了还不知道。看下面你的DEMO:
  new(P);
  Move(ABuffer,P, Sizeof(ABuffer)); //可以将数据复制到P, ABuffer 和 P 指向同一个内存区 , ABuffer = $29580D0 ,ip= '192.168.1.132',P = $29580D0

  这个只是把指针ABuffer的四个字节拷贝到P,而不是拷贝指针指向的内存块,所以持行这个的结果是ABuffer和P都指向一块内存,效果和P:=ABuffer一样。你应该这样调:
Move(ABuffer^,P^, Sizeof(TArrayByte));
而用CopyMemory是这样:
CopyMemory(P,ABuffer, Sizeof(TArrayByte));

这两个是等效的。注意Move和CopyMemory的参数,两个的参数是不一样的,Move的参数传的是数据块的地址,而CopyMemory传的是指针.

--------------------------------------------------------------------------------------

3、静态方法(普通的方法)、虚方法、动态方法:

静态方法只根据变量的定义类型来调用,定义的什么类型就取什么类型里边的对应事件;

虚方法、动态方法会根据变量实际引用的对象类型来调用该对象类型里边的对应事件

--------------------------------------------------------------------------------------

4、窗体移动,对于没有标题栏的窗体比较有用

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
   ReleaseCapture;
   Perform(WM_SYSCOMMAND, $F012,
0);
end;

 

------------------------------------------------------------------------------------------------------------------------------------------------------

对象的方法能定义成静态(static)、虚拟(virtual)、动态(dynamic)或消息处理(message)。请看下面 
的例子: 

TFoo = class 
procedure IAmAStatic; 
procedure IAmAVirtual; virtual; 
procedure IAmADynamic; dynamic; 
procedure IAmAMessage(var M:TMessage); message wm_SomeMessage; 
end; 

1. 静态方法 
IAmAStatic 是一个静态方法,静态方法是方法的缺省类型,对它就像对通常的过程和函数那样调 
用。编译器知道这些方法的地址,所以调用一个静态方法时它能把运行信息静态地链接进可执行文件。 
静态方法执行的速度最快,但它们却不能被覆盖来支持多态性。 

2. 虚拟方法 
IAmAVirtual 是一个虚拟方法。虚拟方法和静态方法的调用方式相同。由于虚拟方法能被覆盖,在 
代码中调用一个指定的虚拟方法时编译器并不知道它的地址。因此,编译器通过建立虚拟方法表(VMT) 
来查找在运行时的函数地址。所有的虚拟方法在运行时通过VMT来调度,一个对象的VMT表中 
除了自己定义的虚拟方法外,还有它的祖先的所有的虚拟方法,因此虚拟方法比动态方法用的内存要 
多,但它执行得比较快。 

3. 动态方法 
IAmADynamic 是一个动态方法,动态方法跟虚拟方法基本相似,只是它们的调度系统不同。编译 
器为每一个动态方法指定一个独一无二的数字,用这个数字和动态方法的地址构造一个动态方法表 
(DMT)。不像VMT表,在DMT表中仅有它声明的动态方法,并且这个方法需要祖先的DMT表来访问 
它其余的动态方法。正因为这样,动态方法比虚拟方法用的内存要少,但执行起来较慢,因为有可能 
要到祖先对象的DMT中查找动态方法。 

4. 消息处理方法 
IAmAMessage 是一个消息处理方法,在关键字message后面的值指明了这个方法要响应的消息。 
用消息处理方法来响应Windows的消息,这样就不用直接来调用它   
    
      5. 方法的覆盖 
在Object Pascal覆盖一个方法用来实现OOP的多态性概念。通过覆盖使一方法在不同的派生类间 
表现出不同的行为。Object Pascal中能被覆盖的方法是在声明时被标识为virtual或dynamic的方法。为 
了覆盖一个方法,在派生类的声明中用override代替virtual或dynamic。例如,能用下面的代码覆盖 
IAmAVirtual和IAmADynamic方法: 

TFooChild = class(TFoo) 
procedure IAmAVirtual; override; 
procedure IAmADynamic; override; 
procedure IAmAMessage(var M:TMessage); message wm_SomeMessage; 
end; 

用了override关键字后,编译器就会用新的方法替换VMT中原先的方法。如果用virtual或dynamic替换 
override重新声明IAmAVirtual和IAmADynamic,将是建立新的方法而不是对祖先的方法进行覆盖。同样, 
在派生类中如果企图对一个静态方法进行覆盖,在新对象中的方法完全替换在祖先类中的同名方法。 

6. 方法的重载 
就像普通的过程和函数,方法也支持重载,使得一个类中有许多同名的方法带着不同的参数表, 
能重载的方法必须用overload指示符标识出来,可以不对第一个方法用overload。下面的代码演示了一 
个类中有三个重载的方法: 

type 
TSomeClass = class 
procedure AMethod(I:Integer); overload; 
procedure AMethod(I:String); overload; 
procedure AMethod(I:Double); overload; 
end; 

7. 重新引入方法名称 
有时候,需要在派生类中增加一个方法,而这个方法的名称与祖先类中的某个方法名称相同。在 
这种情况下,没必要覆盖这个方法,只要在派生类中重新声明这个方法。但在编译时,编译器就会发 
出一个警告,告诉你派生类的方法将隐藏祖先类的同名方法。要解决这个问题,可以在派生类中使用 
reintroduce指示符,下面的代码演示了reintroduce指示符的正确用法: 
type 
TSomeBase = class 
procedure Cooper; 
end; 
TSomeClass = class(TSomeBase) 
procedure Cooper; reintroduce; 
end; 

8. Self 
在所有对象的方法中都有一个隐含变量称为Self,Self是用来调用方法的指向类实例的指针。Self 
由编译器作为一个隐含参数传递给方法


--数据库存取图片方法:

procedure TForm1.Button1Click(Sender: TObject); 
var 
  Op: TOpenDialog; 
  jpg:TJPEGImage; 
  msmem:TmemoryStream; 
begin 
  Op:= TOpenDialog.Create(Self); 
  jpg:=TJPEGImage.Create; 
  msmem:= TmemoryStream.Create; 
  Op.Filter:= '图像文件|*.jpg'; 
  if Op.Execute then 
  begin 
    Image1.Picture.LoadFromFile(Op.FileName); 
    jpg.LoadFromFile(Op.FileName); 
    jpg.SaveToStream(msmem); 
    ADOTable1.Insert; 
    TBlobField(ADOTable1.FieldByName('image')).LoadFromStream(msmem); 
    ADOTable1.Post; 
  end; 
end; 


procedure TForm1.Button2Click(Sender: TObject); 
var 
  jpg:TJPEGImage; 
  ms:TMemoryStream; 
begin 
  jpg:=TJPEGImage.Create; 
  ms:=TMemoryStream.Create; 
  TBlobField(ADOTable1.FieldByName('image')).SaveToStream(ms); 
  ms.Position :=0;   // 将MS的指针置0,否则出现JPEG ERROR #42的错误 
  jpg.LoadFromStream(ms); 
  Image1.Picture.Assign(jpg); 


end; 

 

9、调用系统软键盘、计算器

uses ShellAPI;

shellexecute(0,'open','osk',nil,nil,sw_normal);

打开系统自带软键盘;

uses Windows;

winexec('calc.exe',sw_normal);

打开系统自带计算器

 


10、类型转换

function BytesToHex(PB:PByte;len:Integer ):string ;
var
   x:string;
begin
   setlength(x,len*2);
   bintoHex(PB,pchar(x),len);
   Result:=x;
end;
procedure HexToBytes(Hex:string;PB:PBYTE;Len:Integer );
var
   x:pchar;
begin
    x:=PChar(hex);
    if(length(x)< len) then len:= length(x) mod 2;
    hextobin(PChar(x),PB,len);
end;

function BytesToStr(PB:PByte;Len:Integer ):string;
var
   X:ansistring;
begin
   SetLength(x,Len );
   CopyMemory(@x[1],pb,len);
   result:=x;
end;
procedure StrToBytes(Str:string;PB:PByte );
var
  pc:PChar;
begin
   pc:=PChar(Str);
   pb:=pByte(pc);
end;



 

给字符指针(PChar、PWideChar、PAnsiChar)分配内存, 最佳选择是: StrAlloc 
 StrAlloc 虽然最终也是调用了 GetMem, 但 StrAlloc 会在指针前面添加 Delphi 需要的 4 个管理字节(记录长度).

StrAlloc 分配的内存, 用 StrDispose 释放, 用 StrBufSize 获取大小.

用 FreeMem 释放可以吗? 这样会少释放 4 个字节.

这种类型的指针一般用于 API 函数的参数, 譬如获取窗口标题:
--------------------------------------------------------------------------------
 
var
  p: PChar;
begin
  p := StrAlloc(256);
  GetWindowText(Handle, p, StrBufSize(p));
  ShowMessage(p); {Form1}
  StrDispose(p);
end;

 

原创粉丝点击