Board logo

標題: delphi 技巧合輯 [打印本頁]

作者: segaa    時間: 2010-3-10 04:40 PM     標題: delphi 技巧合輯

INI文件的操作要点
3 f# O: E+ \! {9 W/ ^, ]# [2 g(1)在interface关键字后的uses子句中加入
& A6 ~: w1 G- v- |7 m- X9 N4 }uses …,inifiles;8 c2 b" a4 N( L" T+ W3 q4 Q  I
(2)设置变量:var inifile:=TIniFile;
# F2 W+ |0 N( t. n' D(3)使用前,一定要先做:% d, t7 a; Q  j' D( [
inifile:=TIniFile.Create(inifilename);
$ T5 q& F" V# T) A/ J: X我在这里绕了个弯子,写成7 l" f! T; a& X9 t' [  h
inifile.Create(inifilename);
8 B: p$ O( u" G* d3 F/ M3 K1 X8 V1 \- d
TShiftState用来检测CTRL,ALT,Shift,以及鼠标按键的状态,
8 V& z. s/ m' W常常用在键盘或鼠标的事件处理程序之中。  \5 E. }4 g% _* o$ f/ j% T
' Y3 v: }3 P1 n
DCU文件(编译的库单元)的重用
9 {) Z3 d% v, H6 Y; O) Y# ]9 {) X9 Y3 u4 S(1)在interface里的uses子句中引用。如Windows,Dialogs,
5 W& f6 k, u' }& O- i5 Y7 S等等,要求被引用的DCU一定要放在Delphi 3\Lib子目录中。
% K1 s, S0 L- v# ]  D6 E* o8 y* n(2)在implementation里的uses子句中引用。如果是自行编写的: X, D- j: E3 U; s
DCU文件,应采用这一方式,并将被引用的DCU文件放入当前
! a  S8 B, g9 q( d) n5 e0 b工程所在的子目录中。* j  p. G2 E; L3 u
executefile函数(在FmxUtils.DCU中定义)不能用在FormCreate& _. E, E* r( d
事件中。真奇怪……
. V1 n, O2 v  i1 p0 g( X6 o* [" Z/ ^( J! u: r# [2 G
内置的版本号控制功能5 u/ |8 f# G* y9 \+ {
在Project Options中的VersionInfo项里,有版本信息的定制,
: X; k# z3 B6 ]* h& z* j包括一个有趣的版本号自动增加功能(Auto-increment build
! @  M* G; C9 v; `$ }8 {number),即每Build一次,版本号中的Build Number加1。选中, _4 Y) d) v0 b
Include version information in project,编译,用资源管
+ O; z/ h' n( b0 X! i1 e理器里找到生成的.exe文件,点右键,查看“属性”一项,就
, B: t2 O, U% E8 c会看到在属性中多了一页“版本”,里面就是你刚才输入的各
+ i1 ]$ n, \" D0 ?# F3 d7 q项内容。) J& D4 ~0 c. ?  p8 C. t

. u) d+ _6 O0 i! Z  @# y
: w+ x, R( I- q' p3 d3 z定制Speedbar% v5 Y% c* U$ _2 ]
右键点击左上角的加速键条(speedbar),选中Properties,1 F* H" S5 K# H: Q8 N5 G" c
在列表框中找到你想要加入speedbar的命令按钮,将它拖到
9 U& P: P( {( U! V! i/ cspeedbar上的合适位置即可。如果speedbar上没有多余的空间
& C6 a: L9 v9 d/ k  A7 Y; b- S1 n来容纳新的按钮,可把鼠标在speedbar右框处变为双向箭头的3 b  L! H) j! {; R' _
形状,向右拖动一段距离,就可腾出空间。如想删除speedbar! U, g- M( f3 i5 V) K
上的某个按钮,可简单地把它拖出speedbar的范围,就能删除。
; N' Z% u( ?8 H( b& _. T6 O2 l
5 q# i& _) h" a$ m, T" t
% c$ z+ K; ~5 j  l' A/ J) v$ [+ Q& K计算出的字段4 T) Q5 w, i8 d- F
在写一个程序时,我要在DBGrid中显示出一个memo的部分信息,当我把那个
2 ]4 t/ v4 x8 Rmemo字段放进去后,运行时只能显示出“(memo)”字样。从书上找到计算字  F/ q4 u3 @  J% I8 h
段的用法后,我在TTable中增加一个计算字段MemoHeader,宽度为40,在此
$ n. @0 l- w+ c& RTTable的OnCalcFields事件中输入:
6 u- q& q* ?  G0 swith MyTable do
' F. O9 C7 s5 A# Z, ]; A/ dFieldByName(‘memoheader’).asstring:=FieldByName(‘memo’).asstring;' y* L1 b* u0 Y+ S* A
在DBGrid中放入MemoHeader,运行,OK!3 X" r) f6 D9 h1 `! p

- ~( K; N2 g, u9 O9 F+ Q5 {
; `: d% x1 ^5 M" T字段编辑器
6 q) d5 L; F4 T# E( U3 \解决了上面的问题后,我继续学习字段编辑器的作用。原来,DELPHI通过字$ S1 \! E& W- q  [6 J4 n/ Z
段编辑器,近乎完美地实现了数据库的字段级的控制,这包括:
+ G5 v/ L0 v* l2 f1)字段在DBGrid中标题、宽度、能否可见;+ {& |: A6 p$ ]3 e, J0 U
2)字段的显示格式和编辑时输入的过滤条件;
1 R& Q8 G4 ?3 [! G3)字段是否只读;
  b! b$ H( s6 g& f4)字段的类型:数据字段/计算字段/查询字段/内部计算字段;0 r- A  g: D* c/ j2 a$ \
5)字段的显示/赋值/修改等事件的定制。
9 q# x! R* N  Z( N8 _3 }% ?
1 k: T4 f7 _% u7 z) N9 w& I
* P2 w! q' X, r4 U2 D; T设计Form时的快捷键
: N4 T1 H/ H+ u( `& `1 qDel 删除所选组件
: Q4 |! U& X. f. N/ T' l1 UEsc 选择当前组件的容器(通常是Panel,Group或Form)4 h0 Z4 q, f$ C) o+ {5 q7 m
F11 在Form或Unit和对象检查器之间切换" G3 C6 J3 U" [$ S/ g
F12 在Form和代码编辑器间切换' b& m: E  _# z0 g1 }' J. [. c: K2 F
Ctrl-F12 显示“查看Unit”对话框
' [; T7 u; \9 rShift-F12 显示“查看Form”对话框
; M& m9 q( p6 K" B# Z% Y& u0 aTAB 下一个组件( c% n' E- `- F8 I6 a
Shift-TAB 上一个组件
* v0 c4 r' B3 h6 _4 H% e5 Z方向键 选中此方向上最近的组件6 T" [) D) V8 q( B0 `/ n
Ctrl-方向键 将所选组件移动一个点
+ t2 l' h  m! `7 p# @/ ZShift-方向键 将所选组件改变一个点的大小# O! v6 J2 F! g: f* j7 c$ Y' u
Ctrl-Shift-方向键 将所选组件移动一个格3 V6 Y( k+ k* [% n& B. x4 J
Shift-click 按住Shift键再用鼠标点击组件,可以选择多个组件。
* p: p0 c, g: a& P- D  ]–= 下面这条是我摸索出来的 =–$ h& H: ]+ N4 R6 @0 v
Ctrl-drag 按住Ctrl键在一个容器组件(如Panel,QReport,Groupbox等)8 {9 `3 T+ d: }7 M# b. A* {
里拖动鼠标,可强制选择鼠标拖过的矩形框中的所有属于此容
, Q( L+ @! g5 n, r# B- _器的可视组件但不包括该容器组件。) d/ m2 T9 x+ x+ K3 y9 t  X- y
2 G: p, p/ [8 S/ S
$ v9 e! H" @* |
使用QReport的若干经验; J7 M+ T$ A- Q$ J5 ?
1)QuickRep1.DataSet:=query10 ^8 S: k! {+ D( f) b" b
不然无输出结果+ w+ w5 H4 i* x) X% w( l- A6 n
2)从qrpt2man.doc中查知,格式化输出结果的方法是:
- J  l, V, p# O; P在QRDBText.Mask中设为.00;0,将使输出带两位小数。
. |" F' U. N- {3)设置Group时,先加入一个QGroup,再加入一个QRBand,将QGroup的
$ A2 j+ Z% C/ F0 }8 k4 }FooterBand设为刚才的QRBand,就可将其联系起来。
. ]* F' f& C+ F9 U0 ^& A; d$ }& G4)在Group中打印的合计数,其ResetAfterPrint设为True,可实现分组合
! K- g' H2 O+ j1 m6 t) l- V/ s) K& T2 H
format(‘%*.*f’,[8,2,123.456]); //等价于format(‘%*8.2f’,[123.456])  m( _2 p/ \% Q! l$ p! ]7 {$ C
format(‘%d %d %0:d %d’[10,20]);
9 k& {+ k6 R6 ^# J" T
$ R8 _% L3 b* A- ~- E! m- ]4 u
8 U7 E/ e) G/ X8 W( E! W1 x' n+ v$ n3 V; }% s* `2 h  v' u4 O1 E
播放一个wav文件
) f9 T- a. Y$ l# Q4 Zuse mmsystem;# y: G* V0 z9 i. d0 r
SndPlaySound(‘hello.wav’,SND_FILENAME or SND_SYNC)
) \6 z& k% a/ k* _& {$ v/ F2 V0 r% E( Y
使你的form适应不同的显示分辨率
6 y1 J3 A  p$ n$ J  d/ L6 K! z假设你在800*600的分辨率下设计的form,第一步:  E( R4 ]# O- m9 O* w# k9 p
inplementation: r/ V$ N3 D& E; b# _
const8 ?4 K) c6 _- P' X' W! y
ScreenWidth: LongInt = 800; {I designed my form in 800×600 mode.}
) {5 F1 M; K9 U5 f" D- J% s4 }ScreenHeight: LongInt = 600;0 e& u% `2 e" Z3 e
/ g  W. f) v$ M# D  w! O
{$R *.DFM}1 _3 Y5 B7 x- }1 d
# b4 ?  e. _" Z- f
procedure TForm1.FormCreate(Sender: TObject);
: T1 o+ B6 t9 Ubegin
. b  Y) m1 p. A! Y+ @  fscaled := true;
# u. }( o# K" oif (screen.width <> ScreenWidth) then; C" ?, ~  K! d" B/ N1 o, p7 Z, D
begin) ?1 g( N. K/ t* ^+ ^$ O) P4 q+ a
height := longint(height) * longint(screen.height) div ScreenHeight;$ z, `* ]# D5 n" x* p
width := longint(width) * longint(screen.width) div ScreenWidth;+ _  `2 Z, e* v  u2 S
scaleBy(screen.width, ScreenWidth);7 x% \1 H3 r6 E2 k; l
end;
! N( L0 F; D2 A; L% `end;
% X  g/ L3 r$ s' j) t/ p# D' w( [% c& A- Y& ^+ N5 {# r% y$ |/ y' r) K
下一步,要让每个子控制的字体改变到合适的大小:
5 p7 A* j* @4 stype
" D+ T( b2 J  P2 s5 CTFooClass = class(TControl); { needed to get at protected }- W" H: _! h: l5 u; l. @% @
{ font property }3 I1 h* N; N/ N' d
5 M& \1 L% w  @
var* ~0 {* z/ Q5 j/ B% I
i: integer;  N) A7 x& {; Z) {& {( `  K
begin
- K/ h; G1 _9 N6 O& o4 K* e' tfor i := ControlCount – 1 downto 0 do
0 A& P7 }. z: R2 ]9 I% w3 K' mTFooClass(Controls).Font.Size :=
4 O* h9 t( m3 y+ j(NewFormWidth div OldFormWidth) *( |, i7 G3 h) s! V5 u; k
TFooClass(Controls).Font.Size;
. t  m" I0 C: {* i5 D) _" e5 Wend;0 m% Y: c2 D& B8 K# {2 x1 q6 z

2 v; P: P# ?9 i  x- ?用raise引发一个错误处理例程* {9 |  z7 w; P1 f$ p
示例:先给出下面的定义
: \" h( c3 M! b7 ]$ q" {, o1 _type EPasswordInvalid=class(Exception);4 U$ x+ t0 H! \
这样你就可以随时引发一个”password invalid”的例外:9 {5 W4 I6 X9 J+ a( |2 o- i
if Password<>CorrectPassword then
4 `$ I, E" I' z6 h  a9 s! Draise EPasswordInvalid.Create(‘Increect Password entered’);
7 M; b# A+ M) R5 k2 l+ N, }2 T" Z运行后,出现信息框, M5 S& u, V2 N7 _" X- W
Project Project1.exe raise exception class EPasswordInvalid
$ m4 \% V* C, \% i: B1 z* Mwith message ‘Incorrect Password entered’. Process stopped.
2 R" G, U# H# H7 d( s0 ~Use step or run to continue.4 Z( `9 k2 O: T% a
再按Run按钮,出现一个信息框:6 s3 F. {/ D) v0 m9 F
Incorrect Password entered.
: P) ~$ h$ C! h0 E5 u  ]) I8 _) r2 }  |

