Delphi 2009测试版的新语法特性

Posted by admin on July 2nd, 2009
String的变化与增强了的Exit

为全面支持Unicode,Delphi 2009中的所有跟String相关的部分都由原来的AnsiString变成了UnicodeString。这自然也就意味着,原来一些用String声明的函数现在可能会有一些问题(好在我都不厌其烦的用AnsiString和WideString)。这同时意味着Char已经是WideChar而不再是AnsiChar、PChar也是PWideChar而不再是PAnsiChar了。在使用D2009编程时一定要时刻小心和注意这个地方。

而Exit则变成了类似C的return的作用,不过退出参数是可选的,这样才能兼容以前的代码和Result关键字。虽然说这是一个小改进,但是减少了每次不厌其烦的

if(not True)then
begin
    Result  := nil;
    Exit;
end;

而只需

if(not True)then Exit(nil);

即可了。

匿名方法引用(reference to)

以前我们创建一个方法引用的时候会很麻烦,尤其是在类中,需要跳出去在别的地方写一段函数,然后再回来继续写。新的语法reference to避免了这种情况的发生,尤其是许多时候其实我们的方法实际上只有一两句的时候,它可以大大加快开发的速度,就像前面的Exit语法加强一样贴心。不过遗憾的是,这个类lamda方法的语法糖还不够甜。

type
  TFoo = reference to function(num: Integer): Integer; // reference to Method
var
  func: TFoo;
  n: Integer;
begin
  func := function(a: Integer): Integer // *NOTE*: Do NOT Write ‘;’
begin
    Result := a * a;
end;
  n := func(10);

增强了的反射单元ObjAuto

这个是RTTI里的,按说不算语法上的更新,但涉及到编译器,又在RTTI方面非常有用,所以这里我还是把它拿出来说了。看过李维的《Inside VCL》的应该都知道TypInfo单元在RTTI中的重要性,而ObjAuto可以说是TypInfo的增强版。

先来点儿预备知识:一般情况下,class声明中的默认区域是public,但TPersistent指定了{$M+}编译器参数,使得包括其继承类(所有VCL控件)的默认区域都成为了published。以前我们可以通过TypInfo获取published区域的方法信息,成为了许多控件自动化功能的重要组成部分。而在2009中又增加了{$METHODINFO ON}/ {$METHODINFO OFF}编译器选项,使ObjAuto单元能够获取public区域中的方法信息。具体的示例请看这个链接:http://www.cnblogs.com/del/archive/2008/08/16/1269359.html

泛型

终于到了最激动人心、让人欢喜让人忧的泛型了。大家都知道C++难,异常难,用了十几二十年的人严谨点儿的话也不敢说自己非常懂C++。除了各种cast、实例的创建外,操作符的重载、泛型的支持使得C++变成一个自由度极高的语言,而复杂度也因此上了一个量级。有人说C++的精华就在于Templates,也就是泛型的支持,以我对C++的浅见,窃以为此话还是有一定道理的。在Delphi引入泛型的支持后(还好Delphi的操作符是关键字比较多,不适合重载),许多人担心的是,编译速度会不会变慢。在用了D2009beta版之后,至少目前几个测试项目还体会不到速度的明显降低,好在Delphi里没有C/C++那么复杂的预编译宏。不过就我目前的测试来看,Delphi 2009对泛型的支持还不是那么好,比如class<T>中内嵌type定义record中如果使用了类型为T的泛型成员的话,编译是会挂掉的。虽说有还不算太麻烦的用class代替并且不用默认方式的构架/析构过程的trick来避免这一问题(直接用class模拟record会导致如泛型包含string之类时会发生leak),但不够强大的泛型支持还是比较麻烦的事。

泛型的语法并不复杂,类似C++,在元素名称后使用“<>”包围泛型列表,如“Arr<T>=Array of T”“<TA, TB>”等,在其对应的作用域中可见。可以使用泛型的只有两种情况,一种是新定义一种类型的时候,这个类型可以是record、class、interface、array等,另外一种情况是一个class的方法、类方法可以单独定义泛型,但普通函数/过程不能定义泛型。这里就不具体举例了,有兴趣的可以参考Delphi 2009中自带的Generics.Collections单元中的几个基本类型。

其他

由于对Unicode支持是一个大局大变化,所以由此带来的Windows单元、VCL组件单元带来的变化也不小,其他相关的支持单元也加入了许多元素和进行了一些较大的调整。比如新加入的TEncoding和对TStrings、TStream系列的增强,以及TStringBuilder这种.Net中的概念元素等。还有一些变化使得以前版本的控件无法很方便的移植到D2009中,而Delphi如果缺少第三方组件的支持,可以说吸引力会大打折扣。

对于IDE等方面的变化和VCL控件方面的改进等这里就不介绍了。总之,非常期待正式版的出现,这是Delphi近年来最值得期待的一个版本。同时,Delphi 2009正式版中对泛型的支持我仍然要打一个问号,不知能否改进对使用泛型的class内部record的支持,或者出于编译速度的考虑无法达到十全十美,但愿今天的CodeGear会有一个更令人满意的答复。

  • Share/Save/Bookmark

Delphi 7以来的新语法特性

Posted by admin on July 2nd, 2009
内联函数(Inlining)

D7中的inline关键字作为保留字并不会对编译器产生实际作用,在2009中此关键字起到内嵌到代码中起到实际作用。语法如下:

function foo: Integer; inline;

内部函数/过程也可以使用,但在D2009测试版中,类方法的内部函数使用inline后不认Self指针;类的子过程/子函数,也可以使用inline关键字,但没有实际效果,且虚方法/继承方法(virtual/override)不能使用。

重载运算符(Operator Overloading)

可以重载部分运算符,如+、-、类型转换等,在D2006只支持到record,但从2007开始支持到Class,以下示例修改自官网:

    TMyClass = class
// Addition of two operands of type TMyClass
class operator Add(a, b: TMyClass): TMyClass; 
// Subtraction of type TMyClass
class operator Subtract(a, b: TMyClass): TMyclass; 
// Implicit conversion of an Integer to type TMyClass
class operator Implicit(a: Integer): TMyClass; 
// Implicit conversion of TMyClass to Integer
class operator Implicit(a: TMyClass): Integer; 
// Explicit conversion of a Double to TMyClass
class operator Explicit(a: Double): TMyClass;  
end
class operator TMyClass.Add(a, b: TMyClass): TMyClass; 
begin
//…
end
var
    x, y: TMyClass 
begin
    x := 12; // Implicit conversion from an Integer
    y := x + x; // Calls TMyClass.Add(a, b: TMyClass): TMyClass
end;

类助手(Class Helpers)

Helper是对原Class的扩展,是我们在不修改原类的基础上增加类方法,并加入原类的空间中。在Delphi中,对对象的调用实际上采用了两个步骤,首先是把对象地址放入eax寄存器中,然后call类方法,所以如果不使用继承类增加数据的话,用父类调用继承类的方法是没问题的,所以其实这样的方法在D7中也可以使用,但却很麻烦。所以Class Helper起到的就是这个作用,在Class Helper中可以增加的就是与实例无关的内容,所以任何需要增加实例Size的活VMT的功能不能声明,例如变量、虚方法等,但只占用类空间的没关系,如class var。在应用上我们可以通过这种方法方便的给VCL一类控件加上某个属性。

  TFoo = class helper for TControl 
private
function GetA: Integer; 
public
class var X: Integer; 
procedure MSG(var Message: TMessage); message WM_MYMESSAGE; 
procedure ProcFoo; 
property A: Integer read GetA; 
end;
// …
procedure TForm1.Foofoo;
begin
    ProcFoo; // TControl -> TWinControl -> TScrollingWinControl-> TCustomForm -> TForm -> TFrom1: Call TFoo.ProcFoo
end;

strict关键字(Keyword “strict”)

众所周知,在Delphi中,类的private和protected域中的变量可以被同一单元中可以自由的被访问(Delphi的类没有“友元”的概念,但同一个unit中可以说自动友元化了),而并非是真正的私有或只能被继承类访问。而strict关键字的作用就是使该内容变成严格OO意义上的private/protected作用域,这点没有什么多说的。语法:

strict private

// Blah…

strict protected

// Blah…

结构方法(Records with Methods)

也没什么特别的,就是和class差不多,就一个不用创建和销毁、不能继承、没有作用域之类的类,很容易掌握,所以这里就不多介绍了。但是很有意思的是带参数的constructor可以通过编译,可能是为了初始化的方便吧。

抽象类和固实类(Abstract and Sealed Classes)

这两个概念在OO中也并不陌生,抽象类是不应该创建实例的(但D2006起的编译器就不给检查,连个Warning都没有,这还有啥用啊 -.- ),而固实类是不能被继承的。语法:

TAnAbstractClass = class abstract // or (TParentClass)

// Blah…

end;

TASealedClass = class sealed(TAnAbstractClass) // or empty

// Blah…

end;

类常量、类变量、类属性与静态类方法(Class const/var/property and Static Class Methods)

