组件动态遍历,RTL信息万分疑惑,望指点!(50分)

  • 主题发起人 小八哥
  • 开始时间

小八哥

Unregistered / Unconfirmed
GUEST, unregistred user!
我在一窗体中用到Panel(其中有六个Label),DBText,Label等组件,
想实现的目标是在程序运行过程中当我鼠标点击任一组件时,
该组件颜色变红(Panel与其中的Label看成一个组件)。
当我又点击另一组件时,这时的组件变红,上次点击的组件变回原色。
即在任意时刻只有一个组件的颜色是红色。我的代码如下
for i:=0 to ComponentCount-1 do
 begin
  if Components.Name=TComponent(Sender).Name
 then TLabel(Components).Font.Color:=clred
  else if (Components is TLabel) then TLabel(Components).Font.Color:=clBlack;
 end;
我这代码是错误的在then TLabel(Components).Font.Color:=clred
这句中我不知用什么类来产生panel,dbtext,label的公有.font.color所以用了TLabel类,
运行发现对Panel无用。

下面这行代码更是不行了, 只有对label有效。
else if (Components is TLabel) then TLabel(Components).Font.Color:=clBlack;
我不知说清了没有,万分疑惑,望指点!
 
if Components is TPanel then
TPanel(Components).Font.Color:=...;
if Components is TLable then
TLable(Components).Font.Color:=...;
 
to ysai
我知道panel,dbtext,label是继承自TControl类,但把
TLabel(Components).Font.Color
改成
TControl(Components).Font.Color
编译都通不过。
[Error] Unit3.pas(123): Undeclared identifier: 'Font'
是不是这种运行时出现的属性之类的。我要在编译时把某些开关(选项)关掉。
 
在《Delphi 5 开发人员指南》中有个过程是判断控件有没有某个属性
 
Font是TControl的属性,但是它被protected了,所以外部不能访问,由TControl派生下来的TGraphiControl就可以访问Font了,TLabel是间接继承TGraphiControl的类,
而TPanel是间接继承TWinControl的类,TWinControl也可以访问Font属性,TWinControl和TGraphiControl是同一级别的类,都由TControl派生。

如果你所用到的控件都由TGraphiControl派生下来的话,你可以用TGraphiControl().Font
而若是都由TWinControl派生下来的话,你可以用TWinControl().Font,但是你偏偏分别用到这两个,而再往上一级的话,Font就被protected了,不能访问。

这样的话,想用同一种类来强制转换的话,好象不行吧,最好把控件换一下。换成由同一种类派生的。

或者........,改delphi的源代码,把类TControl的Font属性放在Public下面,重新编译,不过这种做法不太好啊.........
 
有一个方法可以办到,
你重新定义一个从TControl继承的类
TMyControlAccess = class(TControl);

然后,你就可以这样写:
TMyControlAccess(Components).Font.Color:=...;
就可以了。
 
同意鲁小班的
 
楼上鲁班的兄弟,这样也不行吧,按您所说的,从TControl继承下来的类TMyControlAccess其实也是和TGraphicontrol,TWinContrl是
同一级的类,所以小八哥他所有用到的控件都不是TMyConTrolAccess的直接或者间接的派生类,就是说和TMyControl没有血缘关系了,
相当与侄子和叔叔的关系,所以我想也就不能强制转换类了。
 
按鲁小班的建议,我写了个例子测试了一下,结果和我说的结果一样
我写了个从TControl继承的tmyctl,并且将他的Font放在publish下,使font可供访问。
结果我在程序中写
(Label1 as tmyctl).Font.Color:=clred;
这时编译通不过,Incompatible types: 'tmyctl' and 'TLabel',(不兼容的类型,tmyctl 和 tlabel)

而我在事件中写下面一句:
(Sender as tmyctl).Font.Color:=clred;
编译运行以后,报错'inviald class typecast '(无效的类转换)

wang2855,不信的话可以自己去试试。其实按推理也可以想象到这种结果,我只是为了验证一下
 
zyg_zm:
谁叫你用as了?我前面的帖子也没有用as啊.
as 是强制类型转换,是要类型兼容的,
比如A as B,
只有当B从A继承的时候才能编译通过.