4 V; o4 q; @& W从DEMO例程中学到的若干小技巧
7 N+ X. j; d# g* _& `/ H在demo\internet\http\webbrows\main.pas中,
- p5 R' ]' ^# Aprocedure TForm1.DocumentSourceClick(Sender:Tobject);
! S7 Y* x5 p+ F3 \7 D* Jbegin
- m: {% `/ o5 Q$ k( [with DocSourceForm do
& C1 G! b1 x7 c4 o3 k7 obegin: L' `; Q$ h- {0 u) X+ a
show; // 显示HTML源码的FORM
" x  c+ o6 Z+ n8 j1 |: p3 K# E1 TMemo1.lines.clear; // 清空memo1中内容
( a" ]: G& j0 c- cMemo1.lines.add(HTML1.SourceText); // 植入源码4 K/ \/ S* i! _  C
Memo1.SelStart:=0 // ***
" ]$ b) W3 N, j+ ?SendMessage(Memo1.Handle, // Memo1的窗口句柄  b6 }: q8 g/ u0 r+ Z8 K& [
EM_ScrollCaret //将Edit Control中的caret光标滚动到视野中* H/ L  {- H7 L2 O0 B3 y+ p0 x
0,0 //这两个参数暂不使用. S* }- P4 Q/ v' `
end;* `( @! v( ]  |. L/ i
end;
0 L5 r# O8 W/ h- v1 S4 W' H1 @(此SendMessage系一WinAPI调用,给一个或一组窗口发送消息,直到, u* z. g$ Z- q, C5 x( h4 n$ Y! |
相应窗口处理此消息后才有返回值。相似的另一函数为PostMessage,# j  O* w7 ?0 n1 [$ C
它将消息放入消息队列中后立即返回。)
, \0 }2 }: y7 ?  P+ u8 W4 i*** 清空当前选择并将光标移动到指定字符(0代表第一个字符)。如同时
6 f) z  x7 `% p/ ~# p( [! g设memo1.sellength为一非0值,可选择一段文本。
: d& r3 K% s7 N8 B2 j" W
1 K' ], x; `( F. }6 C+ `: N! X% K) W7 [0 g2 N
奇怪的I/O error — 我在开发过程中发现下面这两条语句
. ~! h4 D. j+ g6 L+ Sassignfile(fDesc,CDDatadir+describefile);( |6 W2 X5 w8 T$ Q
reset(fDesc); 2 @2 T  m4 h) m7 _' d5 `
每当我第一次运行到这里时,总会出现 I/O Error 183 的错误.
& f: X4 w+ F) D& D最后我想这也有可能是没有清除 ioresult 的原因.在两句之间加入- k  f7 y1 d0 y! \$ z
if ioresult<>0
' v, R6 w$ O2 Nthen;
- O% M+ q3 j' ?5 L# r) G: w( Qoooook! 可以了.
7 a% F: {3 X9 F6 N% V+ ~: @" Y7 Z' X0 p

8 W2 m# S; Q" c4 U- D& }4 Y值得注意的I/O error
  b: X# V7 F2 @6 eAssignFile(F, fname);
. s/ ?) P& _+ h2 Q% |Rewrite(F);
' d/ X2 K$ l/ k' t1 a5 q. u4 K* l当文件 F 经 Reset(F)打开的情况下, Rewrite(F)会引发一个异常: I/O error 32# C+ y, l# M6 k% }* S# U
反之,经 Rewrite(F)打开, Reset(F)也会引发同一个异常.% D/ Q! z4 Q& j# K
Reset(F)两次,closefile(F),再Rewrite(F),或反之,也会引发同样异常.
& E- T( K* k% x2 t9 x! K
! ]: U, W8 @, N5 L# @$ A$ K" D6 N+ j& u, S( B5 r

1 L6 y9 W* q1 Bstring和pchar的相互转换:9 o/ g0 a- `# }
string –> pchar: pchar(s% o" e; E8 v' s
tr:string);
: a% p8 A5 ^( e( f3 V- }! j7 z' Npchar –> string: strpas(p:pchar);
8 B& |; @' {! ]- x
3 z3 d7 {. u& N, P# y
5 }$ g+ z# l$ [9 Y
+ _  Y- M* p  {! _9 f! F' C在Delphi代码中定义数据库
% V: m  h8 H9 i/ uprocedure tform1.create_tbl;
5 E9 V' z8 B, @1 a8 F# Cvar tbl:ttable;
3 H7 L; a3 Y- Y- e! w, G9 R9 xbegin
6 y0 p$ ^% Z7 a: U. gtbl:=ttable.create(self); // 如没有声明中的”tform1.”,Delphi不认这个self5 }" L0 O7 [' y3 b* D2 v4 p. H. i# n% o
with tbl do! k9 C, W+ l3 B( m. a1 K2 J* }3 r
begin1 b5 i$ e- n) G, E  O, n' ?
datebasename:=;dbdemos’;: c3 E# M% c- Q0 j
tablename:=’my_tbl’;: B2 j& f9 s& ]- u" B4 f3 q# y
with fielddefs do, F: w; h3 _! [0 o  B  `9 O
begin
% p. n7 `! e* o" O" zclear;1 h$ j* }6 L! }4 v1 k& i
add(‘No’,ftInteger,0,false);
0 L# \/ i  G$ s( gadd(‘Name’,ftString,0,false);
0 X+ x. t5 _1 ?& D' I; P- B! ^
' G) Q; f2 _/ U9 P1 F1 X  Nend;
8 ?7 s: ]& A5 N7 C! ywith indexdefs do
0 j! T  [- y8 m6 i5 dbegin' S9 A% L1 v- d" O+ b* i3 R3 E! }5 g
clear;/ N  H8 g, s1 }2 q4 m
add(‘primary’,'no’,[ixPrimary,ixUnique]);
& F- p& ?0 U8 `) V. Y5 \
: u# O3 x3 N1 v  t# _  iend;8 h5 R- m( N+ I3 S0 I7 |/ ]# g
CreateTable;
3 x6 w4 C# @% \* g% {" Jend;
' n% V) v- o4 tend;: Y- u! ^# C- E# p- _4 J