老的Delphi中只提供了类方法,而没有提供类变量、类常量和类属性,这真的是很不方便。这里先区分一下我所使用的类(Class)和对象(Object)即类的实例(Instance of Class)。当在Delphi中声明一个类的时候,这个类是有实际地址的,该地址记录了许多类的相关信息,比如实例的Size啊、虚方法信息啊一堆东西,而创建一个对象的时候则把类实例化,在堆(Heap)中分配一块地址,包括内部数据和VMT之类的东西。在调用实例的时候,首先要知道对象地址,然后才能访问内部变量和调用方法时使用Self指针即实例地址;而在调用类方法的时候,eax中的并不是实例的地址而是类的地址,然后再call方法,这时的Self指针并非实例地址而是类地址。所以对于每一个类和继承类来说,包括它和它的继承类的所有实例,类变量、常量都是同一个,这样就存在了一个唯一的可供使用的变量或常量,方便同步并且不需要使用较多的内存(可以参考C#中的类,不过C#中不允许从实例直接访问类变量、常量、方法)。而静态类方法则是在使用这个类方法的时候不传入class地址,也就是说没有Self指针,这样的类方法的访问开销要小于普通的类方法;这自然也就意味着,该类方法不能被继承(不能virtual/override)。另外,类属性的get/set方法必须使用静态类方法。

TFooClass = class
private
class procedure SetFoo(const Value: Integer); static; // A Static Class Method
protected
class var FX : Integer; // class var
public
const FC: Integer = 10; // class const
class procedure VirtualProc; virtual;
class property X: Integer read FX write FX; // class property
class property Foo: Integer read FC write SetFoo;
end;

类内部类型与嵌套类(Class Types and Nested Classes)

可以说现在的Class的域几乎相当于原来的整个unit,以前不能放里面的元素现在都可以放里面了,这个也没什么好多说的,试验一下就很容易明白了。

终方法(Final Methods)

这个也是建立在虚方法的基础上的,在override后使用final关键字,则表示该虚方法不能再被子类继承下去了。

  TAClass  = class
public
procedure Foo; virtual;
end;
  TFinalMethodClass  = class(TAClass)
public
procedure Test; override; final; // A Final Method
end;

For-in循环(For-in Loop)

这个应该是受.Net影响吧,支持遍历一个数组或提供了GetEnumerator函数的类。GetEnumerator要求返回一个类的实例,该类包含有Current属性和MoveNext方法。

procedure Foo(List: TStrings);
  i : Integer;
  lst : array[0..100]of Integer;

  s : string;
begin
for i in lst do ;

for s in List do ; // Support of TStrings.GetEnumerator

end;

  • Share/Save/Bookmark

New Delphi language features since Delphi 7

Posted by admin on July 2nd, 2009

By: Nick Hodges

Abstract: See many of the major new language features in Delphi released after the Delphi 7 version

Language and Compiler Features Since Delphi 7

Inlining
Routines can now be marked with the inline directive.  This tells the compiler that, instead of actually calling the routine, it should emit code that includes the routine at the call site.

Operator Overloading

Delphi allows certain functions, or operators, to be overloaded within record declarations

TMyClass = class
    class operator Add(a, b: TMyClass): TMyClass; // Addition of two operands of type TMyClass
    class operator Subtract(a, b: TMyClass): TMyclass; // Subtraction of type TMyClass
    class operator Implicit(a: Integer): TMyClass; // Implicit conversion of an Integer to type TMyClass
    class operator Implicit(a: TMyClass): Integer; // Implicit conversion of TMyClass to Integer
    class operator Explicit(a: Double): TMyClass; // Explicit conversion of a Double to TMyClass
end;

// Example implementation of Add class operator 
TMyClass.Add(a, b: TMyClass): TMyClass;
begin
  ...
end;

var
x, y: TMyClassbegin
  x := 12; // Implicit conversion from an Integer 
  y := x + x; // Calls TMyClass.Add(a, b: TMyClass): TMyClass 
  b := b + 100; // Calls TMyClass.Add(b, TMyClass.Implicit(100)) 
end;

Class Helpers

A class helper is a type that – when associated with another class – introduces additional method names and properties which may be used in the context of the associated class (or its descendants). Class helpers are a way to extend a class without using inheritance. A class helper simply introduces a wider scope for the compiler to use when resolving identifiers. When you declare a class helper, you state the helper name, and the name of the class you are going to extend with the helper. You can use the class helper any place where you can legally use the extended class. The compiler’s resolution scope then becomes the original class, plus the class helper. Class helpers provide a way to extend a class, but they should not be viewed as a design tool to be used when developing new code. They should be used solely for their intended purpose, which is language and platform RTL binding.

type
  TMyClass = class

    procedure MyProc;
	function  MyFunc: Integer;
  end;

   ...

   procedure TMyClass.MyProc;
   var
	 X: Integer;
   begin
	  X := MyFunc;
   end;

   function TMyClass.MyFunc: Integer;
   begin
	   ...
   end;

...

type
   TMyClassHelper = class helper for TMyClass
	 procedure HelloWorld;
	 function MyFunc: Integer;
   end;

   ...

   procedure TMyClassHelper.HelloWorld;
   begin
	 WriteLn(Self.ClassName); // Self refers to TMyClass type, not TMyClassHelper

   end;

   function TMyClassHelper.MyFunc: Integer;
   begin
	 ...
   end;
...

var
  X: TMyClass;
begin
  X := TMyClass.Create;
  X.MyProc;    // Calls TMyClass.MyProc
  X.HelloWorld; // Calls TMyClassHelper.HelloWorld
  X.MyFunc; // Calls TMyClassHelper.MyFunc

end;

strict private

The private keyword actually creates a " friendship" relationship between classes in the same unit.  The strict private declaration creates a true private field, not viewable by any other class, not even classes in the same unit.

strict protected

Similar to the strict private declaration, strict protectedcreates a true protected member, visible only to the declaring class and its descendents.

Records with Methods

In addition to fields, records now may have properties and methods (including constructors), class properties, class methods, class fields, and nested types. 

type
  TMyRecord = record
    type
      TInnerColorType = Integer;
    var
      Red: Integer;
    class var
      Blue: Integer;
    procedure printRed();
    constructor Create(val: Integer);
    property RedProperty: TInnerColorType read Red write Red;
    class property BlueProp: TInnerColorType read Blue write Blue;
  end;

constructor TMyRecord.Create(val: Integer);
begin
  Red := val;
end;

procedure TMyRecord.printRed;
begin
  writeln('Red: ', Red);
end;

class abstract

Classes, and not just methods, can be declared as abstract.

type
  TAbstractClass = class abstract
    procedure SomeProcedure;
end;

class sealed

Classes marked as sealed cannot be inherited from.

type
  TAbstractClass = class sealed
    procedure SomeProcedure;
end;

class const

Classes can now have class constants — a constant value associated with the class itself and not an instance of the class.

type
  TClassWithConstant = class
    public
      const SomeConst = 'This is a class constant';
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ShowMessage(TClassWithConstant.SomeConst);
end;

class type

A class can now contain a type declaration that is usable only within that class.

type
  TClassWithClassType = class
  private
	type
	  TRecordWithinAClass = record
	  SomeField: string;
	end;
  public

	    class var
	  RecordWithinAClass: TRecordWithinAClass;
  end;
  ...
procedure TForm1.FormCreate(Sender: TObject);
begin
  TClassWithClassType.RecordWithinAClass.SomeField := 'This is a field of a class type declaration';
  ShowMessage(TClassWithClassType.RecordWithinAClass.SomeField);
end;

class var

A class can also have a class variable, applicable only to the class and not an instance of the class. See "class type" for an example.

class property

A class can have a class property, which is a property that applies only to the class reference and not to an instance of a class.  The accessors for the class property must be either class methods or class variables. See the example in "static class methods" below.

nested classes

Type declarations can be nested within class declarations. They present a way to keep conceptually related types together, and to avoid name collisions.

type
  TOuterClass = class
  strict private
	MyField: Integer;
  public
	type
      TInnerClass = class
	  public
        MyInnerField: Integer;
		procedure InnerProc;
      end;
      procedure OuterProc;
  end;

procedure TOuterClass.TInnerClass.InnerProc;
begin
  ...
end;

final methods

A virtual method that you override can now be marked final, preventing derived classes from overriding that method.

TAbstractClass = classabstract
  public
    procedure Bar; virtual;
  end;

  TSealedClass = classsealed(TAbstractClass)
  public
    procedure Bar; override;
  end;

  TFinalMethodClass = class(TAbstractClass)
  public
    procedure Bar; override; final;
  end;

sealed methods

Classes marked as sealed cannot be descended from. See the example in ‘final methods’.

static class methods

Classes can have static class methods — i.e. methods that can be called from a class type. Class static methods can be accessed without an object reference. Unlike ordinary class methods, class static methods have no Self parameter at all. They also cannot access any instance members. (They still have access to class fields, class properties, and class methods.) Also unlike class methods, class static methods cannot be declared virtual.

type
  TMyClass = class
    strict private
      class var
        FX: Integer;
    strict protected  

    // Note: accessors for class properties must be declared class static.

      class function GetX: Integer; static;
	  class procedure SetX(val: Integer); static;
    public
      class property X: Integer read GetX write SetX;
	  class procedure StatProc(s: String); static;
  end;

TMyClass.X := 17;
TMyClass.StatProc('Hello');

for-in loop

Delphi 2007 for Win32 supports for-element-in-collection style iteration over containers. The following container iteration patterns are recognized by the compiler:

  for Element in ArrayExpr do Stmt;
  for Element in StringExpr do Stmt;
  for Element in SetExpr do Stmt;
  for Element in CollectionExpr do Stmt;
  • Share/Save/Bookmark

純ASP上傳圖像文件到數據庫的最佳例子

Posted by on June 15th, 2009

IAmTrue 發表於2000-11-2 7:56:49 ASP地帶

getfile.htm
————————-
<html>

<head>
<title>保存圖片到數據庫</title>
</head>

<body>
<b>

<p></b>你可以找個圖片試試,保存完畢後會有提示</p>

<form METHOD="POST" ENCTYPE="multipart/form-data" ACTION="savetodb.asp">
<p>Email : <input NAME="email" VALUE="wangcq@sina.com" size="20"><br>
Picture : <input TYPE="file" NAME="blob"><br>
<input TYPE="submit" NAME="Enter"> </p>
</form>
</body>
</html>

savetodb.asp
———————————-
<%

Response.Buffer = TRUE
Response.Clear
byteCount = Request.TotalBytes

RequestBin = Request.BinaryRead(byteCount)
Dim UploadRequest
Set UploadRequest = CreateObject("Scripting.Dictionary")

BuildUploadRequest RequestBin

email = UploadRequest.Item("email").Item("Value")

contentType = UploadRequest.Item("blob").Item("ContentType")
filepathname = UploadRequest.Item("blob").Item("FileName")
filename = Right(filepathname,Len(filepathname)-InstrRev(filepathname,"\"))
picture = UploadRequest.Item("blob").Item("Value")

‘Response.ContentType = contentType
‘Response.binaryWrite picture

set objCn = server.createobject("adodb.connection")
set objRst = server.createobject("adodb.recordset")
objCn.Open "upload"
objrst.Open "pic", objcn, 1,3,2
objrst.addnew
objrst.fields("filename")=filename
objrst.fields("type")="gif"

objrst.fields("what").appendchunk picture
objrst.update
response.write "<a href=showpic.asp?id=" & objrst("id") & ">第" & objrst("id") & "個圖片。</a>"
objrst.close

objCn.close
set objrst=nothing
set objcn = nothing
%>
<!–#include file="upload.asp"–>

showpic.asp
—————————————-
<%
set objCn = server.createobject("adodb.connection")
set objRst = server.createobject("adodb.recordset")
objCn.Open "upload"
objrst.Open "select what from pic where id=" & request("id"), objcn

if not objrst.eof then
response.binarywrite objrst("what")
end if

objrst.close
objCn.close
set objrst=nothing
set objcn = nothing
%>

upload.asp
——————————————-
<%
Sub BuildUploadRequest(RequestBin)
‘Get the boundary
PosBeg = 1
PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(13)))
boundary = MidB(RequestBin,PosBeg,PosEnd-PosBeg)
boundaryPos = InstrB(1,RequestBin,boundary)
‘Get all data inside the boundaries
Do until (boundaryPos=InstrB(RequestBin,boundary & getByteString("–")))
‘Members variable of objects are put in a dictionary object
Dim UploadControl
Set UploadControl = CreateObject("Scripting.Dictionary")
‘Get an object name
Pos = InstrB(BoundaryPos,RequestBin,getByteString("Content-Disposition"))
Pos = InstrB(Pos,RequestBin,getByteString("name="))
PosBeg = Pos+6
PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(34)))
Name = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))
PosFile = InstrB(BoundaryPos,RequestBin,getByteString("filename="))
PosBound = InstrB(PosEnd,RequestBin,boundary)
‘Test if object is of file type
If PosFile<>0 AND (PosFile<PosBound) Then
‘Get Filename, content-type and content of file
PosBeg = PosFile + 10
PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(34)))
FileName = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))
‘Add filename to dictionary object
UploadControl.Add "FileName", FileName
Pos = InstrB(PosEnd,RequestBin,getByteString("Content-Type:"))
PosBeg = Pos+14
PosEnd = InstrB(PosBeg,RequestBin,getByteString(chr(13)))
‘Add content-type to dictionary object
ContentType = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))
UploadControl.Add "ContentType",ContentType
‘Get content of object
PosBeg = PosEnd+4
PosEnd = InstrB(PosBeg,RequestBin,boundary)-2
Value = MidB(RequestBin,PosBeg,PosEnd-PosBeg)
Else
‘Get content of object
Pos = InstrB(Pos,RequestBin,getByteString(chr(13)))
PosBeg = Pos+4
PosEnd = InstrB(PosBeg,RequestBin,boundary)-2
Value = getString(MidB(RequestBin,PosBeg,PosEnd-PosBeg))
End If
‘Add content to dictionary object
UploadControl.Add "Value" , Value
‘Add dictionary object to main dictionary
UploadRequest.Add name, UploadControl
‘Loop to next object
BoundaryPos=InstrB(BoundaryPos+LenB(boundary),RequestBin,boundary)
Loop