而B(A)则不同,它是不用类型兼容的,A和B可以
没有任何关系.它只是把A指向的指针转换成B.

还有,在你的tmyctl中不用再在published中重新定义Font.
这样做反而画蛇添足,运行的时候会出错.
 
to 鲁小班:
好吧,我去试试看,如果真的是这样的话,好真是个好办法,又多学一招!
 
不好意思,原来TWinControl和TGraphicControl的Font属性并没有公布出来,也是不可访问的,上次我看错了就发言了,罪过罪过...
另外,
to 鲁小班
>> 还有,在你的tmyctl中不用再在published中重新定义Font.这样做反而画蛇添足,运行的时候会出错
TControl的font是在protected下的,我在Tmyctl中只是把他声明为published,否则你根本就不能访问这个属性,无论你用什么转换都没用的.
所以不能说是画蛇添足,而是必要的,否则编译都通不过,至于运行时要出错的话,那是别的原因....找找吧,其实我前面分析的都是按照类的定义来看的,应该不会有很低级的错误。

>>而B(A)则不同,它是不用类型兼容的,A和B可以
>>没有任何关系.它只是把A指向的指针转换成B.
虽然是这样说,但是用这种方法,你会发现有时候这样写根本就没用......
 
zyg_zm:
其实这个方法在VCL源代码中也是有应用的,
请参看VCL源文件ComCtrls.pas第16737行(Delphi5)。

to 鲁小班
>> 还有,在你的tmyctl中不用再在published中重新定义Font.这样做反而画蛇添足,运行的时候会出错
TControl的font是在protected下的,我在Tmyctl中只是把他声明为published,否则你根本就不能访问这个属性,无论你用什么转换都没用的.
所以不能说是画蛇添足,而是必要的,否则编译都通不过,至于运行时要出错的话,那是别的原因....找找吧,其实我前面分析的都是按照类的定义来看的,应该不会有很低级的错误。

谢谢你的提醒,确实是我的错误,我在published中这样定义Font:
published
property Font: TFont;
这样它就重新又定义了一个字段Font,这个Font和TControl中的Font是不一样的,
所以在访问这个字段的时候会出现非法操作。

如果这样写就正确了:
published
property Font;

不过,也可以不添加这个声明,效果也是一样的。

 
》不过,也可以不添加这个声明,效果也是一样的。
真的吗,如果不添加这个声明的话,按照我的理解应该是访问不到这个属性的,所以这里我不太明白。不过我没有去测试过。能讲讲原理吗
 
其实道理很简单,DELPHI把在同一个单元里面的类都作为"友元",也就是说可以访问非继承类
的Procteded属性.首先声明一个类 TMyControl = class(TControl); ,然后在这个单元内用
这个类转换TControl对象,因为TMyControl由于上面所说的原因,所以在这个单元内部的类都
可以访问TMyControl类的Protected属性.所以,下面这个是合法的
TMyControl(Compinents).Font.Color := clRed;
这是一种访问类的Protected属性的一个技巧.不过Private是绝对不行的啦.
 
原来如此,其实我也想到了除非是当作友元函数,可是我总以为作为某个类的友元函数需要申明,象C++的friend.....多谢了,又学一招
 
就这么几种控件,还是分种类处理一下吧。
 
因为有些事很多天没来了。
我试用了hlsl的方法,先在type中声明
TMyControl = class(TControl);
后在程序中改为如下代码
for i:=0 to ComponentCount-1 do
if Components.Name=TComponent(Sender).Name
then
TMyControl(Components).Font.Color:=clRed
else TMyControl(Components).Font.Color:=clBlack
end;
编译通过,但在运行时我点选一个控件时,
就出错。
"Access violation at address 00428AB1 in module 'project1.exe'. Read of address ffffffff"
确定以后程序仍能运行。
另外一个问题,用我程序的方法对panel(上面放了几个label)没有效果,不知如何
改进。
 
真是脱裤子放屁--多此一举!

只要是共同拥有的属性,用什么玩艺做强制类型转换都可以,比如:

TEdit(Label1).color:=clred;
 
顶部