打印

delphi 技巧合輯

delphi 技巧合輯

INI文件的操作要点
8 m* T) Q7 ^; S* n& d9 Z(1)在interface关键字后的uses子句中加入
7 ~2 q+ R5 {  k; T* |uses …,inifiles;
3 K, k. [: B2 u(2)设置变量:var inifile:=TIniFile;
& v  w% X0 \2 V! b& D(3)使用前,一定要先做:% n0 D5 W& \& a6 Z) S7 k7 A
inifile:=TIniFile.Create(inifilename);7 r2 B6 X, G; J. W
我在这里绕了个弯子,写成
+ }# q! S6 J" p- B+ W% I( _inifile.Create(inifilename);/ E$ f3 Y8 q9 I4 W
+ M9 |6 u- ?* B1 i( j' f
TShiftState用来检测CTRL,ALT,Shift,以及鼠标按键的状态,, l8 L0 |7 r/ w! K
常常用在键盘或鼠标的事件处理程序之中。* o# [* a; D& H) c. T& M

/ r: c9 Z4 `& ]$ o" r$ E0 S# uDCU文件(编译的库单元)的重用) [; a. c  q- B' k2 d: ?
(1)在interface里的uses子句中引用。如Windows,Dialogs,
  S# t8 r! N# p0 V9 W! E4 D0 ~/ `等等,要求被引用的DCU一定要放在Delphi 3\Lib子目录中。% ]8 W" K' z# i& w: X% \
(2)在implementation里的uses子句中引用。如果是自行编写的
4 H! n/ ?) v7 a8 N& U# oDCU文件,应采用这一方式,并将被引用的DCU文件放入当前
) z" W$ _* O0 V* S( i7 }  P工程所在的子目录中。9 u1 P$ f# ]' |6 J) K/ z
executefile函数(在FmxUtils.DCU中定义)不能用在FormCreate
- z+ D! H1 |( A事件中。真奇怪……5 D4 A+ Y2 R) ^1 L) ^5 _: f3 R
3 y" N3 c" t' y: \& c4 w
内置的版本号控制功能& `4 @& X3 N2 k; f% E/ T
在Project Options中的VersionInfo项里,有版本信息的定制,  d& t5 Q" ]  s
包括一个有趣的版本号自动增加功能(Auto-increment build
# u- P4 O$ X5 f, K8 gnumber),即每Build一次,版本号中的Build Number加1。选中9 {- d( m+ y, w2 @
Include version information in project,编译,用资源管2 M; y# L+ i" a+ j! K+ ^0 u
理器里找到生成的.exe文件,点右键,查看“属性”一项,就: d& I. l( z1 w: S
会看到在属性中多了一页“版本”,里面就是你刚才输入的各* |1 m1 S* v, r) s9 ]$ W" ~
项内容。
+ c4 b( h. K' f8 Z! x
+ t# r( X0 k/ n, n7 p0 C; U% Y
4 c! n  }5 M# i7 w3 u定制Speedbar
; s" k/ P' C3 J" h右键点击左上角的加速键条(speedbar),选中Properties,
7 z# t8 p- ^( S1 Q9 C# t7 C3 d, }6 b在列表框中找到你想要加入speedbar的命令按钮,将它拖到  L$ O# C# j. b' C. j4 z; o
speedbar上的合适位置即可。如果speedbar上没有多余的空间: u9 J; f' D# t' W3 m5 @; G
来容纳新的按钮,可把鼠标在speedbar右框处变为双向箭头的
9 [  {, |* A* i4 n; y) y形状,向右拖动一段距离,就可腾出空间。如想删除speedbar* a* ~- C7 `/ ?2 ^" n) L6 e
上的某个按钮,可简单地把它拖出speedbar的范围,就能删除。
3 Q3 U2 o" H& C4 X
# z" d3 d# X( l7 o( t; b8 B0 I/ L* k- T$ t  M( K
计算出的字段" B) K6 D0 g6 z! [: h
在写一个程序时,我要在DBGrid中显示出一个memo的部分信息,当我把那个
3 p* ~: g5 G9 _memo字段放进去后,运行时只能显示出“(memo)”字样。从书上找到计算字; s5 P) K' D& a5 e
段的用法后,我在TTable中增加一个计算字段MemoHeader,宽度为40,在此& [# V; i# Q( M  b0 P3 ~
TTable的OnCalcFields事件中输入:( L/ ^0 B9 ]8 d  E* r+ k/ ?) i  ^, k
with MyTable do
7 [) Y! \( r! S0 tFieldByName(‘memoheader’).asstring:=FieldByName(‘memo’).asstring;
0 O$ X# I# X2 w; _; a2 m8 p$ l$ Q/ p在DBGrid中放入MemoHeader,运行,OK!
) D- b6 X9 H8 {4 t
$ S, Y0 `$ B1 W0 ^4 H
: a8 X( X7 p8 O9 c字段编辑器3 S# q$ ?0 W0 v
解决了上面的问题后,我继续学习字段编辑器的作用。原来,DELPHI通过字. r4 C8 y0 G6 F1 l* Y, K& ^* v
段编辑器,近乎完美地实现了数据库的字段级的控制,这包括:
, c- Y, {1 f) m9 h1)字段在DBGrid中标题、宽度、能否可见;0 X! J. T+ \( W; S
2)字段的显示格式和编辑时输入的过滤条件;
4 ?3 E+ f9 e9 P. |) t3)字段是否只读;
' U9 l: w9 p3 ^5 M4)字段的类型:数据字段/计算字段/查询字段/内部计算字段;7 U$ A8 t$ J7 }. L7 a5 S/ K
5)字段的显示/赋值/修改等事件的定制。
! @" V$ K8 w& z8 O: h  }+ N  Q, s& [1 c+ W& q& w+ P- g9 o: ~
+ }/ X3 Y. @! `- o
设计Form时的快捷键* A0 ~* w; {2 J9 w
Del 删除所选组件
! N, a1 w  c! ~Esc 选择当前组件的容器(通常是Panel,Group或Form)! ]2 X) C6 K/ N) L
F11 在Form或Unit和对象检查器之间切换+ y8 Z9 ~4 y0 J6 p, t! y
F12 在Form和代码编辑器间切换
1 c" z  U( d# q" E1 e( f% ECtrl-F12 显示“查看Unit”对话框
) ]2 C4 s4 U& L! E; N( ZShift-F12 显示“查看Form”对话框
; R; S0 n6 O) m' S- h7 yTAB 下一个组件! t6 b" x2 E& `) \$ Q" S) R
Shift-TAB 上一个组件( |1 C# S/ u0 e' F
方向键 选中此方向上最近的组件6 S" u, s+ i7 U& B# C' i6 H
Ctrl-方向键 将所选组件移动一个点4 W. q  ~/ t; M- W
Shift-方向键 将所选组件改变一个点的大小+ p) o) o$ @3 m+ U$ `
Ctrl-Shift-方向键 将所选组件移动一个格
6 V* a4 |6 `6 j4 M& JShift-click 按住Shift键再用鼠标点击组件,可以选择多个组件。
- N; G, a0 `0 `# f1 r6 M9 S) @! e! g; f8 w–= 下面这条是我摸索出来的 =–6 `! i) h/ R2 R% v/ f# K
Ctrl-drag 按住Ctrl键在一个容器组件(如Panel,QReport,Groupbox等)
- w/ |! P7 I3 H& a& Z里拖动鼠标,可强制选择鼠标拖过的矩形框中的所有属于此容
7 K% j4 x0 v5 e# ]" A2 u0 x+ F: p器的可视组件但不包括该容器组件。
  U- V7 d& n8 |; |$ q, |( w! y8 t# W
& x2 A- X( K7 d$ W5 N+ n
使用QReport的若干经验
8 k: Z5 Y. d7 N1 ?, o  N1)QuickRep1.DataSet:=query17 A9 C6 l/ v0 A' e- x. }8 z3 m
不然无输出结果; Z# x2 a; ^- l
2)从qrpt2man.doc中查知,格式化输出结果的方法是:2 V; c4 ~; c8 y* M$ R* i
在QRDBText.Mask中设为.00;0,将使输出带两位小数。; j9 Z: d9 @: I6 f9 B/ m8 H% @
3)设置Group时,先加入一个QGroup,再加入一个QRBand,将QGroup的
$ M3 A/ e- v$ L9 bFooterBand设为刚才的QRBand,就可将其联系起来。& J, G# J( G7 T
4)在Group中打印的合计数,其ResetAfterPrint设为True,可实现分组合# u6 ]) e3 A- Q) A# J
9 @* O0 E8 T) a: }
format(‘%*.*f’,[8,2,123.456]); //等价于format(‘%*8.2f’,[123.456])0 m/ v; K' D! q
format(‘%d %d %0:d %d’[10,20]);: S9 I5 I/ S' ]6 Y1 `
7 h' K1 v: t3 o; Q9 a
' Z5 b% ^0 E& g! e, V  |: z
* e) p8 t5 q. v3 P5 }0 Q
播放一个wav文件
% w  L- V6 a% d  ^5 j, I, p' {# T; `. Zuse mmsystem;
) B3 [0 D4 E0 G, P$ s7 r- I/ G! P! hSndPlaySound(‘hello.wav’,SND_FILENAME or SND_SYNC)
+ C. n9 R# ~( y1 }
9 M8 t, h* n+ c! q) P) z使你的form适应不同的显示分辨率4 h, F/ J, a* J2 L
假设你在800*600的分辨率下设计的form,第一步:
& J1 W( d9 \. t4 T# i  ?& Pinplementation
' W4 m6 ]3 @- w, j6 J- b( n% iconst
3 A& Q+ X/ |2 @& l% XScreenWidth: LongInt = 800; {I designed my form in 800×600 mode.}
% Y' p6 }, G; e6 ^ScreenHeight: LongInt = 600;* x+ P3 s  L, M% `9 t' \! [

( g! s. ~! h0 S' N{$R *.DFM}
; M$ y7 Q) I( U
7 D; Q& ?, u3 ^+ L3 {0 c, \; z- n2 b  dprocedure TForm1.FormCreate(Sender: TObject);
; z# e+ G" }# e8 ]2 tbegin
( [  u9 b; _$ Y% X" gscaled := true;
7 `  c7 T1 S) w: `1 S, l3 |4 Jif (screen.width <> ScreenWidth) then7 h; t1 y, Y! G6 B) B6 b7 L/ W
begin- i) T+ A; g7 u( i9 ?) }( w
height := longint(height) * longint(screen.height) div ScreenHeight;2 s% b8 `1 ?4 i
width := longint(width) * longint(screen.width) div ScreenWidth;
8 s6 q, L8 p/ U# ^0 AscaleBy(screen.width, ScreenWidth);- m( z( C: G4 w% f, \, H/ o
end;
5 X0 [3 Z6 `6 H! h4 l4 ~* ^& Dend;
6 c3 X. j  x+ b5 ^6 L& Q) {3 ^5 S, F
下一步,要让每个子控制的字体改变到合适的大小:
) A! g+ X; v& N: Vtype8 l$ M. P# [2 z& S% Z
TFooClass = class(TControl); { needed to get at protected }! e, F8 r* L7 O8 x$ X7 F
{ font property }9 q( m$ P6 |4 o

/ ^4 x8 }( N- Ovar
' J  m$ R! w, C5 e( V) k, ]( Ai: integer;5 ]) b. n8 `& O. N4 k
begin9 q& O9 |4 D" `5 I2 a# K
for i := ControlCount – 1 downto 0 do
" v0 N/ T# R7 L* g3 sTFooClass(Controls).Font.Size :=7 v/ b. n$ W' H6 u) R
(NewFormWidth div OldFormWidth) *& E* t# |5 ^4 e. |! G& A" _. b1 j
TFooClass(Controls).Font.Size;
7 x' \* J' Y& |$ g# Kend;& m8 @2 b0 M" ]0 U

  t8 m' {' T& L; C用raise引发一个错误处理例程
: q  F5 j3 t; }9 _! b示例:先给出下面的定义
! s: _$ B( t9 }" ttype EPasswordInvalid=class(Exception);
5 o# d/ A: u& \% Z% l这样你就可以随时引发一个”password invalid”的例外:
+ @& b" }' k: i! a1 b4 ]& i1 J4 j+ Xif Password<>CorrectPassword then* b! K9 A# }/ w8 q1 D
raise EPasswordInvalid.Create(‘Increect Password entered’);
# d* k8 `) Z* @1 b运行后,出现信息框# ^( F' u% b" F, A+ r9 j: T& I& C
Project Project1.exe raise exception class EPasswordInvalid
6 a$ c8 p* ^# |; c8 ~2 R1 Lwith message ‘Incorrect Password entered’. Process stopped.
' I9 j% G# |  a0 h0 CUse step or run to continue.6 b: b5 c' O2 X6 F, k
再按Run按钮,出现一个信息框:) k6 K. V/ l- v, [( p
Incorrect Password entered.( a/ t0 w& m6 w* d

- J" s- n. p6 \& A. b
, r4 Y9 h( e# N6 ^从DEMO例程中学到的若干小技巧
2 F& J; ]% z7 s9 P在demo\internet\http\webbrows\main.pas中,
) `4 x: J7 e0 W* xprocedure TForm1.DocumentSourceClick(Sender:Tobject);
* ~% }, m' Q( w# }5 h  zbegin
* o5 {( H' u( H# z, `! C3 ]with DocSourceForm do
5 o& N3 ^; c3 o8 E; w0 s* X" ibegin
+ T' d0 }6 [7 F! U7 y3 n! ?1 [9 hshow; // 显示HTML源码的FORM, w- a) E1 ], |5 C; E
Memo1.lines.clear; // 清空memo1中内容" d' n7 }# a( ?7 J( P
Memo1.lines.add(HTML1.SourceText); // 植入源码
. s* T4 c; |' x; t$ r2 k2 A( Q% eMemo1.SelStart:=0 // ***
9 C5 ~6 U6 W& {( k. ISendMessage(Memo1.Handle, // Memo1的窗口句柄5 Q1 W3 p( Q# P: v# B8 ~
EM_ScrollCaret //将Edit Control中的caret光标滚动到视野中  R& o5 Q, P+ Y+ @% _- B
0,0 //这两个参数暂不使用
) A9 l9 P8 g, X8 A: K5 ^) aend;
' ^; @- O: V1 T7 Dend;" B6 G  r+ h# @6 n: Z2 b- w% u
(此SendMessage系一WinAPI调用,给一个或一组窗口发送消息,直到1 t- T9 L2 i. L" [2 z( }
相应窗口处理此消息后才有返回值。相似的另一函数为PostMessage,' D% @4 m: b$ e) Q! _1 y% }3 ~4 G9 [
它将消息放入消息队列中后立即返回。)
4 p6 e. @% P' D( ]8 [- R# G  W4 v*** 清空当前选择并将光标移动到指定字符(0代表第一个字符)。如同时
2 `% r' q  S6 H7 r1 q; r设memo1.sellength为一非0值,可选择一段文本。5 x+ `2 E. L' K' G
: V, ~2 s( x& N; j$ m5 \
, |* F7 N* N5 B$ U  [3 f9 F, o9 J
奇怪的I/O error — 我在开发过程中发现下面这两条语句
5 [0 O% `" N4 h/ yassignfile(fDesc,CDDatadir+describefile);
6 h8 q+ i0 d3 ^reset(fDesc);
$ h2 z) O) `/ w0 d/ d  t; \每当我第一次运行到这里时,总会出现 I/O Error 183 的错误.6 @* a; _0 J! _' j- J
最后我想这也有可能是没有清除 ioresult 的原因.在两句之间加入4 D4 o% l, Q" ]8 A* I, K& q
if ioresult<>0: l; R8 h1 S* e( j6 |
then; 1 O4 Z, C7 c$ v" k
oooook! 可以了.6 P) D- p/ \# ^2 G
# K5 {& l! Y' |9 ^

: z2 S3 x( B! `. H值得注意的I/O error
0 o, W/ c; v, \AssignFile(F, fname);
1 F4 }7 G. K; p4 l; H5 HRewrite(F);
: W! P0 H4 {, i3 M当文件 F 经 Reset(F)打开的情况下, Rewrite(F)会引发一个异常: I/O error 32
; D  H) j2 @( X: z5 C3 q1 y反之,经 Rewrite(F)打开, Reset(F)也会引发同一个异常.6 l7 i# Z9 [0 d) Y6 C: f
Reset(F)两次,closefile(F),再Rewrite(F),或反之,也会引发同样异常." A( N- e+ e1 Q3 E# |+ Q, B* E: [
+ o7 t* ~* ~, u! n2 F1 q7 ?) T- ~
6 L4 \  ?  `; |5 r0 o4 O
! u9 u5 N+ m+ h& ]
string和pchar的相互转换:
. {7 W8 a1 D+ x' _8 y/ }string –> pchar: pchar(s/ K) i& J4 h9 f' O. K8 @$ ?
tr:string);4 u0 X" g" ~0 m5 l7 S1 I1 |
pchar –> string: strpas(p:pchar);
! A# h! S; Q- E; ~3 h9 \7 ^. F
$ H2 Z7 d# V* G  T* ^) v2 r9 E8 _  o, E; ^$ y" X9 }- A
$ L3 F3 M8 ]- c; `
在Delphi代码中定义数据库6 ]: E! d3 s% \5 D7 G7 ]
procedure tform1.create_tbl;
6 v; m2 E+ H3 _( c$ [; Jvar tbl:ttable;- n8 X2 w9 B9 S  k
begin
4 B4 {( J, S3 _9 t1 Htbl:=ttable.create(self); // 如没有声明中的”tform1.”,Delphi不认这个self
# N2 W9 J4 {, J1 H9 j% o& B- Kwith tbl do
8 W( E$ w& W. u& D4 X& fbegin
4 C1 H7 ^) ~) @& L3 [/ \0 [datebasename:=;dbdemos’;
$ S; W6 q4 \; _tablename:=’my_tbl’;
# c, M8 l6 S# X; u# F! }. ~- Dwith fielddefs do
% S; y3 K6 @0 \3 [4 d$ xbegin" d" o: D/ U! X8 G, e1 w# c) }
clear;0 V3 e0 z  P; r
add(‘No’,ftInteger,0,false);
( g9 C) s- s- t8 n* Q  Xadd(‘Name’,ftString,0,false);
6 c6 q, d# e! Q& r0 g  m! e3 [( E2 f
end;* |. z1 U/ J4 x/ i0 g
with indexdefs do
3 s7 y3 @9 d$ e$ o# o. dbegin- y% E7 V: n1 c- T5 Z4 M1 O
clear;7 q; ]. ?4 U2 R) x& A( p
add(‘primary’,'no’,[ixPrimary,ixUnique]);4 ^4 l7 _8 k3 p
) a5 z: \3 Q# M4 G. o+ i2 }
end;/ L& s& h0 O6 @) g+ s- m/ F
CreateTable;
& R- K8 |  s4 I& K$ j* b  O6 gend;
2 A+ x0 e% h* F; g! V9 Q* Rend;
) f0 o9 {; d5 l7 H) E; P7 N9 M/ `4 b+ u0 m9 N& B5 e; x3 O

3 u# w" G; Q; Fstring、TStrings、pchar的相互转换(这里是我的个人经验)
8 |  C9 {& n# S假设有如下定义:
% Z, s/ b! s- p& r) Xvar
0 H3 s% t7 s  Q* O! Bp:pchar;) i/ F# `1 E2 J1 z, q
s:string;
: y6 a6 u" C& s4 m" p/ W+ Ess:tstrings;  X6 ~1 c, U( C/ s$ L
begin  v$ p( _3 @5 ^. @9 i9 Q
ss:=tstringlist.create; // 开始时一定不要忘记创建ss# t! G. D7 a" I. }' m
ss.text:=s; // string –> tstrings
) X. t$ v1 Y+ t* d, Es:=ss.text; // tstrings –> string
* o) |3 p# r- c' ep:=pchar(s); // string –> pchar# |6 d) u+ U: f7 J
s:=p; // pchar –> string  m0 v8 k- s1 {4 W4 r
showmessage(s); // 合法语句
0 c) x  e9 m5 c8 A4 k5 x( fshowmessage(p); // 合法语句# b; {7 X! F! a, A
… …
  ]. ?+ D+ ?2 y2 R  Y" ~+ Wss.free; // 最后还要记着释放ss占用的资源+ s) f4 u7 h) R( k9 X+ e! h/ A
end;4 J; s7 ?$ e. t7 R3 Q
: F% h, B. A0 m  u) f. |9 \3 ?8 `! k
2 ~: c5 g; z/ e& R
5 j4 H9 n3 F6 j5 S
在设计Menu时,常用的ShortCut可从下拉菜单中选取。但我发现可选的ShortCut有些不在列表中,如ESC,Ctrl-Shift-A等。我试着在ShortCut项的右边输入:ESC,竟然成功了。再试Ctrl-Shift-A,这回Delphi自动把它变为Shift-Ctrl-A

TOP

發新話題