delphi 技巧合輯
INI文件的操作要点3 F. C# @7 S4 }# h! f
(1)在interface关键字后的uses子句中加入1 A- N" Q( u2 i3 r
uses …,inifiles;- M9 z6 o! k" N! a
(2)设置变量:var inifile:=TIniFile;
! c3 `8 q1 }2 D8 A(3)使用前,一定要先做:
( f8 Y, J1 f7 S& c; Z7 pinifile:=TIniFile.Create(inifilename);' H2 M$ n; e( n8 i
我在这里绕了个弯子,写成
3 ~ z% A+ W) x8 b2 i2 Qinifile.Create(inifilename);& \% d& `, h* o" J4 j$ U1 S* Q
. \' X ?; @5 q9 r/ X9 F7 j* PTShiftState用来检测CTRL,ALT,Shift,以及鼠标按键的状态,9 [0 R' a" o! Y6 ^2 L
常常用在键盘或鼠标的事件处理程序之中。& _' b) \) H* ?: X' N8 e$ g( y& Z ?( n
' h4 o2 R! O$ x, {& b" e
DCU文件(编译的库单元)的重用
( V% E4 }3 b0 J/ ]% y(1)在interface里的uses子句中引用。如Windows,Dialogs, j: c, a+ C" e2 @( o
等等,要求被引用的DCU一定要放在Delphi 3\Lib子目录中。
5 o1 z8 O! f, G(2)在implementation里的uses子句中引用。如果是自行编写的% P3 _0 y/ P! L# O9 L" A% A
DCU文件,应采用这一方式,并将被引用的DCU文件放入当前+ l" H' N# \" Q
工程所在的子目录中。
* R- @3 Q0 E$ ^+ g# texecutefile函数(在FmxUtils.DCU中定义)不能用在FormCreate; U% V8 l6 s3 N6 `0 r
事件中。真奇怪……: S0 W7 R; V5 W# s' x; ~" P
! q2 v; X$ U- D; D内置的版本号控制功能
6 e a9 `6 |' N5 a, F; Y6 D: S在Project Options中的VersionInfo项里,有版本信息的定制,! }1 [6 e: g: n' U3 c6 ]) F
包括一个有趣的版本号自动增加功能(Auto-increment build. t& C! ^* \$ T1 o8 D
number),即每Build一次,版本号中的Build Number加1。选中
3 `# o w7 q5 v9 e1 Y1 mInclude version information in project,编译,用资源管
1 ^8 ~( g' `5 w* G" r: W理器里找到生成的.exe文件,点右键,查看“属性”一项,就: u5 {% q# C) D6 @ j0 P1 L$ D1 D
会看到在属性中多了一页“版本”,里面就是你刚才输入的各/ C: c" ?+ N9 B4 V( g1 s
项内容。. H6 P3 e( B$ Z" z4 ^9 d
. H: A9 h$ x# y- B: i
8 J2 ?: ^: R7 d! f& s: \定制Speedbar8 `. \- \+ z* Q7 a- v
右键点击左上角的加速键条(speedbar),选中Properties,
! | B& W C" g( b b7 K: }在列表框中找到你想要加入speedbar的命令按钮,将它拖到+ k! _- f0 `- i% U
speedbar上的合适位置即可。如果speedbar上没有多余的空间5 T/ w/ T1 t3 P! m& z
来容纳新的按钮,可把鼠标在speedbar右框处变为双向箭头的
& s4 ?! d6 w J3 c, r- `" M形状,向右拖动一段距离,就可腾出空间。如想删除speedbar9 L8 t9 _3 C0 s, O5 A0 c/ S& {. c
上的某个按钮,可简单地把它拖出speedbar的范围,就能删除。0 q Y- S9 q2 Z* [0 n6 {2 D
7 u/ h$ [3 O- q- |. F' v
$ ? l: c2 j6 M) B$ ]" b# g计算出的字段
% V/ ?0 \! ?9 q$ D2 V! Y6 ]在写一个程序时,我要在DBGrid中显示出一个memo的部分信息,当我把那个
2 Y' C5 m, o* o' ?* V/ `' hmemo字段放进去后,运行时只能显示出“(memo)”字样。从书上找到计算字
$ w& U- z4 U2 V" M段的用法后,我在TTable中增加一个计算字段MemoHeader,宽度为40,在此
8 H1 O+ z0 R4 c8 b0 nTTable的OnCalcFields事件中输入:1 e6 B& W+ L5 Z3 t/ W5 z
with MyTable do. H) `, E" z# E2 c( D& r$ `% U; s
FieldByName(‘memoheader’).asstring:=FieldByName(‘memo’).asstring;
# S# E2 Z. u4 \; r# C, F+ `在DBGrid中放入MemoHeader,运行,OK!
) Y( ]) B. i: _. e/ X0 q3 |
4 i6 ^# Q' |# L! H
$ }( e& A Q, m) A字段编辑器8 A" K/ _$ O, M& F& W# r
解决了上面的问题后,我继续学习字段编辑器的作用。原来,DELPHI通过字
% c$ t: ^7 w& ]* d段编辑器,近乎完美地实现了数据库的字段级的控制,这包括:
- m6 [3 j. a2 r' ^1 x1)字段在DBGrid中标题、宽度、能否可见;
( Q& R$ }6 @- E( W( d( `5 l; I0 b2)字段的显示格式和编辑时输入的过滤条件;% P- H- \9 Y( g: t! \$ h
3)字段是否只读;/ C, k. R% x' a/ u0 A
4)字段的类型:数据字段/计算字段/查询字段/内部计算字段;
/ v# r0 C5 u3 A2 t. o5 R" [9 q5)字段的显示/赋值/修改等事件的定制。" S, z! U# k" V: ]. k- S
2 ~8 \$ `9 r$ Q- R" Y0 m1 ^ y, B
1 b/ c) L- I) N6 g* }7 x# k/ o设计Form时的快捷键/ m( v. r2 K' Y
Del 删除所选组件
. G' N D# w9 f" HEsc 选择当前组件的容器(通常是Panel,Group或Form)0 l. W. Z0 t. h
F11 在Form或Unit和对象检查器之间切换7 y9 a" V3 {& m3 A- L
F12 在Form和代码编辑器间切换0 _( x2 ~/ i3 j2 u1 c
Ctrl-F12 显示“查看Unit”对话框
- ^0 Q$ M u3 D6 r, E0 C+ XShift-F12 显示“查看Form”对话框$ J9 j7 h! H( w0 k
TAB 下一个组件 n; l$ {2 b7 {; w
Shift-TAB 上一个组件8 F& ~! n" a1 A1 y4 G
方向键 选中此方向上最近的组件
3 k1 Y' S; {* ~% yCtrl-方向键 将所选组件移动一个点
* K' ~0 \6 Y3 R' W6 `$ i5 k1 zShift-方向键 将所选组件改变一个点的大小6 F6 I4 Q4 N7 e8 X3 |
Ctrl-Shift-方向键 将所选组件移动一个格: G9 e, R C( u/ |
Shift-click 按住Shift键再用鼠标点击组件,可以选择多个组件。
6 I+ k0 C/ E% s–= 下面这条是我摸索出来的 =–+ J5 m! s% d2 q* _' Q* p
Ctrl-drag 按住Ctrl键在一个容器组件(如Panel,QReport,Groupbox等)
! ?; j2 ]' \5 L3 P, k里拖动鼠标,可强制选择鼠标拖过的矩形框中的所有属于此容
1 e' ~2 U3 K' i( V! J器的可视组件但不包括该容器组件。3 O$ E; |; ~1 l6 s5 ~7 k, U- s
1 e/ X z) A# W( Y
% {3 s5 P3 Z6 R& W( R5 g/ p使用QReport的若干经验
" m1 X" L* K( `9 g3 s1)QuickRep1.DataSet:=query1) z, s7 p6 m) J
不然无输出结果
) ^: D7 l3 ?) s0 ]2)从qrpt2man.doc中查知,格式化输出结果的方法是:9 }" i/ b" x+ `6 w1 O5 t
在QRDBText.Mask中设为.00;0,将使输出带两位小数。7 Y! g! m8 o* m; Z! u: ~+ W7 {
3)设置Group时,先加入一个QGroup,再加入一个QRBand,将QGroup的
) a) ?9 F+ Y9 q) g; Y. w7 i% `FooterBand设为刚才的QRBand,就可将其联系起来。 h6 A0 [3 i& Q! B/ H& R* j
4)在Group中打印的合计数,其ResetAfterPrint设为True,可实现分组合6 V- ^3 H: ^ c" k) W
) e( ~7 E% }; c+ A. l8 ^format(‘%*.*f’,[8,2,123.456]); //等价于format(‘%*8.2f’,[123.456])9 C4 X1 Z8 q q0 j
format(‘%d %d %0:d %d’[10,20]);. k; ?& b* M1 n4 C4 \! z" Q
( L# m8 Q" P- t4 H$ e- v- a4 y7 G B8 x
7 B$ i( g0 T. L9 ^
播放一个wav文件
( p, \) E) w- d8 d2 Q9 B2 Duse mmsystem;
% a( p# f; x( ]SndPlaySound(‘hello.wav’,SND_FILENAME or SND_SYNC)* B7 e2 e% h, f7 t" [
, R, W( V, [8 l" U( I! m
使你的form适应不同的显示分辨率% h: x! c7 O; r7 G! e
假设你在800*600的分辨率下设计的form,第一步:* U. @2 ~/ U( ~
inplementation! I; H) M+ O; a, G/ O
const
0 e% R& Z7 ^' }- v5 w# L1 ^4 kScreenWidth: LongInt = 800; {I designed my form in 800×600 mode.}
7 [/ L2 Y) J1 uScreenHeight: LongInt = 600;
: E/ F, n8 H; F" N2 i& V3 o
$ ?# I( s3 M! H: [6 H; ]{$R *.DFM}
! i2 m' N, |6 P. |" B [, a5 M: p p! n) y
procedure TForm1.FormCreate(Sender: TObject);
. Q3 N+ g) s+ M* nbegin
) V# p3 U0 y! y( h/ F! n; ]7 H8 Kscaled := true;5 }1 n- U3 m7 e7 S+ p
if (screen.width <> ScreenWidth) then" v$ J& h* p: m. m! A
begin
$ e ~8 V7 U- O0 {height := longint(height) * longint(screen.height) div ScreenHeight;
5 ~$ i( M% I1 z4 N$ W- @width := longint(width) * longint(screen.width) div ScreenWidth;
% O( i3 w: W* q4 G2 M YscaleBy(screen.width, ScreenWidth);
7 m; u4 W- m3 p Y5 k2 D5 H" qend;
9 @, a! W+ T: F- p! Send;
1 z. k" O8 {/ f4 b- S. B( _2 x& ?: [1 W% ^$ M+ r
下一步,要让每个子控制的字体改变到合适的大小:9 P0 {) C& q0 y0 T* o2 q/ [
type3 \& _3 F/ W2 V: J
TFooClass = class(TControl); { needed to get at protected }
& o' f% k- g# x* g( E5 l{ font property }& u* Y( N8 p& `1 R+ f! b
6 e2 n5 c8 m1 N) I) ^( A# pvar
! h) S9 Q- ]/ w( g$ H* a% D, Ei: integer;, w( @& x5 a, z- ^ i1 V4 ?: H
begin/ c6 d& T" o) Y
for i := ControlCount – 1 downto 0 do
8 j: A$ I: G' h2 v: @! KTFooClass(Controls).Font.Size :=
~# B3 G. }1 p5 A% I+ o. Q' L! g(NewFormWidth div OldFormWidth) *- F8 g8 \) t9 H8 C9 d& O
TFooClass(Controls).Font.Size;: _. i0 W b, l* n# R+ O
end;
" p9 H+ l& m/ e" E+ H1 r2 E) P& V; Z/ L
用raise引发一个错误处理例程0 F1 W/ R' o8 O+ t
示例:先给出下面的定义
7 X# X- ^& U1 Z( L2 O7 ctype EPasswordInvalid=class(Exception);
# a' O" C, L' B* G1 R这样你就可以随时引发一个”password invalid”的例外:$ A6 `& r0 T) f6 B0 y% b: h
if Password<>CorrectPassword then
4 W! c- ^0 {0 z( l( q' U6 \) jraise EPasswordInvalid.Create(‘Increect Password entered’);
& K2 W% Z( E! P1 i" w运行后,出现信息框4 ?6 A8 I4 O( T
Project Project1.exe raise exception class EPasswordInvalid
% w, p& d# J$ D& V9 B& D, m+ e. Hwith message ‘Incorrect Password entered’. Process stopped.
) D9 b% D5 e1 `6 m. s: ?4 I% HUse step or run to continue.
2 e) p8 ^: n* w" C再按Run按钮,出现一个信息框:( ]# Q; t9 [! }) ~
Incorrect Password entered.
5 ]6 {2 H: K0 _3 w6 W5 P4 s
+ F4 K1 M7 H" F1 F! w9 o8 }5 W2 t6 N$ ~) Q0 m
从DEMO例程中学到的若干小技巧9 o8 ]6 w4 y4 ^: g# q) }# `
在demo\internet\http\webbrows\main.pas中,- J/ I& u/ P4 J
procedure TForm1.DocumentSourceClick(Sender:Tobject);
' j7 @& R& T/ O3 }: ] q6 h1 N8 h3 fbegin! h% `! T) F T
with DocSourceForm do9 E# f" o- v+ Q3 j5 Q
begin2 K' d- l+ Y' m; Q. }7 u3 Q& ]
show; // 显示HTML源码的FORM2 P6 D! t. \ Q$ D+ Y8 _$ ]* @
Memo1.lines.clear; // 清空memo1中内容; V4 K3 w! {# F
Memo1.lines.add(HTML1.SourceText); // 植入源码
0 J; ]- t1 l0 ~! x3 P# s; RMemo1.SelStart:=0 // ***
! @. X9 H( F- o1 M/ m$ ~. x! |) c& xSendMessage(Memo1.Handle, // Memo1的窗口句柄+ {& g: {/ M7 J
EM_ScrollCaret //将Edit Control中的caret光标滚动到视野中
9 D* a3 Y0 r2 b1 J5 F0,0 //这两个参数暂不使用0 V+ X6 o8 \0 {1 _
end;/ u2 K! ^ t: |' s2 ]) h4 h
end;1 b; }$ W! p6 [' z* B2 V
(此SendMessage系一WinAPI调用,给一个或一组窗口发送消息,直到
6 e. s2 [! G7 c: E相应窗口处理此消息后才有返回值。相似的另一函数为PostMessage,
) d5 ~6 r6 R$ n' d$ d5 b1 _它将消息放入消息队列中后立即返回。)
/ D7 M Q# \$ T& N*** 清空当前选择并将光标移动到指定字符(0代表第一个字符)。如同时' o3 F) v: g# g/ H6 _
设memo1.sellength为一非0值,可选择一段文本。
, D6 u/ f6 a! b- M7 [! `3 b( @7 e6 k; ]: S9 l+ P4 p7 u6 k
) g; o+ ]* ~8 @& q. S+ Y% g奇怪的I/O error — 我在开发过程中发现下面这两条语句) k6 V, e7 ]3 `' ]
assignfile(fDesc,CDDatadir+describefile);4 t! O3 z0 d/ B w( U, m
reset(fDesc); 8 t# c9 G) X% O! T1 [' k3 ~/ |& }
每当我第一次运行到这里时,总会出现 I/O Error 183 的错误.: G( j1 d0 c& P/ d1 ?5 O
最后我想这也有可能是没有清除 ioresult 的原因.在两句之间加入7 T- o% A: Q! F. w" \; \
if ioresult<>0
; v8 O& q9 W$ ^* ^/ p, i5 gthen;
5 M" z) F, r; d( Y7 [4 j4 \- e: poooook! 可以了.( F6 o R9 C9 P$ D2 M
I& {; D$ n* Y
7 { w. C x$ ?5 D值得注意的I/O error O" B7 L' Z& ~9 }
AssignFile(F, fname);
3 n8 ]3 s/ [) B$ E1 }: y. z: [; h3 @Rewrite(F);
8 N" m9 W" q! i当文件 F 经 Reset(F)打开的情况下, Rewrite(F)会引发一个异常: I/O error 32
+ g* Q, l/ t5 p$ x; y0 G反之,经 Rewrite(F)打开, Reset(F)也会引发同一个异常.
" _4 [2 @# T9 q8 |' aReset(F)两次,closefile(F),再Rewrite(F),或反之,也会引发同样异常.
$ U3 I1 C# o0 r6 ^& G% L5 K- W+ H b+ ^0 ?! b" s( s8 @
0 t/ h7 _4 ]7 H/ l' Y4 s, I B% U# H& M- l* i5 M9 H$ E0 Y- j- J
string和pchar的相互转换:, z3 R7 x+ {2 ]3 G# G7 w" ]
string –> pchar: pchar(s) M4 J6 M& K6 w' J8 y
tr:string);% T0 v# a" h) t Z- C9 o% i/ d
pchar –> string: strpas(p:pchar);. f$ `2 W; J4 f9 ^, w c& d
# l# Y D2 L( }# I
& C4 D# s: j3 c2 D( X5 L. A3 ?/ j/ s8 c% H. m5 i- n/ A0 ~: v
在Delphi代码中定义数据库1 K2 l& b6 W4 F3 w9 `
procedure tform1.create_tbl;5 B% N0 V' Z" Z- I2 e9 w: m# [
var tbl:ttable;
. O) ?3 L, z% c+ j9 k$ ^begin, i+ V3 h* N, A, d. |, D
tbl:=ttable.create(self); // 如没有声明中的”tform1.”,Delphi不认这个self
7 A& w, `* F6 n8 hwith tbl do3 Q5 h$ f& L6 s8 P/ A. a# ]4 ^! F7 S
begin
9 S& K. A1 B0 u" J2 Cdatebasename:=;dbdemos’;
6 X. v, J0 c3 n% i* K8 @( Otablename:=’my_tbl’;* e1 p) K6 e5 X U- a
with fielddefs do
$ |9 H2 y- d" X9 ybegin
' Y+ s0 S+ i; i# }& H% _clear;
, b/ Z2 u; q. D, }: ?add(‘No’,ftInteger,0,false);
/ @8 c M, |. }/ @add(‘Name’,ftString,0,false);* z3 a7 c* {" v' ]8 D d
…1 x1 Z9 [2 B6 r9 s
end;/ f4 ]% e8 Q' ^7 F+ G& f. E5 q
with indexdefs do8 z; [ q% h; d
begin6 p# {! S0 V. f, O
clear;$ P, c# n0 m H1 ^( I
add(‘primary’,'no’,[ixPrimary,ixUnique]);
* { e& [: f% {0 M% R2 g5 d: ?0 N…5 H9 `1 D4 i, O7 T1 W# G
end;( h0 s+ x3 @ K
CreateTable;
1 U i7 R4 q" {0 d2 S) gend;0 `# a& }. t& y# y* F7 E9 k: p
end;& p h) w5 [' u O/ z6 c
8 D: z8 w1 b( B% P
1 s. p( P C Istring、TStrings、pchar的相互转换(这里是我的个人经验)
- V) q9 t/ D( ^0 |' F假设有如下定义:, e, `) ?" J+ R4 [5 x6 B0 r# F: X
var
3 T# `4 T7 J! Q% \7 n! \p:pchar;3 p5 N. @& X4 i3 T" N
s:string;
2 K% G6 @3 {8 zss:tstrings;
8 H3 I6 l7 I V3 Z5 }+ Bbegin7 J( {3 t2 n2 N+ C
ss:=tstringlist.create; // 开始时一定不要忘记创建ss [0 a5 M1 B/ z2 v1 }1 r3 U. k' Y
ss.text:=s; // string –> tstrings
. @" ?- p* J0 r b' s' G; ^s:=ss.text; // tstrings –> string2 k/ O! @( D* ^
p:=pchar(s); // string –> pchar, |! \( r+ c$ A ~ _' d7 R' b+ n
s:=p; // pchar –> string
, R0 C* K/ F" Eshowmessage(s); // 合法语句
( ?; ^+ A1 Z3 V6 h# o! t8 q+ k. fshowmessage(p); // 合法语句
4 K& n! L, C$ e$ O… …4 [8 ]1 j% w( C5 o5 S3 Q
ss.free; // 最后还要记着释放ss占用的资源 c% W/ Y" i( n6 l+ b7 ?% a, \' ^
end;* ~5 Z/ n0 ^; _0 p5 ]
1 m" y) N, v2 G+ }
9 O: A1 O! y, A2 D1 z8 V' L. P
5 I9 w/ _8 c \, A: B m$ a
在设计Menu时,常用的ShortCut可从下拉菜单中选取。但我发现可选的ShortCut有些不在列表中,如ESC,Ctrl-Shift-A等。我试着在ShortCut项的右边输入:ESC,竟然成功了。再试Ctrl-Shift-A,这回Delphi自动把它变为Shift-Ctrl-A