End Sub

‘String to byte string conversion
Function getByteString(StringStr)
For i = 1 to Len(StringStr)
char = Mid(StringStr,i,1)
getByteString = getByteString & chrB(AscB(char))
Next
End Function

‘Byte string to string conversion
Function getString(StringBin)
getString =""
For intCount = 1 to LenB(StringBin)
getString = getString & chr(AscB(MidB(StringBin,intCount,1)))
Next
End Function
%>

test.mdb(dsn 名稱:upload)
—————————————-
表pic:
id:自動加
filename:文本
type:文本
what:ole

—————————————–
存成單個文件,放在一個目錄下,打開(必須用http://…)getfile.htm
上傳一個.gif或.jpg就可以顯示了。
對於大文件在顯示程序(showpic.asp)中可能會用到循環和getchunk方法。自己去做。記住,由於ASP目前暫時不支持二進行制讀寫,只能存二進制到數據庫中。
有什麼問題,請致電veryblue@chinese.com (IAmTrue)
—————————————————————–

  • Share/Save/Bookmark

用 cairo 实现跨平台图形-用于产生一致输出的矢量绘图库

Posted by on June 5th, 2009

Eli Dow (emdow@us.ibm.com), 软件工程师, IBM Linux Test and Integration Center

2007 年 9 月 24 日

    cairo 的目标是以跨平台的方式在打印机和屏幕上产生相同的输出,它正在成为 Linux® 图形领域的重要软件。GNOME、GTK+、Pango 等许多软件已经使用了它提供的 2D 功能。

cairo 的优点和用途

cairo 是一个免费的矢量绘图软件库,它可以绘制多种输出格式。cairo 支持许多平台,包括 Linux、BSD、Microsoft® Windows® 和 OSX(BeOS 和 OS2 后端也正在开发)。Linux 绘图可以通过 X Window 系统、Quartz、图像缓冲格式或 OpenGL 上下文来实现。另外,cairo 还支持生成 PostScript 或 PDF 输出,从而产生高质量的打印结果。在理想情况下,cairo 的用户可以在打印机和屏幕上获得非常接近的输出效果。

本文将向您介绍 cairo,以及它对应用程序的意义。本文的示例将产生一个 pdf、ps、png、svg 和 gtk 窗口,显示的图形是 IBM 徽标。

cairo 的一项主要设计目标是提供尽可能接近的输出。这种一致的输出使 cairo 非常适合 GUI 工具集编程和跨平台应用程序开发。使用同一个绘图库打印高分辨率的屏幕和绘制屏幕内容,这种功能具有显著的优点。

另外,在支持的每种目标平台上,cairo 尝试智能化地使用底层硬件和软件支持。高质量矢量图形和高性能的结合使 cairo 成为优秀的 UNIX® 绘图系统。

cairo 是用 C 编写的,但是为大多数常用的语言提供了绑定。选用 C 语言有助于创建新的绑定,同时在进行 C 语言调用时可以提供高性能。应该特别注意 Python 绑定,它支持快速原型开发,而且降低了学习 cairo 绘图 API 的门槛。
   
矢量绘图与位图绘图

cairo 是一个矢量绘图(vector drawing)库,因此绘图需要对图形进行几何描述,而不是描述位图中填充的像素。在采用位图绘图(bitmap drawing)时,按照预先决定的布局用预先决定的颜色填充一系列像素,而且图形的质量与位图的大小成正比。

在放大或修改位图图像时,位图绘图方法的效果就会变差。图像常常会变得模糊,就像是近距离观看背投电视或其他大屏幕电视时的效果。在某一距离上,图像可能看起来很清楚,但是靠近之后就会看到许多离散的点。因为数据无法定义预先定义的像素之间应该是什么,所以放大时会很明显地损失清晰度。

计 算机绘图系统和体系结构很早就出现了,cairo 的设计借鉴了 PostScript 和 PDF 模型的许多经验。cairo 之所以借鉴 PostScript 和 Portable Document Format(PDF)方法是因为,它们都使用数学语句定义图像。由于用几何方法表示图像,所以可以在任何时候在一定范围内计算几何描述,从而重新创建整个图像(或一部分图像)。图形的几何性质被表示为点、曲线和直线(这些元素构成了矢量)。

因为可以通过重新计算数学描述来重新绘制图像或其组成部分,所以在对图像进行放大、缩小或变换时不会出现分辨率损失。但是,矢量绘图也有一些限制。例如,如果对矢量图像进行极高比例的缩放,超出了大多数人实际需要的范围,就可能导致失真。在放大时,由于计算中要对误差进行舍入,所以某些直线可能看起来不正确。在缩小时,某些直线可能会无法看到或难以分辨。

cairo 采用矢量绘图还有一个优点:矢量图像往往比较小。这是因为用相当简单的数学表达式就可以表达大量信息。矢量绘图的优点是绘图过程相当简单。由绘图库负责将点、线以及相关表达式转换为用户可以看到的东西。

描述曲线的表达式称为 Bezier 曲线或路径,这个名称源自数学家 Pierre Bezier。Bezier 曲线由至少两个锚点(anchor point)组成,在锚点之间还有一个或多个点,这些点称为控制点(handle)。移动控制点就可以改变曲线的形状。如果您用过 Photoshop 或 GIMP 这样的工具,那么可能熟悉这种曲线。但是,在使用那些工具时,最终保存的图形格式可能是位图!文件的格式决定是否保留 Bezier 路径信息,还是在给定的范围内计算它并以位图格式保存计算结果。

到编写本文时,可用的 cairo 绑定包括 C++、Ruby、Perl、Java™ 语言和 .Net/mono 等等。这些绑定处于不同的开发状态,成熟度各不相同;可以通过 cairo 项目主页了解它们的最新情况(见 参考资料 中的链接)。目前,Python 和 C++ 绑定似乎在开放源码社区中得到了广泛采用。

正 如前面提到的,一些图形工具集也为 cairo 提供了绑定,这使 cairo 开发更加简便了。2.8 之后的 Gtk+ 版本包含对 cairo 的完整支持,而且以后的 GTK 版本一直选用 cairo 作为基本绘图系统。另外,GNUstep 和 FLTK 等工具集已经开始支持用 cairo 来满足图形呈现需求。

如果您打算进行任何跨平台开发,而且需要对绘图操作和组合进行低层控制,那么选用 cairo 作为绘图 API 是非常合适的。如果需要跨平台功能,但是不需要低层绘图控制,那么可以使用在 cairo 之上构建的一些绘图库。

    回页首

为什么要学习一种新的绘图模型?

坦 率地说,我认为目前的开放源码解决方案在几个方面存在欠缺。xprint 的优点是提供了统一的显示和打印 API,但是它通常作为单独的服务器进程运行,而且它的 API 很糟糕。libgnomeprint 提供单独的打印和显示模型,但是打印和绘图 API 的分离使屏幕和打印机的呈现效果产生差异。

cairo 从以前的绘图库借鉴了许多经验,而且从一开始就以实现统一 API 为设计目标。

    回页首

cairo 呈现目标

cairo 可以呈现以下输出格式:

    * X Window System(如果可能的话,会利用 Render 扩展)
    * OpenGL(使用 glitz 后端)
    * In-Memory Images(pixbuffs 等等)
    * PostScript(适用于打印)
    * PDF(Portable Document Format)文件
    * SVG(Scalable Vector Graphics)格式

但是,并非所有呈现目标都产生相同的效果。尽管 cairo 力求在各种后端上产生相同的输出,但是每种后端各有优势。例如,PDF 后端会尽可能使用矢量计算(只在必要时生成图像),而 PostScript 后端实际上会为每个页面生成一个大图像。

cairo 中的呈现模型受到许多原有技术的影响。cairo 采用了 PostScript 中的路径、笔画(stroke)和填充(fill)概念,还实现了 PDF 和现代 X 服务器实现的呈现扩展中的 Porter-Duff 图像组合技术。另外,cairo 还实现了剪切、蒙板和渐变等补充特性。

    回页首

cairo 的实际应用情况

许多有影响力的开放源码项目已经采用了 cairo,cairo 已经成为 Linux 图形领域的重要软件。已经采用 cairo 的重要项目包括:

    * Gtk+,一个广受喜爱的跨平台图形工具集
    * Pango,一个用于布置和呈现文本的免费软件库,它主要用于实现国际化
    * Gnome,一个免费的桌面环境
    * Mozilla,一个跨平台的 Web 浏览器基础结构,Firefox 就是在这个基础结构上构建的
    * OpenOffice.org,一个可以与 Microsoft Office 匹敌的免费办公套件

    回页首

用 cairo 进行概念性绘图

在用 cairo 进行绘图时,最简单的操作就像手工绘画时一样:选择绘图介质,选择画笔,选择颜色,考虑线条的布局,然后进行实际绘制。cairo 文档通过与画家的作画过程进行类比来介绍 cairo 操作,下面的说明也采用这种方式。

对 于画家来说,最容易的事儿通常是选择空白的绘图介质。在现实世界中,艺术家可以选择在纸上、画布上甚至墙上作画。在 cairo 中,也必须选择空白的绘图介质。在用 cairo 进行绘图时,需要设置一个 cairo 上下文,这是主对象。在这个上下文中,可以选择目标外表,比如 PostScript 文件、PDF 文档或屏幕图像。这样就可以选择我们要在什么东西上进行绘图。

现在考虑画家的下一项任务:选择画笔。画家往往花费相当长的时间来选择形状和大小合适的画笔。在 cairo 中,也有画笔形状的概念,这由笔画宽度来表达。不同的笔画宽度会产生不同粗细的线条。

接下来,cairo 用户需要以精确的坐标来表达绘图操作,这一点与现实世界中的绘画过程不同。艺术家只需将画笔放在纸上的大概位置,但是计算机必须知道进行绘图的 x 和 y 坐标。

设置了画笔和开始绘图的位置之后,就需要想像笔画的形状。简单的图形可能由直线组成,但是与现实的画家一样,也可以绘制曲线和弧线。

最后,必须定义笔画终止的位置。同样,这个位置也要用一对 (x,y) 坐标来指定。

另外,还可以给绘制的对象涂上颜色。按照 cairo 术语,这称为填充(fill)。对于上面描述的每种操作,cairo 中都有对应的简便的 API 实现。后面会介绍其中一些 API。

这些基本操作可以帮助您构建一些非常复杂的图形。甚至可以使用 cairo 执行画家无法轻松完成的工作,比如对现有的图形进行放大等转换,或者将图形移动到虚拟纸张上的其他地方。

GIMP 或 Photoshop 也允许执行其中的许多操作,但是 cairo 是不同的:cairo 是一种编程式绘图方式。GIMP 和 Photoshop “在幕后” 使用 cairo 这样的工具来实现绘图。在用这些工具进行绘图时,通过鼠标操作自动设置坐标点和工具类型(比如方框),并通过 GUI 环境选择画笔和笔画宽度。如示例代码所示(见 下载),cairo 需要显式的交互,比如 “使用笔画宽度 1 绘制一个弧线,半径为 10,中心在位置 z”。

    回页首

正确的 cairo 术语

在讨论任何技术时,都要使用正确的术语。cairo API 的术语分为三类:核心绘图术语、外表术语和与字体相关的术语(更多细节见 参考资料)。

首 先,cairo 有一个绘图上下文(drawing context),这相当于画家的画布。上下文是 cairo_t 类型的,要呈现图形,就必须有一个上下文。在绘图上下文上的常见操作是绘制 Bezier 图形、直线和曲线。表示一系列曲线和相关数据的 cairo 术语是路径(path)。可以绘制这些路径,并设置笔画宽度或填充。

使用一个非常简单的 API 将坐标转换为路径。这个 API 非常有意义,因为它使我们不必考虑线性代数或图形学课本中讨论的复杂的转换矩阵。可以对 cairo 绘图操作执行任何转换,包括对图形或部分图形进行剪切、缩放或旋转。通过指定点来绘制每条路径。cairo 按照将点连接起来的方法执行操作。在后面将提供一个示例。

接下来,讨论各种 cairo 外表类型。有几种 cairo 外表类型,它们分别对应一种输出目标。cairo 外表(surface)是执行绘图的位置。具体地说,有用于图像(内存缓冲区)的外表、用于 Open GL 的 glitz 外表、用于呈现文档的 PDF 和 PostScript 外表以及用于直接执行绘图的 XLib 和 Win32 外表。这些外表类型都派生自外表基类型 cairo_surface_t。

在 cairo 中,模式(pattern)是一种可以读取的内容,它用作绘图操作的源或蒙板。cairo 中的模式可以是实体模式、基于外表的模式甚至逐变模式。

到目前为止,我们只谈到了笔画路径。但是,笔画路径一般只能产生不怎么有趣的线条图。实际上,简单的线条笔画只是 cairo 中的 5 种基本绘图操作之一。这 5 种操作是:

    * cairo_stroke
    * cairo_fill
    * cairo_show_text/cairo_show_glyphs
    * cairo_paint
    * cairo_mask

尽 管简单的线条绘图很方便,但是它们的表达能力不够强,不足以表示字体这样的复杂图形。cairo 为字体提供了一个基类 cairo_font_face_t。cairo 支持可缩放字体,其中包含给定字体大小的缓存标准。另外,可以用各种字体选项控制如何显示给定的字体。在使用 cairo 时,在 UNIX 上常用的字体是 Freetype 字体,在 Windows 平台上使用 Win32 字体。

    回页首

cairo 示例应用程序

我编写了一段绘制 IBM 徽标的 cairo 代码。可以从下面的 下载 一节下载这段代码。运行它应该会产生以下输出:

图 1. 用 cairo 生成的 IBM 徽标
用 cairo 生成的 IBM 徽标

请注意代码中的 cairo_stroke (cr) 行,这一行出现在绘制字母之后,但在添加注册标志之前。如果不设置笔画,cairo 就不绘制任何东西。忘记设置笔画是初学者经常犯的错误。

    回页首

cairo 的发展过程

cairo 的版本号采用与 Linux 内核相似的规则 —— 也就是,奇数版本是实验性的开发版本,不适合在生产环境中使用。偶数版本是稳定版本:最初的 1.0 版本主要关注顺利地向用户提供 API 和产生高质量输出。1.2 API 完善了几个开发不太完整的后端,当前的 1.4 系列主要关注优化和添加新功能。

cairo 的开发人员提供了一些出色的示例代码片段,演示了 cairo API 的各种功能(见 参考资料 一节中的链接)。所以不必等待 cairo 的下一个版本了,现在就下载并试用当前版本!

    回页首

下载
描述     名字     大小     下载方法
绘制 IBM 徽标的 cairo 代码     cairo-example.tar     20KB     HTTP
    关于下载方法的信息    

参考资料

学习

    * 您可以参阅本文在 developerWorks 全球站点上的 英文原文。
      
    * cairo 图形项目 主页包含 cairo 用户手册 和演示 cairo API 各个部分的 代码片段 等内容。
      
    * 查阅 cairo 最新的语言和工具集绑定列表,包括用于 Objective Caml 和 GNUstep 的绑定。
      
    * 阅读 GNOME Journal 文章 “Writing a Widget Using Cairo and GTK+2.8”。
      
    * Technical Advisory Service for Images(TASI)提供了 常用矢量图形术语及解释。
      
    * 在 developerWorks Linux 专区 中可以找到为 Linux 开发人员准备的更多参考资料,还可以查阅 最受欢迎的文章和教程。
      
    * 随时关注 developerWorks 技术活动和网络广播。

获得产品和技术

    * 索取 SEK for Linux,共有两张 DVD,包含最新的 IBM Linux 试用版软件,涉及 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。
      
    * 使用 IBM 试用软件 构建您的下一个 Linux 开发项目,这些软件可以从 developerWorks 直接下载。
      

讨论

    * 通过参与 developerWorks blog 加入 developerWorks 社区。
      

关于作者
         

Eli Dow 是位于 Poughkeepsie, NY. 的 IBM Linux Test and Integration Center 的一名软件工程师。他拥有 Clarkson 大学的计算机科学和心理学学士学位,以及计算机科学硕士学位。他的兴趣包括 GNOME 桌面、人与计算机的交互以及 Linux 系统编程。您可以通过 emdow@us.ibm.com 与 Eli 联系。

 

  • Share/Save/Bookmark

StringGrid使用全书

Posted by on June 3rd, 2009

StringGrid行列的增加和删除
如何编写使StringGrid中的一列具有Check功能,和CheckBox效果一样
StringGrid组件Cells内容分行显示在Tstringgrid.ondrawcell事件中
在StringGrid怎样制作只读的列在 OnSelectCell事件处理程序中
stringgrid从文本读入的问题
StringGrid组件Cells内容对齐
StringGird的行列背景色设置
怎么改变StringGrid控件某一列的背景和某一列的只读属性
StringGrid控件标题栏的对齐
怎么改变StringGrid控件某一列的背景和某一列的只读属性
StringGrid控件标题栏的对齐
在stringGrid中使用回车键模拟TAB键切换单元格的功能实现
stringgrid如何清空
让记录在StringGrid中分页显示在
打印StringGrid
如何实现在stringgrid中删除鼠标点中的那一行,下一行再顶上的效果
让stringgrid点列头进行排序
正确地设置StringGrid列宽而不截断任何一个文字方法
实现StringGrid的删除,插入,排序行*作
TstringGrid 的行列合并研究

StringGrid行列的增加和删除

type
TExCell = class(TStringGrid)

public
procedure DeleteRow(ARow: Longint);
procedure DeleteColumn(ACol: Longint);
procedure InsertRow(ARow: LongInt);
procedure InsertColumn(ACol: LongInt);
end;

procedure TExCell.InsertColumn(ACol: Integer);
begin
ColCount :=ColCount +1;
MoveColumn(ColCount-1, ACol);
end;

procedure TExCell.InsertRow(ARow: Integer);
begin
RowCount :=RowCount +1;
MoveRow(RowCount-1, ARow);
end;

procedure TExCell.DeleteColumn(ACol: Longint);
begin
MoveColumn(ACol, ColCount -1);
ColCount := ColCount – 1;
end;

procedure TExCell.DeleteRow(ARow: Longint);
begin
MoveRow(ARow, RowCount – 1);
RowCount := RowCount – 1;
end;

如何编写使StringGrid中的一列具有Check功能,和CheckBox效果一样

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids;

type
TForm1 = class(TForm)
grid: TStringGrid;
procedure FormCreate(Sender: TObject);
procedure gridDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
procedure gridClick(Sender: TObject);

private
{ private declarations }

public
{ public declarations }

end;

var
Form1: TForm1;
fcheck,fnocheck:tbitmap;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
var
i:SmallInt;
bmp:TBitmap;
begin
FCheck:= TBitmap.Create;
FNoCheck:= TBitmap.Create;
bmp:= TBitmap.create;
try
bmp.handle := LoadBitmap( 0, PChar(OBM_CHECKBOXES ));
with FNoCheck do begin
width := bmp.width div 4;
height := bmp.height div 3;
canvas.copyrect( canvas.cliprect, bmp.canvas, canvas.cliprect );
end;
with FCheck do begin
width := bmp.width div 4;
height := bmp.height div 3;
canvas.copyrect(canvas.cliprect, bmp.canvas, rect( width, 0, 2*width, height ));
end;
finally
bmp.free
end;
end;

procedure TForm1.gridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
begin
if not (gdFixed in State) then
with TStringGrid(Sender).Canvas do
begin
brush.Color:=clWindow;
FillRect(Rect);
if Grid.Cells[ACol,ARow]=’yes’ then
Draw( (rect.right + rect.left – FCheck.width) div 2, (rect.bottom + rect.top – FCheck.height) div 2, FCheck )
else
Draw( (rect.right + rect.left – FCheck.width) div 2, (rect.bottom + rect.top – FCheck.height) div 2, FNoCheck );
end;
end;

procedure TForm1.gridClick(Sender: TObject);
begin
if grid.Cells[grid.col,grid.row]=’yes’ then
grid.Cells[grid.col,grid.row]:=’no’
else
grid.Cells[grid.col,grid.row]:=’yes’;
end;

end.

2003-11-17 16:23:23 StringGrid组件Cells内容分行显示在Tstringgrid.ondrawcell事件中:

DrawText(StringGrid1.Canvas.Handle,pchar(StringGrid1.Cells[Acol,Arow]),Length(StringGrid1.Cells[Acol,Arow]),Rect,DT_WORDBREAK or DT_LEFT);

可以实现文字换行!

2003-11-17 16:24:04 在StringGrid怎样制作只读的列在 OnSelectCell事件处理程序中,加入: (所有的列均设成可修改的)

if Col mod 2 = 0 then
grd.Options := grd.Options + [goEditing]
else
grd.Options := grd.Options – [goEditing];

2003-11-17 16:25:07 stringgrid从文本读入的问题(Save/Load a TStringGrid to/from a file?)stringgrid从文本读入的问题(Save/Load a TStringGrid to/from a file?)

// Save a TStringGrid to a file

procedure SaveStringGrid(StringGrid: TStringGrid; const FileName: TFileName);
var
f: TextFile;
i, k: Integer;
begin
AssignFile(f, FileName);
Rewrite(f);
with StringGrid do
begin
// Write number of Columns/Rows
Writeln(f, ColCount);
Writeln(f, RowCount);
// loop through cells
for i := 0 to ColCount – 1 do
for k := 0 to RowCount – 1 do
Writeln(F, Cells[i, k]);
end;
CloseFile(F);
end;

// Load a TStringGrid from a file
procedure LoadStringGrid(StringGrid: TStringGrid; const FileName: TFileName);
var
f: TextFile;
iTmp, i, k: Integer;
strTemp: String;
begin
AssignFile(f, FileName);
Reset(f);
with StringGrid do
begin
// Get number of columns
Readln(f, iTmp);
ColCount := iTmp;
// Get number of rows
Readln(f, iTmp);
RowCount := iTmp;
// loop through cells & fill in values
for i := 0 to ColCount – 1 do
for k := 0 to RowCount – 1 do
begin
Readln(f, strTemp);
Cells[i, k] := strTemp;
end;
end;
CloseFile(f);
end;

// Save StringGrid1 to ‘c:.txt’:
procedure TForm1.Button1Click(Sender: TObject);
begin
SaveStringGrid(StringGrid1, ‘c:.txt’);
end;

// Load StringGrid1 from ‘c:.txt’:
procedure TForm1.Button2Click(Sender: TObject);
begin
LoadStringGrid(StringGrid1, ‘c:.txt’);
end;

*******************************************

打开一个已有的文本文件,并将内容放到stringgrid中,文本行与stringgrid行一致;
在文本中遇到空格则放入下一cells.
搞定!注意,我只写了一个空格间隔的,你自己修改一下splitstring可以用多个空格分隔!

procedure TForm1.Button1Click(Sender: TObject);
var
aa,bb:tstringlist;
i:integer;
begin
aa:=tstringlist.Create;
bb:=tstringlist.Create;
aa.LoadFromFile(’c:.txt’);
for i:=0 to aa.Count-1 do
begin
bb:=SplitString(aa.Strings,’ ‘);
stringgrid1.Rows:=bb;
end;
aa.Free;
bb.Free;
end;

其中splitstring为:

function SplitString(const source,ch:string):tstringlist;
var
temp:string;
i:integer;
begin
result:=tstringlist.Create;
temp:=source;
i:=pos(ch,source);
while i<>0 do
begin
result.Add(copy(temp,0,i-1));
delete(temp,1,i);
i:=pos(ch,temp);
end;
result.Add(temp);
end;

StringGrid组件Cells内容对齐

在StringGrid的DrawCell事件中添加类似的代码就可以了:

VAR
vCol, vRow : LongInt;
begin
vCol := ACol; vRow := ARow;
WITH Sender as TStringGrid, Canvas DO
IF vCol = 2 THEN begin ///对于第2列设置为右对齐
SetTextAlign(Handle, TA_RIGHT);
FillRect(Rect);
TextRect(Rect, Rect.RIGHT-2, Rect.Top+2, Cells[vCol, vRow]);
end;
end;

2003-11-17 16:28:41 当我将StringGird的options属性中包含goRowSelect项时每当我选中StringGrid中一行,则选中行用深蓝色显示,我想将深蓝色改为其他颜色应怎样该?当我将StringGird的options属性中包含goRowSelect项时每当我选中StringGrid中一行,则选中行用深蓝色显示,我想将深蓝色改为其他颜色应怎样该?

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
begin
With StringGrid1 do
begin
If (ARow= Krow) and not (acol = 0) then
begin
Canvas.Brush.Color :=clYellow;// ClBlue;
Canvas.FillRect(Rect);
Canvas.font.color:=ClBlack;
Canvas.TextOut(rect.left , rect.top, cells[acol, arow]);
end;
end;
end;

procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol,
ARow: Integer; var CanSelect: Boolean);
begin
krow := Arow; //*
kcol := Acol;
end;

