99-6-26 关于SQL的一点疑问 今天在写一个数据库应用程序时,用到了一个SQL查询 select name // 从基本信息表中取姓名并要满足下面条件 from an01 where serial in ( // 姓名对应的序号在……之中 select a00 // 从培训班数据表中取出所有序号要求是 from an43 where a01=:a01 // 培训班号等于一结定值 ) 结果无论我怎样改变参数a01的值,这一查询返回的结果总是第一次查询的结果。我只好换另一种方法 select name from an01 a,an43 b where a.serial=b.a00 and b.a01=:a01 结果竟然通过了。我不知道为什么前者不成功后者成功了。你知道吗?
99-6-6 关于RXLib260 朋友建议我用一下RXLib2.6里的RXRichedit控件。我下载了一个,一用之下, 还真的很好。RXRichEdit能支持UniCode、对象(如图片)、URL的自动显示及 单击激活功能、支持缺省为100次的UNDO、内置了查找/替换功能等等。这下用良 友的朋友们有福了! :)
看Demo时,无意中看到了个WinAbout函数,是RX在Rxshell.pas中自定义的。 在程序里用了一下: WinAbout('Win','About'); 啊哈!
99-6-3 网友提问的几个问题 l> 你好: l> 我刚学delphi4.0不久,遇到了不少问题,现想请你指教一下: l> 1、如何设置按回车键相当于单click?(例如在dbgrid表格中) 答:在窗体form1中放入table1,datasource1,dbgrid1,设好联连关系,使dbgrid1 中能正确显示出table1的数据。然后: procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char); begin with DBGrid1 do if Key=#13 then DBGrid1CellClick(Columns[SelectedIndex]); end; procedure TForm1.DBGrid1CellClick(Column: TColumn); begin with DBGrid1 do showmessage(format('row=%d',[SelectedIndex])); end; l> 2、如何用语句调用其他控件的过程和方法? 答:注意上面的例子里的 if Key=#13 then DBGrid1CellClick(Columns[SelectedIndex]); 这就是调用了其它控件的method。 l> 3、show窗体的时候如何激活窗体上的菜单? 答:在form1上增加一个mainmenu1,设好菜单项,再设form1的menu属性为mainmenu1即可。 l> 4、初次装入列表框的时候,如何设置选定默认选项? 答:ListBox1.itemindex:=n; (n即为默认选项的index) l> 5、用query控件生成的临时数据表,能否当源表来重用,如用select来继续查询 等,或保存到一个新建数据表中,以备用? 答:可以保存起来。但需要在运行中动态生成数据库表。具体请见TTable.CreateTable的联机帮助。 l> 6、用delphi删除的数据表记录能否恢复删除? 不能。 l> 7、delphi怎样才能象foxpro的scatter memvar l> 和gather l> memvar命令组那样方便地更新数据表的整条记录? 请看TDataSet.Fields的帮助及Example l> 8、先放入一个button控件,再放入一个panel控件,如何设置使到button归属于panel? 单击Button,按Ctrl-X;再单击panel,按ctrl-C。如果要批量转移,请看我的开发心得。
99-6-1 string、TStrings、pchar的相互转换(这里是我的个人经验) 假设有如下定义: var p:pchar; s:string; ss:tstrings; begin ss:=tstringlist.create; // 开始时一定不要忘记创建ss ss.text:=s; // string --> tstrings s:=ss.text; // tstrings --> string p:=pchar(s); // string --> pchar s:=p; // pchar --> string showmessage(s); // 合法语句 showmessage(p); // 合法语句 ... ... ss.free; // 最后还要记着释放ss占用的资源 end;
99-5-31 惨痛教训一例 今天在我单位财务科,想在我编写的记帐程序中添加一点功能,先在acc.db表上建立索引。 (其实我对数据库方面的东西不算很熟,因为我更喜欢把时间花在开发些实用软件工具方面) 用Database Desktop打开acc.db,选“Restructure...”,给其中的头两个字段加上 主索引,即在右边加上“*”号。然后Save,发现显示了一个表格,大概是产生冲突的记录 列表。我没在意,就关掉了窗口。正式运行程序时,发现原来记的帐少了许多(存放在acc.db 中),几千条记录只剩下300条了……想啊想,终于想起来了:我建立的索引是唯一索引, Database Desktop自动把重复的记录剔了出来,当时显示的那个表就是!我应该马上保存 才对!这一下,就要辛苦操作人员补记上次备份以来的帐了。真不好意思。
99-5-30 使Panel上的所有组件无效/有效 在开发过程中,免不了时常要使整个Panel上的组件同时无效,然后在适当时机同时有效。 这里有个好办法: MyPanel.enabled:=false; 此后,从属于MyPanel上的所有组件就都被禁止了。
99-5-20 制作出类似资源管理器的工具条 要达到这个目的,需要先掌握TCoolBar的用法。这个组件用起来很特别,需要一点技巧, 要多试几次才能得心应手。
先在CoolBar上放一个ToolBar,在它上面放置模仿菜单项的按钮,具体要去看一下 Demos/Docking/Main.pas的示例。有一点值得一提:记住把ToolButton的Grouped 设为True,否则,嘿嘿!你的“菜单”会很难用!
以上建立的“菜单”不同于普通应用程序中常见的那种一直位于屏幕最顶上的主菜单, 而是象资源管理器里一样,能够被鼠标拉着动。
然后还要建立快捷按钮。方法同样还是在CoolBar上放置ToolBar,具体步骤我就不再 仔细描写了。
99-5-18 几个必备function function Confirm(prompt:string):boolean; begin result:=MessageBox(application.handle, pchar(prompt), '确认',mb_ICONQuestion+mb_YesNo)=mrYes; end;
procedure ShowMsg(Msg:string); begin MessageBox(application.handle, pchar(Msg), pchar(Application.title), mb_ICONInformation); end;
99-5-18 TRichEdit快速插入字符串 请注意看下面这段程序: procedure TMainForm.InsertSomethingToMemo(s:string); var c:integer; begin with ContentMemo do begin c:=SelStart; SelText:=s; // 关键 SelStart:=c+length(s); SelLength:=0; Modified:=true; end; end; 其中的SelText:=s就很容易地做到了。如果你没有看到我的程序的话,能不能很快想 到这个办法呢?
99-5-10 RXLib的AppEvents组件 在Delphi中,有一个重要的类TApplication,它被预定义成一个系统级的全局变量: Application。Application有许多属性、方法和事件,合理地管理和定制它,就能 极其灵活地控制应用程序的各个方面。RXLib提供了这个TAppEvents控件,使我们可 以在设计期间就能象对其它VCL组件一样直观地对它的各项属性赋值,还可以直接编写 各个事件处理过程,哇,太方便了。(注:RXLIB2.5是一个优秀的免费Delphi控件集, 带源码,在Delphi小站上有提供。)
有空我要写一个RXLib主要控件简介。
99-5-1 良友秘笈:HZ->GB码的转换示例! function HZtoGB(S: string): string; // 我写的自定义函数,从Str的第Start个字符处 // ..开始找SubStr,找到返回位置(相对于Str) // ..找不到返回0 function PosX(SubStr,Str:string;Start:integer):integer; begin result:=Start+pos(Substr,copy(s,Start,MaxInt))-1; if result<Start then result:=0; end; function InternalHZtoGB(s:string):string; var i,len:integer; begin len:=length(s); SetLength(result,len); for i:=1 to len do result[i]:=char(ord(s[i]) or 128); if (len mod 2)=1 then result[len]:=char(ord(s[len]) and 127); end; var LIdx,RIdx:integer; begin result:=''; LIdx:=pos('~{',s); RIdx:=1; While LIdx>0 do begin result:=result+copy(s,RIdx,LIdx-RIdx); RIdx:=PosX('~}',s,LIdx); if RIdx=0 then begin result:=result+copy(s,LIdx,MaxInt); break; end; result:=result+InternalHZtoGB(copy(s,LIdx+2,RIdx-LIdx-2)); inc(RIdx,2); LIdx:=PosX('~{',s,RIdx); end; result:=result+copy(s,RIdx,MaxInt); end;
99-3-23 1:00:00
在设计Menu时,常用的ShortCut可从下拉菜单中选取。但我发现可选的ShortCut有些不在列表中,如ESC,Ctrl-Shift-A等。我试着在ShortCut项的右边输入:ESC,竟然成功了。再试Ctrl-Shift-A,这回Delphi自动把它变为Shift-Ctrl-A,呵呵,原来如此。
99-3-20
不知你有没有注意到,Delphi4所带的Quick Report有些不大好用。比如:在ColumnHeaderBand1上放几个QRLabel,结果在预显示和打印时,第一页上竟然没有这几个QRLabel!从第二页起才开始出现。在Delphi3的QRLabel里就没有这个Bug。没办法,只好采取一个折衷的措施:把所有ColumnHeaderBand1上的内容移到PageHeaderBand1上去。
什么!不会移?看好了:
·按住ctrl键,拖动鼠标,尽可能多地选中ColumnHeaderBand1上的控件
·按下Ctrl-X(剪切),——没有了;
·点一下PageHeaderBand1,按下Ctrl-V,所有选中的控件都上来了。
·调整PageHeaderBand1的大小及刚才粘贴上的控件的位置。
重复刚才的操作,直到完成。
99-3-4 20:55:28
我对fillchar的初步认识
var
p:pchar;
begin
getmem(p,100);
fillchar(p^,99,'c'); // fillchar(p,99,'c')就是绝对错误的!!!
p[99]:=#0;
...
99-3-4 20:55:33
对fillchar的再认识(下面这个试验通过了。)
procedure TMainform.Button1Click(Sender: TObject);
var
p:pchar;
s:string;
begin
getmem(p,100);
fillchar(p^,99,'c');
p[99]:=#0;
s:=p;
showmessage(string(p)+' -- '+s); // 'cccc... -- cccc...'
freemem(p);
showmessage(string(p)+' -- '+s); // '@$#%... -- cccc...'
end;
99-3-4 20:58:37
(Delphi 4)Anchors属性设为 akRight & akBottom时,元件会伴随着容器的右下角做相应移动。
更深入一步:当改变Align属性时,Anchors的属性值也随之变化。注意观察就会看出其中的规律。无论如何,Align控制更简易,而用Anchors控制更高级,更灵活。熟练使用Anchors控制元件在窗口上的位置,可以省去很多编程工作。
99-3-5
Delphi 4中TTreeView的bug:假设我们要将某个结点treenode移动到另一结点AnItem上并做为AnItem的child,按照文档说明,只需这样做
TreeNode.moveto(AnItem,nrAddChild);
但实际上,在Delphi 4中,假如anode原来没有child的话,这条语句将不做任何事情。折衷的办法是
TempNode:=TopicTV.items.AddChild(AnItem,'');
TreeNode.MoveTo(TempNode, naInsert);
TempNode.free;
在Tipexplr程序的源码中,关于实现同样操作,它指出,Delphi的TTreeView有bug,并提供了自己的解决方法(见下),但这只能在Delphi 3中通过,在Delphi 4中,只能用我的上面的方法。
AttachMode := naAddChild; { Add tip as a child of category }
{ Note: Adding the temporary node is a work around to a bug }
{ that exists in the TreeView component when moving a }
{ node to a another node that doesn't have any children }
TempNode := TvwTips.Items.AddChild( TvwTips.DropTarget,'Temp' );
try
{ Move the node in the tree view }
TvwTips.Selected.MoveTo( TvwTips.DropTarget, AttachMode );
{ Now need to update the category of tip in the database }
TblTips.DisableControls;
try
TblTips.Edit;
TblTips[ 'Category' ] := TvwTips.DropTarget.Text;
TblTips.Post;
finally
TblTips.EnableControls;
end;
finally
TempNode.Free; { Don't forget to release the temp node }
end;