我定制了一个控件(TMyComponent),它会关联n个其他控件。并保存每个控件的信息(通过自定义的TMyControls类)。但是当某个被关联(记录信息)的控件更改名字的时候,我该如何处理呢?或者说,我要怎么得知某个已经被我记录了信息的控件更名的通知?

解决方案 »

  1.   

    好象如果只是更名的话,应该不会有访问上的问题吧,IDE会自动更改属性显示的。如果是链接的控件被删除的话,这个事件倒是一定要处理。
      

  2.   

    要不你改VCL源码,在Name属性更改事件中加上向父窗体发送特定消息的代码,然后你的控件再拦载这些消息就可以了。
      

  3.   

    修改原控件代码, 修改Name属性时,发送特定消息是可行的
      

  4.   

    procedure TComponent.SetName(const NewName: TComponentName);
    begin
      if FName <> NewName then
      begin
        if (NewName <> '') and not IsValidIdent(NewName) then
          raise EComponentError.CreateResFmt(@SInvalidName, [NewName]);
        if FOwner <> nil then
          FOwner.ValidateRename(Self, FName, NewName) 
      //可以看到当每一个组件更新时候,会对他的拥有者发消息
      //可以在拥有者的ValidateRename消息
        else
          ValidateRename(nil, FName, NewName);
        SetReference(False);
        ChangeName(NewName);
        SetReference(True);
      end;
    end;procedure TComponent.ValidateRename(AComponent: TComponent;
      const CurName, NewName: string);
    begin
      if (AComponent <> nil) and not SameText(CurName, NewName) and
        (AComponent.Owner = Self) and (FindComponent(NewName) <> nil) then
        raise EComponentError.CreateResFmt(@SDuplicateName, [NewName]);
      if (csDesigning in ComponentState) and (Owner <> nil) then
        Owner.ValidateRename(AComponent, CurName, NewName);
    end;
    在看在类中ValidateRename为虚方法!
     TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)
     protected
    procedure ValidateRename(AComponent: TComponent;
          const CurName, NewName: string); virtual;
    end
    所以我的想法是做一个TFROM的子类对上面的虚函数进行OVERRIDE
    然后在消息发生时候发消息通知你做的组件
      

  5.   

    TCustomForm = class(TScrollingWidget)
    procedure ValidateRename(AComponent: TComponent;
          const CurName, NewName: string); override;
    //在TFORM类的父类中你可以发现他被覆盖了procedure TCustomForm.ValidateRename(AComponent: TComponent; const CurName,
      NewName: string);
    //覆盖后的代码
    begin
      inherited ValidateRename(AComponent, CurName, NewName);
      if FDesignerHook <> nil then
        FDesignerHook.ValidateRename(AComponent, CurName, NewName);
    end;所以我的方法你明白了把就是做一个TFORM的子类,
    然后对ValidateRename进行覆盖,
    然后用这个你做的类,做那些控件的父窗口并且做成拥有者形式,就是那些控件如果动态生成的话,要把拥有者参数写成你生成类的窗口啊。花我20分钟看VCL
      

  6.   

    当一个子组件的名字被修改前,VCL调用ValidateRename检查其最顶级拥有者拥有的所有子组件是否有名字和新名字相同的组件,所以覆盖“n个其他控件”的拥有者的ValidateRename就可以得知那个(AComponent)组件的名字要发生变化。
    但是很不幸的是,如果“n个其他控件”的拥有者为nil的话,这样就无法解决问题了。—————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    —————————————————————————————————
      

  7.   

    SetName是一个虚拟方法:
    procedure SetName(const NewName: TComponentName); virtual;
    对于单个的组件,可以覆盖这个方法,就可以得到名字修改信息。但是对于多个组件,显然不能一一覆盖,如果能找到动态创建函数和过程的方法(就是动态创建新的SetName方法用来替换原来的SetName),这个问题就解决了。可惜我最近一直为这个问题烦恼,不知道怎么办呢。—————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    —————————————————————————————————
      

  8.   

    VCL博大精深,呵呵,多谢ZJYBEST指点!谢谢!
      

  9.   

    FrameSniper(§好好学习 天天向上§) :互相学习! 
    lxpbuaa(桂枝香在故国晚秋) :
      我想对于组件来说他们的SETNAME的函数所在VMT的索引号是相同的,但是索引号下的调用地址可以不同因为是VIRTUAL函数,所以我的想法可以直接修改该索引下的调用地址,指向我们新做的一个SETNAME中去,做完以后也可以链接原来的旧的SETNAME,形成一个调用莲,这就可以动态连接拉!
      

  10.   

    谢谢各位先!
    不过第一我可不打算写一个tform子类,因为这样通用性(姑且先这么说)不强。
    还有那部分vcl源码我也看了,setname只是向owner传递更名的通知。
    至于“修改该索引下的调用地址”应该也可以在设计期完成,不过我觉得这样做也有点得不偿失。
    不知道大家还有没有新的发现呢?
    另外zhboy(孔方兄) 说保存这些控件的指针倒是可以考虑......我自己再试试看吧。
    再次谢谢大家,这点分不够我可以再开一个帖子。
      

  11.   

    zjybestzjybest(zjybestzjybest) ( ) :
    取得SetName的地址可以通过RTTI搞定(具体的就是通过GetPropInfo(,'Name'),然后给SetName加上一个偏移就可以)。但是SetName是一个方法而不是过程,方法有一个附加的对象指针(指向所属对象),在动态创建此方法时,如果指定此对象指针,是一个难题。—————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    —————————————————————————————————