注意:必须把变量KROW的值初始为1或其他不为0的值,否则如果锁定第一行的话,第一行的颜色将被自设颜色取代,而锁定行不会被重画。

2003-11-17 16:32:44 怎么改变StringGrid控件某一列的背景和某一列的只读属性,StringGrid控件标题栏的对齐.怎么改变StringGrid控件某一列的背景和某一列的只读属性,StringGrid控件标题栏的对齐.
请参考以下代码:
在OnDrawCell事件中处理背景色。程序如下:
//将第二列背景变为红色。

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
begin
if not((acol=1) and (arow>=stringgrid1.fixedrows)) then exit;
with stringgrid1 do
begin
canvas.Brush.color:=clRed;
canvas.FillRect(Rect);
canvas.TextOut(rect.left+2,rect.top+2,cells[acol,arow])
end;
end;

//加入如下代码,那么StringGrid的第四列就只读了.其他列非只读
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);
begin
with StringGrid1 do begin
if ACol = 4 then
Options := Options – [goEditing]
else Options := Options + [goEditing];
end;

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var
dx,dy:byte;
begin
if (acol = 4) and not (arow = 0) then
with stringgrid1 do
begin
canvas.Brush.color := clYellow;
canvas.FillRect(Rect);
canvas.font.color := clblue;
dx:=2;//调整此值,控制字在网格中显示的水平位置
dy:=2;//调整此值,控制字在网格中显示的垂直位置
canvas.TextOut(rect.left+dx , rect.top+dy , cells[acol, arow]);
end;
//控制标题栏的对齐
if (arow = 0) then
with stringgrid1 do
begin
canvas.Brush.color := clbtnface;
canvas.FillRect(Rect);
dx := 12; //调整此值,控制字在网格中显示的水平位置
dy := 5; //调整此值,控制字在网格中显示的垂直位置
canvas.TextOut(rect.left + dx, rect.top + dy, cells[acol, arow]);
end;
end;

