delphi 技巧合輯
INI文件的操作要点( x" C" Z/ |3 x9 k
(1)在interface关键字后的uses子句中加入
3 c' d! s5 X* s& j+ auses …,inifiles;- k& V: H6 c/ H
(2)设置变量:var inifile:=TIniFile;! s5 a/ W$ | C9 Q2 B Y
(3)使用前,一定要先做:
7 K. j0 I0 m6 N9 U3 T1 einifile:=TIniFile.Create(inifilename);
5 D7 s* [$ o# v, ?1 I" P7 m我在这里绕了个弯子,写成
; F3 u6 u W: ?inifile.Create(inifilename);
) Y$ R/ n! C, P5 i- r/ x) l/ F3 O4 |. h6 v0 S. Q
TShiftState用来检测CTRL,ALT,Shift,以及鼠标按键的状态,( }1 _3 O5 B$ P3 O
常常用在键盘或鼠标的事件处理程序之中。
7 P& k3 R0 O% u& K" q' B# }; I3 F( G, M; V: z+ x
DCU文件(编译的库单元)的重用% H2 d: H4 J. k
(1)在interface里的uses子句中引用。如Windows,Dialogs,; G- Y5 |8 Q5 k1 ?
等等,要求被引用的DCU一定要放在Delphi 3\Lib子目录中。
& r: ~+ m H6 z- y# C' L(2)在implementation里的uses子句中引用。如果是自行编写的9 C0 p$ R8 n/ A4 r/ C. B
DCU文件,应采用这一方式,并将被引用的DCU文件放入当前8 ^3 y2 B Y4 M. E5 x7 A$ k
工程所在的子目录中。
0 H3 K1 g" `6 G& sexecutefile函数(在FmxUtils.DCU中定义)不能用在FormCreate
8 r- x2 M) V1 A; i1 L6 t3 P' R事件中。真奇怪……
7 k. h. T3 ~. K6 X2 o" x* a j& e* c f6 m, j- {3 ]' I; a
内置的版本号控制功能
5 c* u5 z0 V/ ]' L7 ]在Project Options中的VersionInfo项里,有版本信息的定制,
$ C1 s+ p3 v; ]包括一个有趣的版本号自动增加功能(Auto-increment build
i5 P) V/ u8 W! fnumber),即每Build一次,版本号中的Build Number加1。选中
; h7 V8 U. e* D# p/ O$ G7 S, s* xInclude version information in project,编译,用资源管
5 b4 J) W- O' U6 q理器里找到生成的.exe文件,点右键,查看“属性”一项,就- F) Y& t7 w* l& H( T4 a
会看到在属性中多了一页“版本”,里面就是你刚才输入的各 O5 G- X6 |/ F, X( H' ~2 D* z" {
项内容。 v% J; N L8 p4 H+ ?8 K
, J9 [ W3 a' p& q- ~4 V
" Y, Q3 |5 A! U' ?定制Speedbar& J6 t3 h" Z8 g% O& g% |
右键点击左上角的加速键条(speedbar),选中Properties,
8 I, s* S0 G# T9 h9 J& e3 R在列表框中找到你想要加入speedbar的命令按钮,将它拖到5 d2 A. M! K: a7 y
speedbar上的合适位置即可。如果speedbar上没有多余的空间# r* v4 r7 [ I- P. |* q
来容纳新的按钮,可把鼠标在speedbar右框处变为双向箭头的- T ^( w* t9 P
形状,向右拖动一段距离,就可腾出空间。如想删除speedbar
6 N9 y' l0 e S上的某个按钮,可简单地把它拖出speedbar的范围,就能删除。
4 j- H/ W$ J% X: t
) Z1 f6 ~$ Y2 n3 O! u6 p4 H' x- F% S; _' d
计算出的字段
, Y' j- q: F0 v8 R: |7 j4 R在写一个程序时,我要在DBGrid中显示出一个memo的部分信息,当我把那个! ]7 z- i4 ]/ T( ^8 z) a
memo字段放进去后,运行时只能显示出“(memo)”字样。从书上找到计算字
3 L- \9 }& b" _/ I" A段的用法后,我在TTable中增加一个计算字段MemoHeader,宽度为40,在此
( Y b; ^ J( h3 f3 p6 n1 DTTable的OnCalcFields事件中输入:
: y! {1 |6 R' X- Nwith MyTable do2 l1 T& q2 P u' J: l* _
FieldByName(‘memoheader’).asstring:=FieldByName(‘memo’).asstring;
+ j$ r; h [6 E7 b$ @在DBGrid中放入MemoHeader,运行,OK!
+ L' g% V9 F$ ^2 d5 h1 {% S: l) B
1 V1 j2 z: s6 D: m' ~2 E3 C0 a+ J0 Y, w# r0 q" B! T
字段编辑器: a! a% I" }7 P$ H2 A0 P
解决了上面的问题后,我继续学习字段编辑器的作用。原来,DELPHI通过字. w/ K( G; Z. q$ h# Z6 \: ~6 G
段编辑器,近乎完美地实现了数据库的字段级的控制,这包括:6 {# ^4 T t6 l
1)字段在DBGrid中标题、宽度、能否可见;5 S0 V" ]2 f. b4 H! L) w: K) X
2)字段的显示格式和编辑时输入的过滤条件;
4 ~) t; \6 C; l& v8 w1 ~0 Z3)字段是否只读;( @4 I3 K7 U r a
4)字段的类型:数据字段/计算字段/查询字段/内部计算字段;
- {9 V9 N9 }6 B7 Q5)字段的显示/赋值/修改等事件的定制。
* r/ l2 E& b$ b! \- g+ a* k3 u+ P ~ ~0 v
1 c) P, l1 J; X1 p
设计Form时的快捷键' W2 j7 Z9 [6 e, W
Del 删除所选组件& N+ i T; }3 Q% i( d: s
Esc 选择当前组件的容器(通常是Panel,Group或Form)
% \1 P8 `. N! P R: @% m. {/ bF11 在Form或Unit和对象检查器之间切换( \' N* U; {. B) m6 Z' p1 [0 F
F12 在Form和代码编辑器间切换! q$ }3 \: R( F3 @
Ctrl-F12 显示“查看Unit”对话框: Y- T- R# J/ N4 e9 o; u
Shift-F12 显示“查看Form”对话框
9 l* q l5 p: m1 f# eTAB 下一个组件
0 v T2 w4 J8 W7 I) C6 \2 W* dShift-TAB 上一个组件
' a1 q* [) z5 a/ x9 F方向键 选中此方向上最近的组件" D' ]6 r. i, ]# ?3 |& B4 r
Ctrl-方向键 将所选组件移动一个点1 L e. {( K8 z7 E
Shift-方向键 将所选组件改变一个点的大小) d7 k+ H; B. _
Ctrl-Shift-方向键 将所选组件移动一个格
* E5 ]. { s% e. e5 eShift-click 按住Shift键再用鼠标点击组件,可以选择多个组件。% o w4 [3 I2 M# C- J3 X
–= 下面这条是我摸索出来的 =–1 E9 t8 k5 x) F, A( ~
Ctrl-drag 按住Ctrl键在一个容器组件(如Panel,QReport,Groupbox等)7 V2 V$ _6 x; o0 ]) o
里拖动鼠标,可强制选择鼠标拖过的矩形框中的所有属于此容
" x" Y6 a ?+ O3 M" h$ x器的可视组件但不包括该容器组件。& C4 Q" j, N) k: s1 Z6 H- y
) n/ W. W$ ~, o% j! P
v! q- r1 L8 P: H) x使用QReport的若干经验- |/ f! ?6 D( Y& c
1)QuickRep1.DataSet:=query14 C6 h" J8 K) S' S" p$ S
不然无输出结果
1 \3 u% G' |8 J2 f2)从qrpt2man.doc中查知,格式化输出结果的方法是:: [3 d+ ~- y4 ?2 o0 P6 C( }
在QRDBText.Mask中设为.00;0,将使输出带两位小数。% E% d S/ a7 L. D& X$ O
3)设置Group时,先加入一个QGroup,再加入一个QRBand,将QGroup的) M+ ?% ^3 N) g; o
FooterBand设为刚才的QRBand,就可将其联系起来。: V+ C, I) R% P( `8 I; N
4)在Group中打印的合计数,其ResetAfterPrint设为True,可实现分组合, Z L# f4 q+ e% G5 o* F N
# H2 y6 w+ S0 V5 Uformat(‘%*.*f’,[8,2,123.456]); //等价于format(‘%*8.2f’,[123.456])
$ I3 k3 ?# H8 h0 |format(‘%d %d %0:d %d’[10,20]);" k; Q: q8 ^6 @6 o% q, [7 e
+ j9 }$ v! O- w
/ d4 @" ]2 i( q
/ K( {, c+ u8 ~" M4 u; q7 q- p
播放一个wav文件
, ?4 r( ?; [6 wuse mmsystem;
' ^, Z5 Q% S9 g) R; j7 fSndPlaySound(‘hello.wav’,SND_FILENAME or SND_SYNC); [6 X( s ]2 B( ^. `( U1 a2 i
0 `: @) f H( r9 C- z使你的form适应不同的显示分辨率
3 ]% o1 N; y( s3 T5 g3 o' o假设你在800*600的分辨率下设计的form,第一步:' J9 \$ k! s2 t$ G
inplementation7 X, ], _4 a4 \6 ^3 a- Q% R
const% h- | o3 N4 Z9 E; p) i( G
ScreenWidth: LongInt = 800; {I designed my form in 800×600 mode.}( Z8 u! z. H; [8 |4 ?6 p
ScreenHeight: LongInt = 600;! B6 Q) L/ q: O7 \& f# R! e( Q
4 y: J8 h+ h$ ^2 s$ [5 a% Y# C{$R *.DFM}! R1 ]6 v" o: @: n1 \
$ E: @0 V0 Q9 h, n( u; ~' q7 B' i* ?
procedure TForm1.FormCreate(Sender: TObject);
$ ?. G4 ]& Y1 F1 Q6 f4 O) jbegin# }5 \: m3 V/ q( Q
scaled := true;$ K' e4 c) K+ E( d1 P5 w1 ?
if (screen.width <> ScreenWidth) then
" b; o2 F- L, D( q7 Q' Ebegin& k; g. [: B+ Y) Z- i
height := longint(height) * longint(screen.height) div ScreenHeight;' }3 K m6 n# Y/ i! E0 C
width := longint(width) * longint(screen.width) div ScreenWidth;5 n" B8 G# I9 L; l; x- C7 [
scaleBy(screen.width, ScreenWidth);
9 K# y" ]0 s( M# \, r4 yend;( y& D5 a4 X b( ?3 v
end;. \$ [* z7 {) a* O
4 }4 T) r( ^7 j, M5 v5 e
下一步,要让每个子控制的字体改变到合适的大小:4 L% J, o4 ~. }" ^# k
type
T6 W7 z( I& g9 B1 JTFooClass = class(TControl); { needed to get at protected }/ R8 v: N$ ]* D
{ font property }' a+ W9 d* l/ R: b `
4 \2 D& P B! j: Fvar
" C i! S5 \9 h5 V; K7 Yi: integer;5 |6 e% d% @& c3 V& F
begin
1 ?$ p1 B$ l$ D) N) Ffor i := ControlCount – 1 downto 0 do8 k- A9 u/ ], V. i4 Q' u# x. l
TFooClass(Controls).Font.Size :=; g$ \% U6 S( f
(NewFormWidth div OldFormWidth) *
8 U3 f8 f! t, J" {% ]8 iTFooClass(Controls).Font.Size;
0 A6 W6 k( I) j3 Cend;7 e( U* n: S/ p2 o9 x$ P% Y. }& m
3 u, }* a* v" \% [4 b/ U
用raise引发一个错误处理例程* F+ }9 j1 r. q% g6 O6 j
示例:先给出下面的定义1 L* H$ D; u1 ]' u
type EPasswordInvalid=class(Exception);
6 C0 [. y n+ ?. ^/ C这样你就可以随时引发一个”password invalid”的例外:& F, F, J% A$ q; ^2 Z
if Password<>CorrectPassword then
% M7 ~, E% f1 j, Vraise EPasswordInvalid.Create(‘Increect Password entered’);( C# e# C/ N; h9 N# R' c2 \% \
运行后,出现信息框
, l# d) R/ u5 u$ h( q5 LProject Project1.exe raise exception class EPasswordInvalid
9 h" a& ~ s" M! W5 g0 ~7 Wwith message ‘Incorrect Password entered’. Process stopped.
6 Q2 P( J8 Z) ]& |% ^' RUse step or run to continue.' D' g' Y7 m+ x' m2 M
再按Run按钮,出现一个信息框:
9 J: M& | @. J' ]) s: @% z. pIncorrect Password entered.; y( w' j+ X2 Y2 [( G# [6 Q8 q
o; f( }. R* M! U
5 m' g; d/ n6 x5 x/ g
从DEMO例程中学到的若干小技巧: q' e7 V" \& u1 \
在demo\internet\http\webbrows\main.pas中,
! X5 O4 u8 s! W/ zprocedure TForm1.DocumentSourceClick(Sender:Tobject);* K6 X% W$ G7 R4 n9 l: c+ f: Q" |
begin+ ]8 l6 @# i4 C5 X& ^4 q- J
with DocSourceForm do
$ s& L/ `$ D7 a5 q9 ^/ V% O6 z9 Ybegin% Q* v: F/ z3 ~$ f6 ?% _; y }) Y
show; // 显示HTML源码的FORM+ d# C) `$ F% z" _ `+ r
Memo1.lines.clear; // 清空memo1中内容
0 Y9 q- d- b! I2 o( l) ], A* w+ LMemo1.lines.add(HTML1.SourceText); // 植入源码
. C/ A3 J9 V, BMemo1.SelStart:=0 // ***9 a& P. R# ^/ N, I# [
SendMessage(Memo1.Handle, // Memo1的窗口句柄
% ~4 n6 b9 o$ [EM_ScrollCaret //将Edit Control中的caret光标滚动到视野中# [) V" }0 n& \1 k4 L. n
0,0 //这两个参数暂不使用
& v" }* f$ k$ t2 H8 q' Fend;
. Q4 [5 Q7 O* z& z! v1 n$ P# Uend;+ s& ?( q g0 x7 ~1 ~" E
(此SendMessage系一WinAPI调用,给一个或一组窗口发送消息,直到
6 R) x! a; F& e相应窗口处理此消息后才有返回值。相似的另一函数为PostMessage,
: `: X7 s8 E* G5 E6 D; ^# ]5 U4 l它将消息放入消息队列中后立即返回。)
1 p" ^3 P3 T3 L5 R8 z$ F*** 清空当前选择并将光标移动到指定字符(0代表第一个字符)。如同时
( {# P! C4 a8 n L) X设memo1.sellength为一非0值,可选择一段文本。/ R; F0 t# O* P6 W" M
- z5 G! z+ t: L1 E( Q+ Z4 {. }
# Z# P2 B* t4 T; N. Y奇怪的I/O error — 我在开发过程中发现下面这两条语句
$ ^$ H, X6 P* S Q( Xassignfile(fDesc,CDDatadir+describefile);
1 M4 t6 z- E% `7 \2 y' [3 Ureset(fDesc); * Z3 t1 D0 j) r0 I
每当我第一次运行到这里时,总会出现 I/O Error 183 的错误. J. d: B$ }" c0 z( N+ w
最后我想这也有可能是没有清除 ioresult 的原因.在两句之间加入
6 @% ?) F- d" j r, l `" }if ioresult<>0, C I$ B3 S( K9 i: q* M
then;
5 \: D- ?9 U6 a; q' e+ foooook! 可以了.
! \% |1 z0 L5 p- [. ~! G
; ^ [6 `) J/ T3 ^5 M
8 O8 Z, U7 p1 Y5 D: s" n值得注意的I/O error* t' g. x5 S0 D6 Z4 {/ ?3 ]' h
AssignFile(F, fname);+ F" q- J3 x5 I" P8 s
Rewrite(F);- r# I/ G. i) |) P
当文件 F 经 Reset(F)打开的情况下, Rewrite(F)会引发一个异常: I/O error 32
; g) c& m. [5 k2 v# D% H+ F反之,经 Rewrite(F)打开, Reset(F)也会引发同一个异常.8 P3 f, z3 D. C( w9 A, R- K
Reset(F)两次,closefile(F),再Rewrite(F),或反之,也会引发同样异常.
0 S' N' U' V! @3 y P& C% ^, l; X* H4 a/ j+ O. G" K0 x) \
# X2 g; s( f5 X# ]* c
) \2 w! M. u; _1 N2 L6 {
string和pchar的相互转换:
1 A# J" S, {8 \7 K/ D# cstring –> pchar: pchar(s
( E; d) @0 @5 H: ]" ?* B4 l+ btr:string);2 A# C( E1 Q6 k8 _8 V$ {$ ~
pchar –> string: strpas(p:pchar);2 L2 f* F% G6 U T2 N
6 r# L0 z/ G/ c, T7 T
; m5 J4 Q$ ?+ u6 c0 K/ N( L7 b( h% S6 O
在Delphi代码中定义数据库
! [4 Y' q3 R/ ?+ ]procedure tform1.create_tbl;
1 ?5 _+ `$ N9 N4 k6 Bvar tbl:ttable;
, Z M! H3 D3 {) z( Y( o* cbegin4 n, g( A$ C! r& b0 v. a0 x5 \* p
tbl:=ttable.create(self); // 如没有声明中的”tform1.”,Delphi不认这个self
_* X2 R2 `1 ~0 U& B$ }with tbl do; V! R5 B2 }/ c' Z
begin; u8 x% L( ~4 n+ d2 v5 k
datebasename:=;dbdemos’;
/ ]9 J# t' S t! t& q gtablename:=’my_tbl’;
* f% L" c/ E w5 V) o9 ]1 zwith fielddefs do+ i4 @' i7 B5 w J' h
begin) Z1 W3 D6 o- [
clear;
: z4 c# _1 G8 O2 ?6 h# v% \7 t. Fadd(‘No’,ftInteger,0,false);
: m& e: @ O z) s- ~add(‘Name’,ftString,0,false);
: h0 h) n$ K# [ T( @% W…; t$ K. E0 c* i4 q* k
end;
: {, M9 K/ p- `- l4 T# ?with indexdefs do
4 M# S& z3 T9 a, z0 ?5 ?, Dbegin
( V ~+ `* Y0 X; ]- Zclear;
0 [) {8 S& l4 J3 U) {' ?$ uadd(‘primary’,'no’,[ixPrimary,ixUnique]);' g, U! m" V6 a/ h& W% y- k2 c
…2 o1 [0 I3 q- c# v& Y
end;# \' S7 w. q9 C; X4 M( I& f& z
CreateTable;: d7 V, ?7 j) W& t+ F
end;* d: c" X; K1 W, Q* F
end;
7 o) W3 V- L! ]$ T- r) @2 K. J
+ k4 T5 o. X5 p' [3 C) {/ Y6 `1 z) @/ M% s* R; i
string、TStrings、pchar的相互转换(这里是我的个人经验)
" I) O: @( c+ N8 {/ B! U% u) |$ N$ j ?假设有如下定义:
0 h( U; ^! t3 Nvar% x: S& I+ @% X6 Z
p:pchar;
. y$ c- H! z: r7 l1 C3 Y) \s:string;/ W2 `) s: {0 _6 R1 M9 B
ss:tstrings;
1 N& F* r9 X2 Vbegin, g. ? {* F5 @+ i2 \0 d2 n2 j
ss:=tstringlist.create; // 开始时一定不要忘记创建ss
6 M/ Z$ G7 f- `3 z4 d5 n7 Q5 H. N$ Xss.text:=s; // string –> tstrings% R8 \$ I- F( X2 H4 M
s:=ss.text; // tstrings –> string& Q* d; ~! p8 z
p:=pchar(s); // string –> pchar! V) t/ t. J, B* \ w- b: e
s:=p; // pchar –> string. G! k1 t4 J+ p2 m% |
showmessage(s); // 合法语句
* v$ T5 ~) U, {2 C. T" z0 jshowmessage(p); // 合法语句
8 H7 Z- V+ C0 o9 d( Q3 E… …
! m# \0 X+ y- `: Z' O. ]ss.free; // 最后还要记着释放ss占用的资源
. x/ [- B% [* fend;/ ?) j9 ^5 Y( g1 c* T
0 V) p; ^' N+ i! `. c t. K! Y P- y8 J
+ X |7 o8 `' A# u; B* Z: W
在设计Menu时,常用的ShortCut可从下拉菜单中选取。但我发现可选的ShortCut有些不在列表中,如ESC,Ctrl-Shift-A等。我试着在ShortCut项的右边输入:ESC,竟然成功了。再试Ctrl-Shift-A,这回Delphi自动把它变为Shift-Ctrl-A