6

TCustomControlから派生したカスタムコントロールを作成しています。次に例を示します。

type
  TMyCustomControl = class(TCustomControl)
private
  FText: string;
  procedure SetText(const Value: string);
protected
  procedure Paint; override;
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
published
  property Text: string read FText write SetText;
end;

上記は、例を短く単純にするために不完全であることに注意してください。

とにかく、私のコントロールには、FTextCanvas.TextOutを使用して(フィールドからの)テキストを表示するPaintイベントがあります。

コンポーネントがDelphiフォームデザイナに追加されると(ユーザーがコンポーネントに変更を加える前に)、TextOutにコンポーネントの名前を表示させます。TButton、TCheckBox、TPanelなどは、キャプションプロパティを持つこの例です。

コンポーネントの名前をコンストラクターでFTextに割り当てようとすると、空が返されます。例:'';

constructor TMyCustomControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FText  := Name; //< empty string
  ShowMessage(Name); //< empty message box too
end;

これに変更FText := NameするFText := 'Name';と、テキストがコンポーネントに出力されるため、実際のコード内で問題がないことはわかりますが、明らかにこれは「Name」を出力し、MyCustomControl1、MyCustomControl2などの実際のコンポーネント名は出力しません。

だから私の質問は、コンストラクターイベントからコンポーネントの名前をどのように取得できるかということです。

4

4 に答える 4

6

コンストラクターの実行中は、Nameプロパティはまだ割り当てられていません。設計時に、IDEはName、コンポーネントがDesignerにドロップされた後、コントロールのコンストラクターが終了した後、プロパティに値を割り当てます。実行時に、Nameプロパティは代わりにDFMストリーミングシステムによって設定されます。DFMストリーミングシステムは、コンストラクターが終了した後にも呼び出されます。

いずれの場合も、TControl.SetName()プロパティセッターは新しい値を検証しText、現在のText値が古いName値と一致し、コントロールのControlStyleプロパティにcsSetCaptionフラグが含まれている場合に一致するように、新しい値をコントロールのプロパティに設定します(デフォルトではこれが行われます)。Text何らかの理由でプロパティが変更されると、コントロールは自動的に通知を送信しますCM_TEXTCHANGED。コントロールにそのメッセージをキャッチInvalidate()させ、それ自体を呼び出して新しい再描画をトリガーすることができます。Paint()ハンドラー内で、現在のName値をそのまま描画します。空白の場合はそうです。を強制しようとしないでくださいName。VCLに通常どおり処理させてください。

于 2013-01-28T17:46:54.353 に答える
5

これを処理する適切な方法は、の継承されたプロパティTextまたはCaptionプロパティを使用TCustomControlし、が設定されていることを確認することだと思いcsSetCaption ControlStyleます。

于 2013-01-28T17:40:10.483 に答える
0

名前を適用するには、TComponent.Loadedメソッドをオーバーライドできます。

しかし、私はあなたが名前をテキストにコピーするべきではないと思います。それらは意味的に別個のプロパティであり、それらに予期しないバインディングを追加すると、いつかあなたを傷つけるでしょう。

むしろ、WMPaintメソッドは、テキストが空であるかどうかを確認してから名前をレンダリングする必要がありますが、テキストのプロパティ自体は変更しないでください。

procedure TMyComponent.WMPaint; message WM_Paint; var InternalCaption: string;
begin
....
   InternalCaption := Self.Text;
   If InternalCaption = '' then InternalCaption := Self.Name;
   If InternalCaption = '' then InternalCaption := Self.ClassName;
....
   Self.Canvas.OutText(InternalCaption);

Name := 'AAA'; Name := 'BBB';どちらかといえば、テキストと名前が同期しなくなるという単純な理由だけで、プロパティを分離しておく必要があります。そして、あなたのアプローチでは、最初のステートメントはテキストを解決し、2番目のステートメントは実際の名前が変更された後も古い名前を表示したままにします。

于 2013-01-29T08:15:04.673 に答える
0

簡単ではない方法は、メソッドSetNameをオーバーライドすることです。

TMyCaptionString = type of WideString;

TMyLabel = class(TCustomControl)
private
  FCaption: TMyCaptionString;
  FCaptionAsName: Boolean;
  procedure SetCaption(Value: TMyCaptionString);
protected
  procedure SetName(const NewName: TComponentName); override;
public
  constructor Create(AOwner: TComponent); override;
  property Caption: TMyCaptionString read FCaption write SetCaption;
end;

implementation

constructor TMyLabel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csOpaque, csReplicatable,csSetCaption];
  FCaptionAsName := (csDesigning in ComponentState) and not (csReadingState in ControlState);
  ...
end;

procedure TMyLabel.SetName(const NewName: TComponentName);
begin
  if FCaptionAsName then
  begin
    FCaptionAsName := FCaption = Name;
    FCaption := NewName;
    invalidate;
  end;
  inherited SetName(NewName);
end;

procedure TMyLabel.SetCaption(Value: TMyCaptionString);
begin
  if FCaption <> Value then
  begin
    FCaption := Value;
    Invalidate;
    FCaptionAsName := False;
  end;
end;

ユニコードの代わりにワイドストリングを使用し、カスタムプロパティエディタを作成したいので、Captionporeprtyに独自の変数が必要でした。古いトピックで書いていることをお詫びしますが、これがお役に立てば幸いです。

于 2015-09-28T10:32:41.307 に答える