2003-11-17 16:37:15 在stringGrid中使用回车键模拟TAB键切换单元格的功能实现……
procedure TForm1.StringGrid1KeyPress(Sender: TObject; var Key: Char);
label
nexttab;
begin
if key=#13 then
begin
key:=#0;
nexttab:
if (stringgrid1.Col begin
stringgrid1.Col:=stringgrid1.Col+1;
end
else
begin
if stringgrid1.Row>=stringgrid1.RowCount-1 then
stringgrid1.RowCount:=stringgrid1.rowCount+1;
stringgrid1.Row:=stringgrid1.Row+1;
stringgrid1.Col:=0;
goto nexttab;
end;
end;
end;

2003-11-17 16:42:17 stringgrid如何清空with StringGrid1 do for I := 0 to ColCount – 1 do Cols.Clear;

2003-11-17 16:44:00 选中某单元格,然后在该单元格中修改-> 选中某单元格,然后在该单元格中修改

设置属性:
StringGrid1.Options:=StringGrid1.Options+[goEditing];

2003-11-17 16:46:14 让记录在StringGrid中分页显示在Uses中加入: ADOInt

//首先设定PageSize,取出PageCount
procedure TForm1.Button1Click(Sender: TObject);
begin
ADoquery1.Recordset.PageSize :=spinedit1.value;
Edit1.Text := IntToStr(ADoquery1.Recordset.PageCount);
ShowData(spinedit2.value);
end;

//然后将AbsolutePage的数据乾坤大挪移到StringGrid1中
procedure TForm1.ShowData(page:integer);
var
iRow, iCol, iCount : Integer;
rs : ADOInt.Recordset;
begin
ADoquery1.Recordset.AbsolutePage:=Page;
Currpage:=page;
iRow := 0;
iCol := 1;
stringgrid1.Cells[iCol, iRow] := ‘FixedCol1′;
Inc(iCol);
stringgrid1.Cells[iCol, iRow] := ‘FixedCol2′;
Inc(iRow);
Dec(iCol);
rs := adoquery1.Recordset;
for iCount := 1 to SpinEdit1.value do
begin
stringgrid1.Cells[iCol, iRow] := rs.Fields.Get_Item(’FieldName1′).value;
Inc(iCol);
stringgrid1.Cells[iCol, iRow] := rs.Fields.Get_Item(’FieldName1′).value;
Inc(iRow);
Dec(iCol);
rs.MoveNext;
end;

//上一页
procedure TForm1.Button2Click(Sender: TObject);
begin
If (CurrPage)<>1 then
ShowData(CurrPage-1);
end;

//下一页
procedure TForm1.Button3Click(Sender: TObject);
begin
If CurrPage<>ADoquery1.Recordset.PageCount then
ShowData(CurrPage+1);
end;

2003-11-17 16:48:51 打印StringGrid的程序源码这段代码没有看懂,但是可能有的朋友需要,所以共享一下子:)