: {2 x" \( c( q: i: @  d
& a2 C  S, f( Istring、TStrings、pchar的相互转换(这里是我的个人经验)% n& r  s/ m% L2 M, M9 T* Z* W: O. c
假设有如下定义:% T7 f& J- V  {) l9 J
var
( D/ F3 U* s! R( F% \p:pchar;; _/ _: `: q1 C2 V" b8 U
s:string;% r, b& c! ?  T+ o+ U
ss:tstrings;
, W: W0 D) Q$ A" z, k7 wbegin; C+ _. p' D. u6 v
ss:=tstringlist.create; // 开始时一定不要忘记创建ss
* D3 z3 `0 j5 u/ Yss.text:=s; // string –> tstrings7 Q* D3 O% i, v1 g2 O* q
s:=ss.text; // tstrings –> string# f' \" p. |6 m& b6 r
p:=pchar(s); // string –> pchar3 M) L2 G- |* m6 p% p' v
s:=p; // pchar –> string3 |6 b8 U* L/ l7 ]& ]/ I
showmessage(s); // 合法语句9 X5 a8 S5 t' Z0 b7 a4 [+ F
showmessage(p); // 合法语句
6 C3 ^7 J5 T2 ?2 v- v: M7 v* f… …  h" k# T7 N  I1 o2 Z# ]5 i7 R
ss.free; // 最后还要记着释放ss占用的资源) w$ n( Y  P+ a
end;: ~  n2 j6 F; B
- l1 n0 `* G' D( n
7 A% ?, J. `& M9 e! L$ z2 k

. Z  E4 n; A9 |8 O- b在设计Menu时,常用的ShortCut可从下拉菜单中选取。但我发现可选的ShortCut有些不在列表中,如ESC,Ctrl-Shift-A等。我试着在ShortCut项的右边输入:ESC,竟然成功了。再试Ctrl-Shift-A,这回Delphi自动把它变为Shift-Ctrl-A




歡迎光臨 幸運草之戀 (http://discuz.segaa.net/) Powered by Discuz! 6.0.0