刚开始用DELPHI的时候, 是不是大多数人都在ONXXXXX事件中写代码? (我也是)一直想说说这个问题. 感觉是从一开始就进入了"误区". 这种习惯感觉很不好!有些非可视的组件,尤其像TDataSet的子孙们根本就不应该在属性编辑器中有OnXXXX事件. public出来就OK了.或者TDataSet的子孙根本不应该能直接拖到TForm 或 TDataModule 上.还有像TButton.Click. 应该能像C#这样 Click += XXXX.Click会更好. 以上只是本人的一点看法. 希望大家说说一些认为值得"推敲"的东西.
解决方案 »
- 如何让TWebBrowser释放焦点﹖
- 从oracle导出数据到txt后txt的格式问题
- 求助:EasyRecovery 都不能恢复
- 关于录音的问题(急,高分求!)?
- 对话框出现英文件很不舒服,请问哪有D7的汉化资源包?
- 一个弱弱的问题,TADOQuery的FilterOptions属性为什么不可用?
- 手工发布delphi7+ado+access2k需要一些什么文件?
- 一个网络的问题请帮帮我
- 怎么实现UDP数据包的拆包组包发送与接收?在线等待,期待高手(Up、gz均有分)......
- 关于Treeview中的EndEdit?????????????????
- 关于dat类型数据库的问题
- dev express安装的问题
delphi 中当然可以;
取消
Button1.OnClick := nil;
指向
Button1.OnClick := MyClick;
对于Click += XXXX.Click 我是想说C#的代理
button1.Click += new System.EventHandler(this.button2_Click);
button1.Click += new System.EventHandler(this.button3_Click);to:
除此之外,我想说,什么事都有双面性,如果什么东西都“根”开始,说不定等你所开发的东西交工之日,便是你被炒之时!
呵. "根"打不好. 盖的永远是危楼.
button1.Click += new System.EventHandler(this.button3_Click);
不会C#,向楼主请教一下这两句的具体作用
相当于 button2 和 button3 对 button1 说: 你结婚时要告诉我.button1被"点"的时候, 就会发出消息to button1, button2. 我要结婚了, 你们看着办吧.
那么换用Delphi的话,button1被"点"的事件就是:button2.click;
button3.click;即单击button1时等于分别单击了button2和button3
button3.click;
self do something //button1自己还要做的事.感觉是button1让button2, buttn3也去做什么. 不是一种"通知". (另:我打的比方有不太恰当之处)to 12楼
我晕! 什么意思嘛. 呵.
to 13楼
莫发乱想. :)
AMsg = 99999;type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
OldWndProc: TWndMethod;
procedure BtnWndProc(var Message: TMessage);
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.BtnWndProc(var Message: TMessage);
begin
if Message.Msg = 99999 then
Self.Button1.Caption := FormatDateTime('hh:nn:ss', Now);
Self.OldWndProc(Message);
end;procedure TForm1.FormCreate(Sender: TObject);
begin
OldWndProc := Self.Button1.WindowProc;
Self.Button1.WindowProc := Self.BtnWndProc;
end;procedure TForm1.Button2Click(Sender: TObject);
begin
PostMessage(Button1.Handle, 99999, 0, 0);
end;
C#中用了委托来实现的DELPHI的这种属性,也就是上面的过程函数,等C#里的委托理解为指向函数的指针应该也行吧。 从语法上是完全是C# 与 pascal 的区别不过Click += XXXX.Click 这样的实现的确比 DELPHI在publised 实现的要强一些。delphi 自动实现了button1.Click 用 Button1onClick 来实现了事件。
要实现 C# 中的委托,可能就要改变下 procedure Button1Click(Sender:Tobject);
begin
if Sender is ... 这样来实现委托的效果。 的确复杂了点。
end;
不要总按书上那样使用 delphi, 例如:
TDataSet的子孙总是放到TForm 或 TDataModule 上,
OnClick总是在设计时指定,
其实需要时, 还可以用代码来实现这些功能, 而且更加灵活.初学者要领悟楼主的意思, 不要误解成 delphi 不好.虽然有段时间没用delphi做过实际开发了, (转入嵌入式开发了)
但从经验来看, 除了驱动程序, 还没有 delphi 做不到的.
这点毫无疑问,定义委托更容易解除消息事件以及订阅事件之间的藕合关系,使之更为灵活(可轻松实现合并委托之类的)。从事件设计模式上来讲,的确很不错!
Delphi这方面实现得的确不太灵活!
2.有些非可视的组件,尤其像TDataSet的子孙们根本就不应该在属性编辑器中有OnXXXX事件. public出来就OK了.这点相当不明白LZ的意思!
3.TDataSet的子孙根本不应该能直接拖到TForm 或 TDataModule 上. 从快速开发角度来讲,可能会降低工作效率!
我曾考虑过在d2009中diy一个山寨版的泛型模板,但是rtti中关于method类型参数的信息量太少,参数传递的方式又非常复杂,如何保存和恢复stack也就变得极复杂。考虑过两三种我能想到的实现方式,要么太浪费空间要么不现实,反正是没找到一个比较理想的实现方式
俺觉得C#和Delphi的事件其实本质上都是一样的,都是类的成员函数指针而已,
只不过C#的事件是个指针链表,而Delphi只是一个指针而已。。想到这些,感觉
C#的事件只是在使用上比Delphi稍微的简单一些,但是Delphi实现类C#的事件也应该可以的,
譬如说:也可以先定义函数指针链表,对其赋值,尔后在 Delphi的Click事件中
根据事先定义好的链表开始依次执行不就OK了?!如有疑问可以参考VC的MFC源码,
那里有一段是程序启动时如何初始化 全局变量的操作,不过具体是MFC的那个源文件
我倒是既不清楚了
以上,个人愚见,有什么不妥之处请各位大牛见谅哈。
C#为了一点点灵活性损失效率, 何况是几乎不用的灵活性, 实在得不偿失!个人认为, 这一点上, C#不如delphi, 而不是向lz说的那样
初学者、求简单快捷,可以直接使用其高层的封装:快速实现一些普通的功能;
想实现一些特殊的功能(被初学者认为只有vc才能做到的),也可以像vc一样直接使用api进行编程,只是开发效率也与vc一样了。楼主这个问题,其实是只看到delphi的高层的封装,就以为delphi没有低级的实现手段了当然,采用控件的模式,个人现在看来,除了界面控件有必要之外,非可见的控件,其实还是采用直接的类-对象这样更简明一些
当然,dataset也做成控件,估计是为了提供一体化的高层封装,以便能单纯靠拖放控件的方式一口气实现一个最基本的应用(demo)另外,delphi现在看来也是有一些缺憾,但是这与delphi出的早有关了
从win32开发而言,应该是基本完美的了
相当于delphi提供了一个现成的应用框架,在很多地方提供 OnBeforeXXX OnAfterXXX OnXXX
——当然AAA被XXX的时候,执行:
if assigned(AAA.OnBeforeXXX) then
AAA.OnBeforeXXX(参数);
if assigned(AAA.OnXXX) then
AAA.OnXXX(参数);
if assigned(AAA.OnAfterXXX) then
AAA.OnAfterXXX(参数);
只需要开发者根据自己的需求特点对事件的切入点再做进一步的具体实现,相当于填空
如果某个处理,现成的框架已经足够满足了,不提供(不填)也完全能跑了
Delphi.about.com当中也有个不错的解决方案:http://delphi.about.com/od/usedbvcl/a/multicastdelphi.htm
方便是方便了,但让人忽略了很多设计方面的东西.(先说下我的一个习惯. 如果能用一行代码解决问题,我绝不写两行代码)
所以提C#中的 Click += XXXX.Click 代码, 是因为在delphi中,我要多写些代码(不管用观察者模式(大才小用)
还是其它方式,都要引用不必要的类或方法,使一个简单的问题反而搞的复杂了)
{-- 尤其像TDataSet的子孙们根本就不应该在属性编辑器中有OnXXXX事件. public出来就OK了. --}
我觉得把像一些 if .. then 的代码写在 OnBeforeDelete OnAfterPost...等事件里是有问题的.不知道大家怎么看.{-- 或者TDataSet的子孙根本不应该能直接拖到TForm 或 TDataModule 上. --}
TDataModule一建立, 一大堆DataSet什么的就都生成了.浪费内存不说. 如果上面的TDataSet多了, 看着眼晕.
找起来眼花. 另外很自然的, TDataModule单元中一大堆OnXXXX. (我刚用DELPH的时候就是这样.所以我这么说.)
如果TDataSet的子孙们不能直接拖上去. 我想每个人都应该有自己的"套路"了吧. 并且或许会想的更多一些.
楼主可以考虑去找Borland或CodeGear索要赔偿,当然你需要准备一份正版Delphi和神经受损的证明。
TDataModule一建立, 一大堆DataSet什么的就都生成了.浪费内存不说. 如果上面的TDataSet多了, 看着眼晕.
找起来眼花. 另外很自然的, TDataModule单元中一大堆OnXXXX. (我刚用DELPH的时候就是这样.所以我这么说.)
如果TDataSet的子孙们不能直接拖上去. 我想每个人都应该有自己的"套路"了吧. 并且或许会想的更多一些. --------------------RAD的开发模式问题,其实就是工具摆在这了,看大家怎么用了。从来不喜欢在DATASET上写事件的飘过...
这里貌似有两个问题,第一个是ONXXXX,第二个是多路通知事件。对于第一个问题俺完全不能理解……所谓时间也就是一个回调函数的问题。一个类的回调函数可以允许开发者在不继承这个类的情况下改变这个类的行为,其实也就是一种变相的派生类的方法(Windows也有所谓的子类化,搞的是一样的事情)。之所以弄成published而不是public,也是为了大家写代码方便些,更重要的是让用户在不打开类库源代码的情况下清楚的知道他能做什么。个人觉得这个绝对是Delphi的一大创举和亮点(此处用过去时T_T)。第二个问题,Delphi不支持多路事件是一个遗憾,估计是实现的成本有点高,而且有时候反而降低了系统的编译和运行效率。
且,委托代理估计大多都是使用Hash表,所以保证了效率和空间就不保证调用顺序了。
估计CSharp也差不多。当多个Click事件都要操作同一数据时就不太妙了,你要自己保证数据的正确性,那时候恐怕更麻烦。
如果你非要用代理,干脆用TList建立一个事件列表,然后在一个事件(a)里依次调用它们,我个人觉得这和委托没什么两样,然后,把a赋给OnClick。这不就一样了!当然,如果你对事件列表排序了的话,那调用顺序也是无法保证的。
支持liangpei2008
Delphi中保留了很多“面向窗体”的特征,让人感觉不够完美。
不能显示的控件就不应该搁到窗体上。
创建一个子孙,覆盖掉你希望隐藏或覆盖的东西不就行了,他顶多提示你,你改变了访问权限,不会影响程序的编译,当然,如果你再在其它地方又希望以Published方式调用而导致出错,那就另当别论了。Published是为了便于你了解和使用,但因为他方便你就搬石头砸自己脚那就不优雅了吧?再说了,Delphi并没有要求你必须要把组件拖放到容器中才能使用吧?你完全可以在代码中自己声明自己创建然后自己使用啊!还有,一定要记得自己的,还要自己擦屁股,必须自己去释放用完的组件。就像C/C++和Java那样,你完全可以不使用拖放来编写程序啊!
完完全全没有人会阻止你这么去做的呀!
我就经常嫌放在窗体里的非可视组件太多,而觉得太乱,就在代码中自己声明,并创建,当然,要自己记得对单元引用的添加和声明(当然,拖放就不用担心单元引用的添加和变量声明了),然后使用和释放。但是有时过段时间我再回头来看这段代码却还是觉得组件放在明处(窗体上)更亲切和容易理解。“支持楼主。
支持liangpei2008
Delphi中保留了很多“面向窗体”的特征,让人感觉不够完美。
不能显示的控件就不应该搁到窗体上。 ”不是Delphi把你束缚在"面向窗体"中,是你自己把自己束缚在其中了。不能显示的组件或控件,你完全可以不在窗体上放置么,根本就没有人会阻止你去这么做。我们往往把自己的愚蠢归咎于工具的糟糕,其实,这才是我们最可悲的地方。
其他工具中有缺陷,也并不能说这不是Delphi的一个缺陷。
TForm1 = class(TForm)
Button1: TButton; //Button对象
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
FXXXObject: TXXXObject; //XXX对象
public
{ Public declarations }
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
//Form自己造个房间来, 让Button.onClick指向这个房间.
//Button和XXXX对象或其它对象通话.
//弄个List也好还是其它办法也好. 还要再写代码.
end;procedure TForm1.FormCreate(Sender: TObject);
begin
//C#中可以这样
Button1.Click += XXXX1.Click; //在这你自己通话吧. Form不管了.(也不用造房间了)
Button1.Click += XXXX2.Click
... end;Form作为一个中介者, 知道很多"对象". 本身复杂度就高. 还要自己造个房间.(没事给自己找事)事件本身是好的, 至少可以让对象间解耦,不需要知道是谁关心自己的事件.
TYourButton = class(TButton),然后建议自己的事件订阅和发布机制。
这个方法不是Button的, 而是Form, 本身是button的事. Form也不得不参加进来自己加入一个方法. 觉得是可以推敲的.如果没有足够的理由,一般不会创造MyButton或其它控件. 就个人来说,觉得VCL的设计的非常棒,弹性很大. 所以通常是建个ButtonHelper的类来处理.
之所以觉得不应在属性编辑器上有很多的ONxxx事件. 就是觉得 Form, DM或其它(好像也没什么了)会加入大量的方法. 并且生成的这些方法会被随便使用. 其实这个问题本身来说并不能怪到DELPH上,毕竟用工具的是人.
1.不依赖其它实例的多路发布,即链式的多次回调通知,这个相对比较简单,其实就是允许同一个事件允许有多个处理例程,对于这个,跟你在Button1Click当中再去调用一个Button2Click,Button3Click...没有任何区别。
2.依赖其它实例的多路发布,这个就会存在一个问题,对于C#并不存在野指针的问题,所以不需要担心,任何时候依存关系都被维持着,但是Delphi/C++则似乎并不是这么简单的。这个就类似在Button1Click当中去调用Button2.Click,Button3.Click...这跟前者是完全不一样的。但是实际上这两种都有人需要,就TButton.OnClick而言,这两种处理上是完全不同。如果你是设计者,你会如何考虑?
1.不依赖其它实例的多路发布,即链式的多次回调通知,这个相对比较简单,其实就是允许同一个事件允许有多个处理例程,对于这个,跟你在Button1Click当中再去调用一个Button2Click,Button3Click...没有任何区别。
2.依赖其它实例的多路发布,这个就会存在一个问题,对于C#并不存在野指针的问题,所以不需要担心,任何时候依存关系都被维持着,但是Delphi/C++则似乎并不是这么简单的。这个就类似在Button1Click当中去调用Button2.Click,Button3.Click...这跟前者是完全不一样的。
不是很明白, 僵哥能否再详细的说下这两种方式.(尤其是第二种.)
其实,就像你不会直接使用TForm一样,你都会生成一个TForm的子类,其实你也可以先子类化一个组件,然后加到你的Form中,但调用时会需要大量参数。就是用VC不也是把消息在类中以函数来实现的么?C#也是在类中以函数来实现吧。正因为它是你的Form的函数,所以你才能操作其中的各种数据和组件啊!想象一下,喔哦,那需要传递多少参数
一个没有接口的类...用都没法用,谁又会知道他的存在?
我有时也会一时钻牛角尖,可能你也处在此刻。
编码与界面完全分开,至于界面中的控件采用IBOutlet进行联系,方式则是与任意IBAction(方法)进行连接,对于楼主提出的方法代理,的确是个可以灵活运用的机制,关于数据代理部分却与楼主说得十分相似,没有任何控件,直接是代码上的连接,不过是否适合刚入门的人就不得而知了,毕竟都是从磕磕绊绊中走过来的。
我觉得僵哥的意思是,
第一种是不依赖于特定对象是否存在的方法调用。即,即使对象不存在也不影响程序正常运行的方式。比如,你创建了Button2的OnClick事件——Button2Click,但是,在Button1的Click事件调用它之前,Button2被释放了,但Button2Click依然存在,此时,你依然可以调用Button2Click例程。
第二种是必须依赖于特定对象的存在,及如果Button2的实例对象不存在那就根本不存在Button2.Click属性。则此时调用它就会出错。
1、“有些非可视的组件,尤其像TDataSet的子孙们根本就不应该在属性编辑器中有OnXXXX事件. public出来就OK了.
或者TDataSet的子孙根本不应该能直接拖到TForm 或 TDataModule 上”
这是IDE中所谓可视化设计的思想。就可视化设计IDE来说这并不存在多大问题。RAD中嘛,拖一个TComponent子类放界面上就可以直接用,比你手工uses单元,实例化其对象会快很多。2、“TButton.Click. 应该能像C#这样 Click += XXXX.Click会更好”
完全一个东西,都是函数指针。只不过Delphi面世的时候,程序在大多数时候还不需要一个事件需处罚多个处理过程,新出来的C#可以对一个事件存储多个函数指针而已
希望您搞清楚一个基本的逻辑:
Button被点击这是“button的事”,但是Button被点击之后要做什么(“这个方法”)并非“button的事”,至少在大多情况下Button被点击之后的事件处理与这个Button本身没有什么关系。
您认为Button被点击的事件处理方法就“应该”属于Button这恰恰是把代码和界面元素混为一谈的拙劣设计。Button只应该起通知的作用,它不必、也不应该管被点击之后做些什么。VCL的设计当然是非常棒的,而且它恰好没有棒到您期待的那种程度。
恕我直言,对于一个应用框架“应该”如何构造,您还没有一个清楚的概念。指点江山为时尚早。:)
东西都是一个人发明的;
可不是一个人哦。
C#的设计者anders hejlsberg在Borland的时候主要是做编译器的,VCL架构的设计者是chuck jazdzewski。说句题外话,Borland的四大高手ABCD(anders hejlsberg、blake stone、chuck jazdzewski、danny thorpe)都跑了,Borland居然不倒,也算得上是超级厉害,和以前的仙童公司有得一拼,是(别人的)技术摇篮。
希望您搞清楚一个基本的逻辑:
Button被点击这是“button的事”,但是Button被点击之后要做什么(“这个方法”)并非“button的事”,至少在大多情况下Button被点击之后的事件处理与这个Button本身没有什么关系。
您认为Button被点击的事件处理方法就“应该”属于Button这恰恰是把代码和界面元素混为一谈的拙劣设计。Button只应该起通知的作用,它不必、也不应该管被点击之后做些什么。VCL的设计当然是非常棒的,而且它恰好没有棒到您期待的那种程度。
恕我直言,对于一个应用框架“应该”如何构造,您还没有一个清楚的概念。指点江山为时尚早。:) //----
太高抬我. 指点江山本人是差的太远了. 不过我还是可以说出我个人的看法. 是不是. :)
Button被点击这是“button的事”,但是Button被点击之后要做什么(“这个方法”)并非“button的事”,至少在大多情况下Button被点击之后的事件处理与这个Button本身没有什么关系。
您认为Button被点击的事件处理方法就“应该”属于Button这恰恰是把代码和界面元素混为一谈的拙劣设计。Button只应该起通知的作用,它不必、也不应该管被点击之后做些什么。//--------
"您认为Button被点击的事件处理方法就“应该”属于Button"
这个是您的认为. 我只能说您未明白我想说的意思. Button要通知谁. 为什么不能直接通知过去呢. 偏偏要Form
生成个buttonClick事件,
您觉得是直接 Click += XXXX.Click 好, 还是在form.buttonClick中写 XXXClick 好呢?
其实质大体和调用一个事件列表相似,你完全可以自己订制一个Button类,来实现类似的方法,当然,实现起来可能会有很多需要考虑的元素和方面,毕竟,我们很难和那些天才的架构设计大师们相比。
其实"+="运算符的重载也可看成一个函数,这和你用一个例程实现由有什么区别?
区别就在于,C#中,已经在它的类体系里给你预定制了,而你想在诞生在C#之前的Delphi中使用它当然只能由你自己来实现整个体系了。
打一个恐怕不太恰切的比喻,比如我有一台1968年的野马跑车,现在我非要在它上面安装ABS、GPS定位、车载DVD、车载卫星电视、倒车镜头、车载5.1音响系统和自动排档系统,显然,汽车生产厂家不可能给我提供该服务,我只能自己定制。我觉得这就很像楼主现在在说的这个话题。我个人觉得C#不想门语言,它更像微软的一个战略,一个可以用来消灭Window平台上其他应用开发竞争对手的战略。当然,我觉得箭头直指的是Java,同样,如果能顺便消灭其他所有对手就更好了。
从设计的清晰度来讲,Button的OnClick本身就只是一个事实,它不应该去做更多累赘的事.做为一个闹钟的设计者,永远不会说是直接就设计出无数个闹铃接口.如果你想要得到更为广泛的通知服务,实际上在更多的时候提升闹铃的影响面,而不是为每一个人去提供一个闹钟.你也可以去设计另外一种更实用的通知服务,但是不能说原本闹钟的设计就是一个失败的设计.
看您的原话“双击Form上的button时, 会自动生成 procedure Button1Click(Sender: TObject);这个方法不是Button的, 而是Form, 本身是button的事. Form也不得不参加进来自己加入一个方法. 觉得是可以推敲的. ”我相信任何思维正常的人都只能把您的意思理解成“Button被点击后的事件处理方法应该属于Button(‘这个方法’应该是Button的方法,不应该是Form的方法)”,您难道还要说“中文的语法是不是害了不少人”?您所谓“Button要通知谁. 为什么不能直接通知过去呢”令人费解,如何“直接通知”啊?Form.ButtonClick不是“直接通知”,XXXX.Click就是“直接通知”?恕我眼拙,我看不出来Click += XXXX.Click如何就比Button.OnClick := Form.ButtonClick更“直接”。唯一的差别不过是可以添加多个事件处理方法(挂接)还是只能设置单个事件处理方法(替换)//这个可以另外讨论。
显然,您给出的这个XXXX.Click也不可能是孤立存在的,在面向对象的结构中它总得是某个对象(XXXX)的方法吧,不可能成了全局过程吧。您为什么非要看到它属于Form就不爽呢?(而且您不爽错了,见下面)最重要的一点,您说的“偏偏要Form生成个buttonClick事件”是明显的错误理解,就象我前面说的“对于一个应用框架“应该”如何构造,您还没有一个清楚的概念”,OnClick是一个事件,它是属于Button的,而Form生成的buttonClick是一个方法,是处理Button被点击之后要做的事,它是事件处理,而不是事件本身,因此它不必、也不应该成为Button的方法!
就如同交通事故发生后的处理应该是交警的事,而不应该是交通事故中的车辆(司机)的事,那不乱套了。