procedure TForm1.SpeedButton11Click(Sender: TObject);
var
Index_R ,ALeft: Integer;
Index : Integer;
begin
StringGrid_File(’D:\AAA.TXT’);
if Not LinkTextFile then
begin
ShowMessage(’失败’);
Exit;
end;
//
QuickRep1.DataSet := ADOTable1;
Index_R := ReSize(StringGrid1.Width);
ALeft := 13;
Create_Title(TitleBand1,ALeft,24,HeaderControl1.Sections.Items[0].Width,20,
HeaderControl1.Sections[0].Text,taLeftJustify);
with Create_QRDBText(DetailBand1,ALeft,8,StringGrid1.ColWidths[0],20,
StringGrid1.Font,taLeftJustify) do
begin
DataSet := ADOTable1;
DataField := ADOTable1.Fields[0].DisplayName;
end;
ALeft := ALeft + StringGrid1.ColWidths[0] * Index_R + Index_R;
For Index := 1 to ADOTable1.FieldCount – 1 do
begin
Create_VLine(TitleBand1,ALeft – 13,16,1,40);
Create_Title(TitleBand1,ALeft,24,HeaderControl1.Sections.Items[Index].Width,20,
HeaderControl1.Sections[Index].Text,taLeftJustify);
Create_VLine(DetailBand1,ALeft – 13,-1,1,31);
with Create_QRDBText(DetailBand1,ALeft ,8,StringGrid1.ColWidths[Index] * Index_R,20,
StringGrid1.Font,taLeftJustify) do
begin
DataSet := ADOTable1;
DataField := ADOTable1.Fields[Index].DisplayName;
end;
ALeft := ALeft + StringGrid1.ColWidths[Index] * Index_R + Index_R;
end;
QuickRep1.Preview;
end;

function TForm1.ReSize(AGridWidth: Integer): Integer;
begin
Result := Trunc(718 / AGridWidth);
end;

function TForm1.StringGrid_File(AFileName: String): Boolean;
var
Strvalue : String;
Index : Integer;
ACol , ARow : Integer;
AFilevalue : System.TextFile;
begin
Strvalue := ”;
Try
AssignFile(AFilevalue , AFileName);
ReWrite(AFilevalue);
Strvalue := HeaderControl1.Sections[0].Text;
For Index := 1 to HeaderControl1.Sections.Count – 1 do
Strvalue := Strvalue + ‘,’ + HeaderControl1.Sections[Index].Text;
Writeln(AFilevalue,Strvalue);
Strvalue := ”;
For ARow := 0 to StringGrid1.RowCount – 1 do
begin
Strvalue := ”;
Strvalue := StringGrid1.Cells[0,ARow];
For ACol := 1 to StringGrid1.ColCount – 1 do
begin
Strvalue := Strvalue + ‘, ‘ + StringGrid1.Cells[ACol,ARow];
end;
Writeln(AFilevalue,Strvalue);
end;
Finally
CloseFile(AFilevalue);
end;
end;

function TForm1.LinkTextfile: Boolean;
begin
Result := False;
with ADOTable1 do
begin
{ConnectionString := ‘Provider=Microsoft.Jet.OLEDB.4.0;’ +
‘Data Source= D:\;Extended Properties=Text;’ +
‘Persist Security Info=False’;
TableName := ‘AAA#TXT’;
Open; }
if Active then
Result := True;
end;
end;

  • Share/Save/Bookmark

夫妻之间的经典定律

Posted by on June 3rd, 2009

炒菜定律:
经常炒菜的肯定是妻子,炒菜好吃的肯定是丈夫。
忠诚定律:
妻子越是爱丈夫,丈夫对妻子越是不忠;丈夫越是爱妻子,妻子越是对丈夫不忠诚。
花钱定律:
妻子把钱花在打扮(美容、穿戴)上,丈夫把钱花在过(烟、酒、牌、电脑……)瘾上。
买菜定律:
一到菜市场就不知买什么菜好的多是妻子,一到菜市场见啥菜买啥菜的多是丈夫。
成熟定律:
越是被妻子深爱着的丈夫越是成熟,越是被丈夫娇宠着的妻子就越是不成熟。
说话定律:
夫妻之间谁说得话越多,谁的话就越没分量。
伤害定律:
夫妻间,一方对另一方付出得越多,分手时所得到的伤害越大。
抱怨定律:
经常抱怨的总是妻子,经常被抱怨的总是丈夫。
干活定律:
在丈夫的眼里,家里总是没有什么活;在妻子的眼里,家里总是有干不完的活。
做事定律:
做事见好就收的总是丈夫,做事想好上加好的总是妻子。
着装定律:
男人只有合身的服装而缺少流行的服装;女人只有流行的服装而缺少合身的服装。
出门定律:
最着急出门的是妻子,最后一个出门的也是妻子。
洗碗定律:
妻子洗碗易净,丈夫洗碗易碎。
唠嗑定律:
越唠越有精神的多是妻子,越唠话越少的多是丈夫。
回家定律:
妻子一出门就想回家,丈夫一出门就不爱回家;妻子一旦不愿回家,丈夫就得匆匆回家;丈夫一旦不愿回家,妻子迟早也得离家。

  • Share/Save/Bookmark

AdvStringGrid使用方法

Posted by on June 1st, 2009

本文简单的介绍了TAdvStringGrid控件的一些常用的属性事件和方法,主要用于统计数据和设计比较复杂的表格!核心部分:合并单元格的几个函数和过程!

  1.可否进行编辑
  设置Options中goEditing设置为true。

  2.点击鼠标时直接进入编辑,或允许、不允许改变行或列宽等特性,都可以在MouseActions中设置。

  3.设置Grid中,某一列的数据格式,预定义的格式有:
  enum TEditorType { edNormal, edSpinEdit, edComboEdit, edComboList, edEditBtn, edCheckBox, edDateEdit, edDateEditUpDown, edTimeEdit, edButton, edDataCheckBox, edNumeric, edPositiveNumeric, edFloat, edCapital, edMixedCase, edPassword, edUnitEditBtn, edLowerCase, edUpperCase, edFloatSpinEdit, edTimeSpinEdit, edDateSpinEdit, edNumericEditBtn, edFloatEditBtn, edCustom, edRichEdit, edNone, edUniEdit, edUniComboEdit, edUniComboList };
  通过OnGetEditorType()事件进行设置,例如:

1.   void __fastcall TForm1::editgridGetEditorType(TObject *Sender,int aCol, int aRow, TEditorType &aEditor)
2. {
3.   switch (aCol) {
4.     case 1:aEditor=edComboList; break;  //设置第一列为ComboBox类型输入
5.     case 2:aEditor=edEditBtn; break;  //设置第二列为EditBtn类型输入,弹出一个选择框
6.     case 3:aEditor=edSpinEdit; break;  //设置第三列为SpinEdit类型输入
7.     case 4:aEditor=edDateEdit; break;  //设置第四列为日期型输入,弹出DatetimePicker。
8.   }
9. }

  4.TAdvStringGrid中每一种格式的输入与输出都要对应,否则载入时不能识别(因为各种类型的文件之间存储格式是不一样的)。例如:
  如果保存时使用TAdvStringGrid::SaveToFile(),那么载入时就要相应的使用TAdvStringGrid::LoadFromFile();其它对应如下:
TAdvStringGrid:: LoadFromBinFile();??TAdvStringGrid:: SaveToBinFile();
TAdvStringGrid:: LoadFromCSV ();??TAdvStringGrid:: SaveToCSV();
等等。

  5.增加edComboEdit和edComboList的下拉列表:
方法:
TAdvStringGrid:: ClearComboString(void); //清除已有了下拉列表
TAdvStringGrid:: AddComboString(AnsiString S);
TAdvStringGrid::Combobox->Sorted = true;
通过Combobox可以访问内置的Combo类型的控件的属性和方法。

  6.增加edCheckBox界面处理
  在Grid中数据载入之后,使用:
TAdvStringGrid:: void __fastcall AddCheckBox(int ACol, int ARow, bool State, bool Data)方法来添加CheckBox界面处理.
例如:
for(i=1;iRowCount;i++)
editgrid->AddCheckBox(5,i,FALSE,FALSE);
 
  7.通过TAdvStringGrid:: SpinEdit对象,可以访问内置的SpinEdit类的特性;
  同样的道理,通过其它一些内置的对象,可以访问这些类的属性,执行这些类的方法。

  8.TAdvStringGrid中的排序问题:
  首先设置排序参数:通过TAdvStringGrid:: SortSettings属性(发布TSortSettings类为一个属性),通过这个属性设置
然后调用TAdvStringGrid::QSort()方法应用SortSettings。
排序方向: SortSettings-> Direction=enum {sdAscending, sdDescending};
排序列:SortSettings->Column = 3;

  9.TAdvStringGrid::AutoSize属性,自动设置列宽,不推荐使用,自动调整后,真的很难看。

  10.多行显示
  bool TAdvStringGrid:: Multilinecells属性,是否支持多行显示,如果支持的话,可以用”#13”作为分隔符插入多行字符串,用多行显示。
折中的方法,可以用WordWrap来支持多行显示
  一般在设置和取消多行显示时,同时,对TAdvStringGrid::DefaultRowHeight进行设置,将有良好的效果。

  11.欲设置某些行或列为Fixed风格的显示,使用OnIsFixedCell()事件句柄来处理,调用TAdvStringGrid:: Repaint()方法来使设置生效。
例如:

