创建窗体时不会调用TPicture属性的Set方法 [英] Set method of TPicture property doesn't get called when the form is created

查看:97
本文介绍了创建窗体时不会调用TPicture属性的Set方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的组件的总体结构:

Here's my component overall structure:


  • 我的组件


    • 财产类别:TCollection(属于TCategory)


      • TCategory


        • 财产图标:TPicture读取FIcon写入SetIcon;

        • 属性示例:整数读取FExample写入SetExample;

        • (其他类别属性... )

        在IDE的对象检查器中,我选择了一张图片并将其成功序列化(我在表单视图作为文本)。我在 SetIcon 方法上设置了一个断点,当我编译并运行该应用程序时,根本没有调用它。同时, SetExample 被正确调用。

        In the Object Inspector of the IDE, I choose a picture and it gets serialized successfully (I checked it in form view as text). I set a breakpoint on SetIcon method and when I compile and run the application, it doesn't get called at all. At the same time, SetExample gets called right as it should.

        TPicture 属性?

        PS:在IDE中调用Set方法,但在运行时不调用。

        P.S: Set method is called in IDE, but not at runtime.

        以下是代码的MCVE:

        Here's a MCVE of the code:

        unit MCVE;
        
        interface
        
        uses
          System.SysUtils, System.Classes, Vcl.Controls, Graphics, Dialogs;
        
        type
          TMyCollectionItem = class(TCollectionItem)
          private
            FIcon: TPicture;
            procedure SetIcon(const Value: TPicture);
          public
            constructor Create(Collection: TCollection); override;
          published
            property Icon: TPicture read FIcon write SetIcon;
          end;
        
          TMyCollection = class(TCollection)
          end;
        
          TMCVE = class(TCustomControl)
          private
            FCollection: TMyCollection;
            procedure SetCollection(const Value: TMyCollection);
          public
            constructor Create(AOwner: TComponent); override;
          published
            property MyCollection: TMyCollection read FCollection write SetCollection;
          end;
        
        procedure Register;
        
        implementation
        
        procedure Register;
        begin
          RegisterComponents('Samples', [TMCVE]);
        end;
        
        { TMyCollectionItem }
        
        constructor TMyCollectionItem.Create(Collection: TCollection);
        begin
          inherited;
          FIcon := TPicture.Create;
        end;
        
        procedure TMyCollectionItem.SetIcon(const Value: TPicture);
        begin
          ShowMessage('SetIcon is called!');
          FIcon.Assign(Value);
        end;
        
        { TMCVE }
        
        constructor TMCVE.Create(AOwner: TComponent);
        begin
          inherited;
          FCollection := TMyCollection.Create(TMyCollectionItem);
        end;
        
        procedure TMCVE.SetCollection(const Value: TMyCollection);
        begin
          FCollection := Value;
        end;
        
        end.
        


        推荐答案

        对于简单类型,例如 Integer 布尔值 Double 等,流式传输就是您描述的方式。流式框架读取值,然后调用属性设置器。

        For simple types like Integer, Boolean, Double etc., streaming operates the way you describe. The streaming framework reads the value, and calls the property setter.

        对于更复杂的类型,例如 TPicture ,它不会那样发生。流框架无法调用属性设置器。为此,它需要拥有一个完整的 TPicture 。而且它不知道该怎么做,先验。

        For a more complex type like TPicture, it does not happen that way. The streaming framework cannot call the property setter. In order to do so it would need to get hold of a fully formed TPicture. And it doesn't know how to do that, a priori.

        所以发生的是,流框架调用属性的getter来获取 TPicture 实例,您的组件的构造函数已创建。然后以存储在.dfm文件中的 TPicture 的状态进行流传输。

        So what happens instead, is that the streaming framework calls the getter of the property to obtain the TPicture instance that your component's constructor created. And then streams in the state of the TPicture stored in the .dfm file.

        实际上, TPicture 没有已发布的属性。图片数据保存在名为 Data 的属性下的.dfm文件中。所以,那是从哪里来的。答案是在覆盖的 DefineProperties 方法中。代码看起来像这样:

        As it happens, TPicture has no published properties. The picture data is saved to the .dfm file under a property named Data. So, where does that come from. The answer is in the overridden DefineProperties method. The code looks like this:

        procedure TPicture.DefineProperties(Filer: TFiler);
        
          function DoWrite: Boolean;
          begin
            // .... code removed for brevity
          end;
        
        begin
          Filer.DefineBinaryProperty('Data', ReadData, WriteData, DoWrite);
        end;
        

        WriteData ReadData 方法进行流式传输。

        The WriteData and ReadData methods do the streaming.

        因此,回顾一下。您问为什么在图片属性中流式传输时不调用 TPicture 属性的设置器。之所以不会调用它,是因为在构造函数中创建的图片对象会在其属性中流式传输。

        So, to recap. You asked why the setter for a TPicture property was not called when streaming in the picture's properties. It is not called because the picture object that you created in your constructor streams in its properties.

        这篇关于创建窗体时不会调用TPicture属性的Set方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