Delphi心得介绍
Delphi心得介绍
98-8-23 22:00 raise的用法 看Demo时学的: raise Exception.Create('Project ID is required'); 在工程文件中Application.Run语句之前加入下面语句,可不让主Form在运行时显示: Application.ShowMainForm := False; 在CSDemos.dpr中,有许多有用的c/s编程技巧…… 98-8-23 21:40 在Delphi代码中定义数据库 近来由于应用上的需要,要在运行中动态生成数据库,结构不定。我想一定要用 BDE32API中的知识才能实现。无意中在5月7日的《中国计算机报》上发现一篇文 章《在Delphi代码中定义数据库》,帮了我的大忙。部分代码如下: procedure tform1.create_tbl; var tbl:ttable; begin tbl:=ttable.create(self); // 如没有声明中的"tform1.",Delphi不认这个self with tbl do begin datebasename:=;dbdemos'; tablename:='my_tbl'; with fielddefs do begin clear; add('No',ftInteger,0,false); add('Name',ftString,0,false); ... end; with indexdefs do begin clear; add('primary','no',[ixPrimary,ixUnique]); ... end; CreateTable; end; end; 98-8-20 22:24 异种数据库之间的互相转换 记得过去曾经见到过一篇文章,介绍如何用一极简单的方法将异种数据库之间 的表(Table)相互转化,但没有记住作者是用了什么方法。现在,我需要有这 样一种工具,怎么也找不到,只能用笨办法,一条记录一条记录地Insert。好 在刚刚在看Help文件时找到了要找的:那就是用TBatchMove!真是的,天天都 在我眼皮底下晃,为什么到现在才发现…… 有个Demo工程在Delphi 3/HELP/EXAMPLES/BATCHMV之下,功能很全的。 98-8-20 22:22 在程序运行一耗时操作时改变鼠标形状 begin screen.cursor:=crHourglass; try ... // do some long-time work finally screen.cursor:=crDefault; end; end; 1998-08-19 11:03 在TQuery中查询时关键字冲突 我用了这样一个查询: select no,name,py,belong from dwbm 结果Delphi提示"Invalid use of keyword...",换成 select "no",name,py,belong from dwbm 查询结果的第一列又恒为 "no",经反复试验,最后终于成功了: select "a"."no",name,py,belong from dwbm a 1998-08-18 14:06 我的第一篇Delphi文章《Delphi使用技巧四则》 请看 http://www.ciw.com.cn/ciw/751/d0902.htm 这是中国计算机报的站点。 98-8-15 20:56 InsertRecord和AppendRecord的一条注意事项 在用InsertRecord插入一条记录时,发现有两个字段颠倒了。又核对了一 遍数据库(table)中的字段顺序,没有发现不一致的地方。想起用了Field Editor,会不会是……打开Field Editor,果然,为了显示的需要,我把 其中两个字段对调了位置。原来,InsertRecord中的字段顺序应该与Field Editor中的顺序一致才行。这一点,好象书上和联机帮助上都没有提到过。 这一点,对AppendRecord也同样。 98-8-12 21:44 一夜之间 昨天朋友找我帮忙,编制一个数据库应用软件,必须在今天早上之前完成。 我答应了,因为我知道Delphi的能力,也了解到这个应用并不是多么复 杂。结果,从晚8点到晚0点,程序顺利作成,而且没有忘记加了个About 版权信息对话框和一个Splash启动封面。连我也从来没有想到过一夜之 间做好一个界面漂亮功能齐全的软件! 记得有本书上介绍一位程序员用Delphi用了一天一夜的时间,为一家大 公司开发出一套大型软件的演示版,击败了他的一个在此之前总是比他 提前完成的竞争对手。在这24小时里,他不光拚命地工作,而且还要应 付失火、朋友拜访、嘴唇被碰破、失恋等意外事件。但最终,他还是胜 利了。所有这些,都只是因为:他用上了Delphi! 哈哈!Delphi真是给咱们程序员脸上贴金! 98-8-12 9:39 TSplitter的用法 见到过一些文档中提到过在运行中改变两个Panel的边界的方法。其实,Delphi 3.0 提供了一个组件TSplitter,可以非常轻松地实现上述功能。步骤如下: 1、加入Panel1,Align设为alLeft。(也可根据情况设为right,bottom或top) 2、在Form1的空白处加入一个Splitter,可以看到它自动处于紧贴Panel1的位置。 如果不是紧贴,可以把它的Align设成和Panel1一样即好。 3、加入Panel2,Align设为alClient。(必须有一个Panel为alClient) 运行,把鼠标放在两个Panel之间,当光标改变成双向箭头形状时拖动它。 试一下,是不是很爽? 98-8-7 18:07 pchar的一个特别之处 var p:pchar; begin getmem(p,10); p:=''; if p='' then ... 这是错误的! if 语句应该这样写 if p+'a'='a' then ... 才行。您要是不信,试一下就知道了。 98-8-7 10:18 使用OnFilterRecord时应注意的一个问题 我在制作一个数据库应用程序时遇到下面的现象: 运行时好好的,退出程序时,出现 'Invalid variant type conversion'. 程序中的实现过程如下: procedure TMainForm.RadioButton1Click(Sender: TObject); begin Datamodule2.payedquery.OnFilterRecord := BfsjFilter; end; ... procedure TMainForm.BfsjFilter(DataSet: TDataSet; var Accept: Boolean); begin accept:=(copy(dataset['Bfsj'],1,6)>=monthfrom.text); end; 真奇怪。用单步执行,原来在Close之后,程序又执行了TMainForm.BfsjFilter中的 语句。有办法了: 在Mainform的OnClose里加入一行 Datamodule2.payedquery.OnFilterRecord := nil; 错误不再。 98-8-4 22:50 关于文件夹的几个函数 uses filectrl; procedure ForceDirectorys(dir:string) ------------ 一次建立指定的多级文件夹 function DirectoryExists(Name: string): Boolean; - 指定文件夹是否存在 function SelectDirectory(var Directory: string; Options: TSelectDirOpts; HelpCtx: Longint):Boolean; - 打开一个选择文件夹的对话框(英文的) 快捷方式(ShortCut) uses shlobj,comobj; var sl:ishelllink; begin sl:=CreateComObject(CLSID_ShellLink) as IShellLink; end; 98-8-3 18:05 TQuery的另一件怪事 我把一个Query元件设置好,Active属性置为True,运行它,怪事出现了:Query 的Active自动变为False。奇怪,我单步运行它,发现在第一步时,Active就 会变。这和Form中的语句无关。注意到我在编辑SQL语句串时,打开了一个 Code Editor窗口,我把它关闭,再次运行,正常了。我做了个实验:仍旧打 开Code Editor窗口,运行,没问题;在Code Editor中做一点改动,再运行, 上述现象再次出现;点击Save All按钮,运行,仍然出现;关闭Code Editor 窗口,运行,正常。 ---- Bug? 98-8-1 10:01 在使用TQuery时,我遇到了一个怪事。经过是这样的: 我先建立一个Query1元件,输入一条SQL语句,并作了些修改,它工作正常。 后来,SQL语句有了很大变化,我输入新的SQL语句,双击Query1的Active属性, 出现:Query1: Field 'SUM(RS)' not found 我知道,这条SQL语句在Oracle服务器上执行得好好的,里面没有任何错误。 没找到原因,我只好建立另一个元件Query2,把新的SQL贴入,这个工作正常。 也许是某些基本属性改变了。但仔细对照Query1和Query2的各项属性值,发现 它们一模一样。再试,还是Query1不行,Query2行。我忽然想到一个办法:单 击Query1,按Ctrl-C键,把它放在WIN95剪贴板里,打开Notepad,再Ctrl-V; 再用同样方法,把Query2放在另一个Notepad窗口里,两相对照,真相大白: --------------------------------------------------- object Query1: TQuery DatabaseName = 'myorac' SQL.Strings = ( 'select a.dwbm,d.dwmc,a.ybsj,a.srs,a.sylj from' ... 以下省略 ... ) Left = 104 Top = 16 object Query1DWBM: TStringField FieldName = 'DWBM' Size = 10 end object Query1YBSJ: TStringField FieldName = 'YBSJ' Size = 6 end object Query1SUMRS: TFloatField FieldName = 'SUM(RS)' end object Query1SUMYLJ: TFloatField FieldName = 'SUM(YLJ)' end end --------------------------------------------------- object Query2: TQuery DatabaseName = 'myorac' SQL.Strings = ( 'select a.dwbm,d.dwmc,a.ybsj,a.srs,a.sylj from' ... 以下省略 ... ) Left = 200 Top = 16 end --------------------------------------------------- 原来Query1中多了这么多东西!我想起自己曾用字段编辑器(Field Editor) 为增加新SQL语句前置入一些字段。双击Query1打开字段编辑器,果然如此! 上面真的有一行是SUM(RS)。看来,这是一个经验问题,错误很隐蔽。 ......差点错怪Delphi。 98-7-27 10:21 看了《中国计算机报》7月20日C12版的《Delphi编程经典》,禁不住想买本 《Delphi2 程序设计大全》。正好星期六去省城济南,我当然不会错过这个 机会。在青龙桥的计算机书店里,我发现了那里的这部书的最后一本!好贵: ¥133!但我算了一下,共有1207页,平均每页1毛1,比别的同类型的书相对 来说还要便宜一点呢。^o^ 这本书真是名不虚传,它和我看过的另外四本Delphi书有很大的不同。后者 主要的目的不外乎介绍Delphi的入门,控件的用法,OLE,DLL,数据库,高 级控件编写,等等,而前者……,嘿嘿,还是让我引用几段原文吧。 ------------------------------------------------------------------ 编制程序是一个有趣的职业,但同时也是一个容易令人头痛的职业。下 面所列的是作者发现自己在干得最为糟糕的那些日子里问自己的问题: - 为什么这东西不工作? - 为什么我不能这样做?难道这是不允许的? - 为什么我一定要这样做呢? - 难道没有更好的方法吗? - 这可能吗?这难道能实现? - 为什么这方法有些情况能用,有些情况又没用? - 这样做合法吗?还是我越做越离谱了? 这些是作者在自己不明白一种方法不奏效时问自己的问题。回答它们的 最好办法是透过表面去看一看自己所用的东西是怎样被组合在一起的!只有 这样才能完全明白工具和自己的潜力。 某些程序员天生就非常聪明。他们的大脑就像一台调得很准的钟。大多 数人永远都不能做得和这些极具天赋的人一样好。然而,还有另一条成为优 秀程序员的路子,这就是搞明白系统怎样工作以及为什么这样工作。 如果知道怎样做一件编程工作,就能把一项工作做好。而如果懂得了为 什么Windows和Delphi会这样工作,以及它们所遵循的原则,就能做好任何 牵扯到Windows和Delphi的工作,前者教会你做一件事情,后者教会你要干 好每件事所需知道的东西。 这本书属于后者。书中许多内容是关于隐藏在Windows和Delphi内部的 机制的。作者一向是这样著书的,因为我相信最为实际的成为一个优秀程序 员的方法就是弄清操作系统自身是怎样工作的,以及Delphi是如何组合在一 起的。 ……解决问题的关键不在于记住一系列的命令,而在于明白面向对象的 理论是怎么回事儿。一旦懂得了VMT是怎么回事以及虚拟内存是如何被调用 的,面向对象编程就再也不是一件神秘的玩意儿了。于是作者就可以从系统 要想正常工作必须怎样实现这样的简洁的思路来思考问题了。 搞明白对象、组件、内存、GDI或是任何其它东西的理论并不意味着可 以神奇地将问题一下子全部解决了,但这是成为一个优秀的、全面的程序员 最有效的方法。 当在计算机前工作的时间越来越多时,你必将成为更好的程序员。经验 能帮助人们减短往往困扰着初学者的学习曲线。只要读者在不断地学习关于 计算机的东西,学习新技巧的过程也就越来越快。 通过经验能学到的不只是一系列的技巧,还有对日夜伴你工作的机器和 工具的内部机理的理解。这种理论上知识是世界是最实际的知识,因为它能 帮助用最短的时间完成每项工作。 真正的天才程序员的头脑中都有一幅系统如何工作的景象,他们只要一 坐下来编制程序,这幅景象就会得以利用。这本书就是这样一幅关于系统是 如何工作的景象。 ------------------------------------------------------------------ 看了这些话,我的心情可以说激动,感动,震动兼而有之。这已经不仅仅是 单纯地介绍编程了! 98-7-23 3:56 ansistrlastchar('你好')结果是“好”。如果有半个汉字出现, 返回这半个汉字。二者字符串长度分别为2和1。 98-7-23 3:43 无意中学得两个字符串比较函数: CompareStr - 区分大小写 CompareText - 不区分大小写 98-7-22 23:57 Win32系统调用: ShGetFileInfo 在学习Demos/Internet/Ftp中的例程时,我发现了这个系统调用,原型是: WINSHELLAPI DWORD WINAPI SHGetFileInfo( LPCSTR pszPath, DWORD dwFileAttributes, SHFILEINFO FAR *psfi, UINT cbFileInfo, UINT uFlags ); 它的作用是:取回文件系统中的一个对象的信息,对象可以是文件、文件夹、 目录或驱动器的根目录。经过三个多小时的调试,我终于完全弄明白怎样取 得并显示一个文件的图标了:包括大图标、小图标,象资源管理器上的那样。 操作过程大体如下: var ShFileInfo: TSHFILEINFO; FileList:TListView; begin ... Result := FileList.Items.Add; with Result do begin Caption:=filename; ShGetFileInfo(pchar(vartostr(filename)), 0, SHFileInfo, SizeOf(SHFileInfo), SHGFI_SMALLICON or SHGFI_SYSICONINDEX or SHGFI_TYPENAME)=0 then showmessage('error in shgetfileinfo'); ImageIndex := SHFileInfo.iIcon; end; ... end; 这是最关键的几个地方,中间省略了许多细节。 另:我在6月17日的笔记里提到ExtractAssociatedIcon()和ExtractIcon()函数, 也可以提取文件的图标,但是速度比这个方法要慢上许多,而且我不会用它们提 取小图标。