1. If(colfix->Checked) { //colfix为一个TCheckBox
2. AdvStringGrid1->Repaint();
3. }
4. //事件处理句柄
5. void __fastcall TForm1::AdvStringGrid1IsFixedCell(TObject *Sender,
6. int Arow, int Acol, bool &isfixed)
7. {
8. if ((Acol==3) && (colfix->Checked))
9. isfixed=TRUE; else isfixed=FALSE;
10. }

  12.处理显示风格,如添加货币前缀和物理量单位
  在TAdvStringGrid::OnGetFormat()事件处理句柄中处理。
aPrefix参数设置显示前缀;
aSuffix参数设置显示后缀;
AStyle 参数enum TSortStyle { ssAutomatic, ssAlphabetic, ssNumeric, ssDate, ssAlphaNoCase, ssAlphaCase, ssShortDateEU, ssShortDateUS, ssCustom, ssFinancial, ssAnsiAlphaCase, ssAnsiAlphaNoCase, ssRaw, ssHTML, ssImages, ssCheckBox, ssUnicode };设置排序风格;

  13.是否能对特定的单元格进行编辑
用TAdvStringGrid::OnCanEit()事件句柄来处理,
设置bool &canedit参数来达到能否编辑某些单元格的效果

  14.隐藏和显示某些单元格
TAdvStringGrid:: UnHideColumn(int ACol)
TAdvStringGrid::HideColumn(int ACol);

  15.查找的实现:
TAdvStringGrid::Find()
TAdvStringGrid::FindNext();
两个方法返回TPoint类型,
Find()需要一个TFindParams类型的参数,enum TFindParameters { fnMatchCase, fnMatchFull, fnMatchRegular, fnDirectionLeftRight, fnMatchStart, fnFindInCurrentRow, fnFindInCurrentCol, fnIncludeFixed, fnAutoGoto, fnIgnoreHTMLTags, fnBackward, fnIncludeHiddenColumns };可通过自己设计一个查找窗体来实现。
例如:

1. //———-findfirst———-
2. void __fastcall TForm1::Findfirst1Click(TObject *Sender)
3. {
4. TFind *Find;
5. TFindParams findparams;
6. TPoint res;
7.
8. Find = new TFind(Form1);
9.
10. if (Find->ShowModal()==mrOk)
11. {
12. if (Find->chkcase->Checked) findparams << fnMatchCase;
13. if (Find->chkfull->Checked) findparams << fnMatchFull;
14. if (Find->chkregular->Checked) findparams << fnMatchRegular;
15. if (Find->dir->ItemIndex==1) findparams << fnDirectionLeftRight;
16. if (Find->where->ItemIndex==1) findparams << fnFindInCurrentCol;
17. if (Find->where->ItemIndex==2) findparams << fnFindInCurrentRow;
18.
19. res = AdvStringGrid1->FindFirst(Find->findtext->Text,findparams);
20. if (res.x>=0)
21. {
22. AdvStringGrid1->Col=res.x;
23. AdvStringGrid1->Row=res.y;
24. }
25. else
26. ShowMessage(”Text not found”);
27. }
28. delete Find;
29. }
30. //———-findnext———-
31. void __fastcall TForm1::Findnext1Click(TObject *Sender)
32. {
33. TPoint res;
34.
35. res = AdvStringGrid1->FindNext();
36.
37. if ((res.x>=0) && (res.y>=0))
38. {
39. AdvStringGrid1->Col=res.x;
40. AdvStringGrid1->Row=res.y;
41. }
42. else
43. ShowMessage(”Text not found”);
44. }
45. //———-
46.
47.

  16.TAdvStringGrid:: Ints[int ACol][int ARow]以Integer类型的值来访问单元格,如果读取失败,会触发异常.

  17.对特定单元格的对齐方式进行处理
  添加TAdvStringGrid::OnGetAlignment事件处理句柄。

  18.
  (1).添加图标:TAdvStringGrid::AddIcon();
原型:void __fastcall AddIcon(int ACol, int ARow, Graphics::TIcon *aicon, TCellHAlign hal, TCellVAlign val)
  (2).添加旋转字体:TAdvStringGrid:: AddRotated;
原型:void __fastcall AddRotated(int ACol, int ARow, short AAngle, AnsiString s);
  (3).从ImageList中取出图象添加到单元格中:TAdvStringGrid:: AddImageIdx;
原型:void __fastcall AddImageIdx(int ACol, int ARow, int Aidx, TCellHAlign hal, TCellVAlign val);
参数Aidx为图片在ImageList中的索引.
  (4).向单元格中添加位图:TAdvStringGrid:: AddBitmap;
原型:void __fastcall AddBitmap(int ACol, int ARow, Graphics::TBitmap *ABmp, bool Transparent, TCellHAlign hal, TCellVAlign val);
参数bool Transparent设置是否显示透明.
  (5).自动添加编号:AutoNumberCol
TAdvStringGrid:: AutoNumberCol(int ACol)方法,对指定的列从1进行编号,不对Fixed行中的列编号;
用途:用于产生首列的自动编号。
  (6).向单元格中添加多个图象:TAdvStringGrid::AddMultiImage
原型:void __fastcall AddMultiImage(int ACol, int ARow, int Dir, TCellHAlign
hal, TCellVAlign val);
事实上只是向系统声明一下,这个单元格将放置多个图象,图象的添加通过GridImages来添加。例如:
AdvStringGrid2->AddMultiImage(5,1,0,haBeforeText,vaCenter);

AdvStringGrid2->CellImages[5][1]->Add(0);
AdvStringGrid2->CellImages[5][1]->Add(1);
  (7).如果TAdvStringGrid:: EnableHTML属性启用,那么,单元格中输入HTML源代码,它将以HTML格式显示出来,例如:
AdvStringGrid2->Cells[7][1]=”Easy HTML
formatting”;
AdvStringGrid2->Cells[7][2]=”Including

AdvStringGrid2->Cells[7][3]=”Enjoy
———-

miniHTML”;

AdvStringGrid2->Cells[7][4]=”
AdvStringGrid2->Cells[7][5]=”125 9/16“;
这些内容在TAdvStringGrid中将以HTML格式显示出来。
  (8).通过TAdvStringGrid:: RichEdit属性可以调用TAdvStringGrid的内置的RichEdit类,是一个RichEdit编辑器,可以使用它处理RTF格式文档,然后使用TAdvStringGrid::RichToCell方法写入单元格.
原型:void __fastcall RichToCell(int Col, int Row, Comctrls::TRichEdit *Richeditor);
可以把用TAdvStringGrid::RichEdit::Clear()把RichEdit清空,再重新添加内容,然后再添加到单元格中。
可以通过TAdvStringGrid::RichEdit::SelAttributes来调整RichEdit的格式。
  (9).通过TAdvStringGrid:: AddProgress方法来在单元格中添加进度条
原型:void __fastcall AddProgress(int ACol, int ARow, Graphics::TColor FGColor, Graphics::TColor BKColor);
单元格的整数值就是当前进度值,可以使用TAdvStringGrid::Ints[col,row]来访问这个值。
  (10).通过TAdvStringGrid::AddComment方法来添加注释。
原型:void __fastcall AddComment(int ACol, int ARow, AnsiString comment);
添加注释之后,会在单元格的右上角显示一个小的红色的三角号,例如:
AdvStringGrid2->AddComment(8,3,”This is a custom” “\x00D” “comment for this cell”);
AdvStringGrid2->Cells[8][3]=”Cell with
comment”;
  (11).通过TAdvStringGrid增强型的HTML语法解析,添加内部单元格之间的链接,例如:
AdvStringGrid2->Cells[8][4]=” AdvStringGrid2->Cells[8][5]=” (12).通过TAdvStringGrid:: AddButton来在单元格中添加按钮
原型:void __fastcall AddButton(int ACol, int ARow, int bw, int bh, AnsiString Caption, TCellHAlign hal, TCellVAlign val);
当添加的按钮被按下时,OnButtonClick事件被触发(?经测试,不能触该事件)。

  19.在TAdvStringGrid::OnGetCellsColor()事件处理句柄中,可以对单元格的颜色和字体进行设置.

  21.添加可收缩结点,外观上看起来类似于分组,
方法:

1. TAdvStringGrid::FixedCols=0;
2. TAdvStringGrid::FixedColWidth=20;
3. TAdvStringGrid::AddNode(2,4);
4. TAdvStringGrid::AddNode(7,2);
5. TAdvStringGrid::AddNode(13,4);
6. TAdvStringGrid::AddNode()方法原型:
7. void __fastcall AddNode(int ARow, int Span);第二个参数为分组的跨越度。

  22.展开所有结点:

1. TAdvStringGrid:: ExpandAll()方法
2.  收缩所有结点:TAdvStringGrid:: ContractAll()方法
3.  TAdvStringGrid::CellNode->NodeType=cnFlat;
4.  TAdvStringGrid::CellNode->NodeType=cn3D;
5.  TAdvStringGrid::CellNode->NodeType=cnGlyph;
6.

以上三个属性设置StringGrid以结点的方式显示时的结点显示风格。

  23.对TAdvStringGrid添加过滤
使用TAdvStringGrid中预定义的一种Filter类: TFilterData
例如:

1. TFilterData* fd;
2.
3. AdvStringGrid3->Filter->Clear();
4.
5. fd = AdvStringGrid3->Filter->Add();
6.
7. fd->Condition = ComboBox1->Items->Strings[ComboBox1->ItemIndex];
8. fd->Column = 1;
9.
10. fd = AdvStringGrid3->Filter->Add();
11.
12. fd->Con_dition=ComboBox2->Items->Strings[ComboBox2->ItemIndex];
13. fd->Column = 3;
14.
15. AdvStringGrid3->FilterActive=true;
16.
17.

  24.自动调整列宽AutoSizeColumns
原型:void __fastcall AutoSizeColumns(const bool DoFixedCols, const int Padding)
用第二个参数来指定自动调整后需要额外增加的空间

  25.TAdvStringGrid的打印。
  使用TAdvPreviewDialog连接TAdvStringGrid来预览.这个控件中提供了接口可以直接对界面进行本地化。
  使用TAdvStringGrid的Print()方法来打印。打印设置调整TAdvStringGrid::TPrintSettins类的相关属性。
1. procedure TForm1.FormCreate(Sender: TObject);
2. begin
3. AdvStringGrid1.FixedRows:=2;
4. AdvStringGrid1.SaveFixedCells := false;
5. AdvStringGrid1.MergeCells(1,0,2,1);
6. AdvStringGrid1.MergeCells(3,0,2,1);
7. AdvStringGrid1.Cells[1,0] := ‘

Identification

