问题描述
这是我的组件的总体结构:
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 formedTPicture
. 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 theTPicture
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 namedData
. So, where does that come from. The answer is in the overriddenDefineProperties
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
andReadData
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方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
- TCategory
- 财产类别:TCollection(属于TCategory)