‘;
8. AdvStringGrid1.Cells[1,1] := ‘Brand’;
9. AdvStringGrid1.Cells[2,1] := ‘Type’;
10. AdvStringGrid1.Cells[3,1] := ‘CC’;
11. AdvStringGrid1.Cells[4,1] := ‘Pk’;
12. AdvStringGrid1.Cells[3,0] := ‘

Power

‘;
13. AdvStringGrid1.BtnEdit.ButtonWidth := 24;
14. end;

一、Navigation——AdvancelInsert:控制当光标在最后一个CELL时是否可以按回车插入新行

二、Navigation——AdvanceOnEnter:控制按回车是否自动移到下一个CELL

三、Navigation——AllowDeleteRow:控制是否按DELETE键删除当前行

四、Navigation——AppendOnArrowDown:控制按下箭头是否可以新增一行

五、EnableWheel:=true时,一次滚动多行,EnableWheel:=False时,一次滚动一行。

六、SearchFooter—Visible:=TRUE时,会在ADVStringGrid的底部显示出搜索框

七、Options—goTabs:控制是否可用TAB键将光标移到下一CELL

八、AutoNumAlign:=True则数字类型数据在CELL里会自动右对齐

九、ADVStringGrid.AutoNumberCol(0);表示第0列按顺序显示数字,即1,2,3……

十、FloatingFooter—Visible:为TRUE时,即在ADVStringGrid底部显示求和列,要想让求和列显示小数,还需要将FloatFormat属性设置为:%g

十一、当合并行后,如果想使文字垂直居中,可以先设置ADVStringGrid的 MultilineCells 设置为 True,然后在文字前面加 #13 换行来实行

十二、改变固定列的显示样式:ControlLook——FixedGradientFrom(起始色)——FixedGradientFrom(结束色)

十三、改变单元格的背景色,可在OnGetCellColor事件中写代码实行(前提需将FLAT设置为TRUE):

1. procedure Tfrm_dingdan.strgridGetCellColor(Sender: TObject; ARow,
2. ACol: Integer; AState: TGridDrawState; ABrush: TBrush; AFont: TFont);
3. begin
4. if ARow=0 then //如果不加这一句,则是以下对应的整列,我这里是只改变固列,所以要把ARow设为0
5. begin
6. Case ACol of
7. 1: ABrush.Color:=RGB(227,249,248);
8. 2: ABrush.Color:=RGB(250,232,193);
9. 3: ABrush.Color:=RGB(227,249,248);
10. 4: ABrush.Color:=RGB(250,232,193);
11. 12: ABrush.Color:=RGB(227,249,248);
12. 14: ABrush.Color:=RGB(250,232,193);
13. 24: ABrush.Color:=RGB(227,249,248);
14. 48: ABrush.Color:=RGB(250,232,193);
15. 51: ABrush.Color:=RGB(227,249,248);
16. End;
17. END;
18. end;
19.
20.
21.
22.

十四、如果在录入的过程中,要对某列做格式化,比如保留几位小数,可用ADVStringGrid的GetFloatFormat事件中操作。比如:

1. procedure Tfrm_dingdan.strgridGetFloatFormat(Sender: TObject; ACol,
2. ARow: Integer; var IsFloat: Boolean; var FloatFormat: String);
3. begin
4. case ACol of
5. 4: floatformat:=’%.0f’; //第4列保留0位小数
6. 5: floatformat:=’%.3f’; //第5列保留3位小数
7. 6: floatformat:=’%.6f’; //第6列保留6位小数
8. 7: floatformat:=’%.5f’; //第7列保留5位小数
9. end;
10. end;
11.

十五、Options—goRangeSelect:控制是否可以选择多行,goRowSelect控制选中整行

、AdvStringGrid做多表头
在onIsFixedCell事件中返回true的就是表头

——————————————————————–
2、怎样实现AdvStringGrid的列宽自动按内容调整?
怎样实现AdvStringGrid的列宽自动按列标题宽度调整?
autosize属性的作用是什么?

autosize,可以根据内容调整列宽。
自动按标题列调整,自己在其RESIZE事件里对COLWIDTHS[I]赋值就行了。

procedure AutoSizeColumns(const DoFixedCols: Boolean; const Padding: Integer);
例:AdvStringGrid1.AutoSizeColumns(False,16);

AdvStringGrid1.AutoSizeColumns(False,16);
第一参数:是否为固定列;第二个参数,文字后面留的空格数

所有单元格自动调整,由第一个参数设置是否含固定单元,
如要固定行折行显示应将其行高设为自动调整即:
AdvStringGrid1.AutoSizeRow(0);
———————————————————————
3、AdvStringGrid插入checkbox列
把advstringgrid的option属性中的goEditing 设为true

在from create事件中加入

1. for i:=1 to advstringgrid.rowcount-1 do
2. advstringgrid.AddCheckBox(1,i,false,false); //其中1表示所在列数
3.
4. GetCheckBoxState(col,row) 可以查询的
5. Bchek:Boolean;
6. AdvSGrid.GetCheckBoxState(Col,Arow,Bchek);
7.

———————————————————————
4、stringGrid中的行或列和并

1. grdList.MergeCells(0,0,2,2);
2. grdList.Cells[0,0]:=’123456′;
3.
4. advstringgrid.mergecol(3,4);
5. advstringgrid..MergeCells(0,0,2,2);
6.

5、
with advStringGrid1 do //引用单元格时, 列数在前,行数在后.
MergeCells(0,0,1,3);
//合并单元格.前两参数为列数行数. 后两参数分别为要合并的列数和行数
Cells[1,0] := Format(’分度线( %s )’,[m_sMeasureRangeUnit]);;

MergeCells(3,JieDianStart – 1,1,1);
Cells[3,JieDianStart - 1] := ‘动作方式’;
ColWidths[3] := ColWidths[3] + 10;
Colors[3,JieDianStart - 1] := FixedColor;
FontNames[3,JieDianStart - 1] := FixedFont.Name;
FontSizes[3,JieDianStart - 1] := FixedFont.Size;
FontStyles[3,JieDianStart - 1] := FixedFont.Style;

前面是我在程序中拉的一段.
控件常用事件:
//单元格可否被修改
onCanEditCell(Sender: TObject; ARow, ACol: Integer; var CanEdit: Boolean);
begin
if ACol = 0 then
CanEdit := false; //false不能修改
end;

//对齐方式
onGetAlignment(Sender: TObject; ARow,
ACol: Integer; var HAlign: TAlignment; var VAlign: TVAlignment);
begin
HAlign := taCenter;
VAlign := vtaCenter;
end;
//是否固定列 ,即标题列, 在表中非开头行需要固定标题列时很有用
onIsFixedCell(Sender: TObject; ARow,
ACol: Integer; var IsFixed: Boolean);
begin
if(ARow = 10) then
begin
IsFixed := True;
end;
end;
——————————————————————————-
6、如何在AdvStringGrid中为每个单元格内的字体定制颜色
在OnDrawCell事件(看名字这个控件应该有这个事件把,呵呵!)写如下代码:
(Sender as TAdvStringGrid).Canvas.Font.Color:=clNavy;
7、cell中内嵌combobox
OnGetEditorType事件
if ACol = 1 then
begin
aEditor := edComboList;
grdMain.ClearComboString;
grdMain.AddComboString(’借’);
grdMain.AddComboString(’ 贷’);
end;

  • Share/Save/Bookmark

Delphi无限N进制转换

Posted by on May 26th, 2009

无限进制转换
(*//
标题 : 无限进制转换
说明 : 使用于数学领域进制之间相互转换
设计 :Zswang
日期 :2002-01-24
支持 :wjhu111@21cn.com
//*)
///////Begin Source
const
cScaleChar = ‘0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ’;

function IntPower(Base, Exponent: Integer): Integer; { 返回 Base 的 Exponent 次方 }
var
I: Integer;
begin
Result := 1;
for I := 1 to Exponent do
Result := Result * Base;
end; { IntPower }

function IntToDigit(mNumber: Integer; mScale: Byte;
mLength: Integer = 0): string;
{ 返回整数的进制表示 ;mScale 指定多少进制 ;mLength 指定长度 ,长度不足时向前补 0 }
var
I, J: Integer;
begin
Result := ”;
I := mNumber;
while (I >= mScale) and (mScale > 1) do
begin
J := I mod mScale;
I := I div mScale;
Result := cScaleChar[J + 1] + Result;
end;
Result := cScaleChar[I + 1] + Result;
for I := 1 to mLength – Length(Result) do
Result := ‘0′ + Result;
end; { IntToDigit }

function DigitToInt(mDigit: string; mScale: Byte): Integer;
{ 返回进制表示转换成整数 ;mScale 指定多少进制 }
var
I: Byte;
L: Integer;
begin
Result := 0;
mDigit := UpperCase(mDigit);
L := Length(mDigit);
for I := 1 to L do
Result := Result + (Pos(mDigit[L - I + 1], cScaleChar) – 1) *
IntPower(mScale, I – 1);
end; { DigitToInt }
///////End Source
///////Begin Demo

procedure TForm1.Button1Click(Sender: TObject);
begin
Edit1.Text := IntToDigit(StrToIntDef(Edit2.Text, 0), 16);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Edit2.Text := IntToStr(DigitToInt(Edit1.Text, 16));
end;
///////End Demo

  • Share/Save/Bookmark

Delphi获取系统当前进程名和进程ID

Posted by on May 22nd, 2009

获取系统当前进程名和进程ID,注意在编写本单元时,应注意引用”TLHelp32″单元”use TLHelp32″.

procedure TForm1.Button1Click(Sender: TObject);
var
ProcessName : string; //进程名
ProcessID : integer; //进程表示符
i : integer;
ContinueLoop:BOOL;
FSnapshotHandle:THandle; //进程快照句柄
FProcessEntry32:TProcessEntry32; //进程入口的结构体信息
begin
FSnapshotHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); //创建一个进程快照
FProcessEntry32.dwSize:=Sizeof(FProcessEntry32);
ContinueLoop:=Process32First(FSnapshotHandle,FProcessEntry32); //得到系统中第一个进程
//循环例举
while ContinueLoop do
begin
ProcessName := FProcessEntry32.szExeFile;
ProcessID := FProcessEntry32.th32ProcessID;
Listbox.Items.add(’应用程序名 :’+ProcessName +’#进程ID:’+ inttostr(ProcessID));
ContinueLoop:=Process32Next(FSnapshotHandle,FProcessEntry32);
end;
end;

  • Share/Save/Bookmark

Copyright © 2007 资料收集站. All rights reserved.