Ustawienie pustego Caption-a w komponencie

0

Jest sobie komponent TMojKomponent (kod okrojony do minimum) na bazie panelu, na którym leżą komponenty FImage (wycięty) i FLabel. Po upuszczeniu komponentu na formatkę Designer-a, Caption komponentu FLabel ustawia się na 'Caption'. Tu OK.

Gdy w komponencie TMojKomponent ustawię property Caption na inny niepusty łańcuch, to we FLabel ustawi się taki Caption, zarówno w Designer-ze, jak i po uruchomieniu programu. Tu też OK.

Jeśli natomiast ustawię property Caption mojego komponentu na pusty łańcuch (może zaistnieć taka potrzeba), to w Designer-ze zostanie on ustawiony w FLabel, ale po uruchomieniu programu już nie (nie wykona się metoda SetCaption mojego komponentu), przez co w FLabel będzie wyświetlane 'Caption'.
Zauważyłem, że jeśli w mojej kontrolce (jak również np. w TPanel, TButton) jest ustawiony Caption jako pusty łańcuch, to w DFM-ie nie występuje pole Caption w ustawieniach kontrolki, co zapewne powoduje, że w runtime nie jest wywoływany setter property Caption komponentu.

Czy da się zrobić, pomijając jakieś kombinacje z ustawianiem spacji jako Caption, żeby pusty Caption był wyświetlany także po uruchomieniu?

unit MojKomponent;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, StdCtrls,  ExtCtrls, Forms;

type
  TMojKomponent = class(TPanel)
  private
    FLabel: TLabel;

    procedure SetCaption(const aCaption: String);
    function GetCaption: String;

  protected
    procedure CreateWnd; override;

  public
    constructor Create(AOwner: TComponent); override;

  published
    { Published declarations }
     property Caption: string read GetCaption write SetCaption;

  end;

 procedure register;

implementation

procedure register;
begin
  RegisterComponents('MOJE', [TMojKomponent]);
end;

constructor TMojKomponent.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ParentBackground := false;
  ParentCtl3D := False;
  BevelOuter := bvNone;
  BorderStyle := bsSingle;
  BorderWidth := 1;

  FLabel := TLabel.Create(Self);
  FLabel.Parent := self;
  FLabel.ParentColor := false;
  FLabel.Transparent := true;

  FLabel.Left := 5; //pozycja Labela na panelu
  FLabel.Top := 5;

  FButtonLabel.Caption := 'Caption';
end;


procedure TMojKomponent.CreateWnd;
begin
  inherited CreateWnd;
  inherited Caption := ''; //czyszczenie Captiona panelu
end;

procedure TMojKomponent.SetCaption(const aCaption: string);
begin
  if FLabel.Caption <> aCaption then
    FLabel.Caption := aCaption;
end;

function TMojKomponent.GetCaption: string;
begin
  Result := FLabel.Caption;
end;

end.
0

zobacz tak. BTW pod debugerem byś wiedział dokładnie co się dzieje

constructor TMojKomponent.Create(AOwner: TComponent);
begin
  FLabel := TLabel.Create(nil);
  FLabel.Parent := self;
  FLabel.ParentColor := false;
  FLabel.Transparent := true;
 
  FLabel.Left := 5; //pozycja Labela na panelu
  FLabel.Top := 5;
  FLabel.Caption := 'Caption';

  inherited Create(AOwner);

  ParentBackground := false;
  ParentCtl3D := False;
  BevelOuter := bvNone;
  BorderStyle := bsSingle;
  BorderWidth := 1;
end;
1

Pusty ciąg znaków dla tekstowej właściwości domyślnie nie jest przechowywany w pliku .dfm.

Zwróć uwagę na to, że jak położysz na formularzu kontrolkę TLabel, ustawisz pusty ciąg znaków dla Caption i zapiszesz projekt, to w pliku .dfm nie będzie informacji o Caption tej etykiety. Dlatego trzeba to obejść.

Spróbuj w ten sposób:

const
  MY_COMPONENT_TITLE = 'my component';

type
  TMyComponent = class(TCustomPanel)
  private
    FTitle: String;
    FTitleLabel: TLabel;
  private
    function IsTitleStored(): Boolean;
  private
    procedure SetTitle(const ATitle: String);
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Title: String read FTitle write SetTitle stored IsTitleStored;
  end;
  
{..}

constructor TMyComponent.Create(AOwner: TComponent);
begin
  FTitleLabel := TLabel.Create(Self);

  FTitle := IfThen(csDesigning in ComponentState, MY_COMPONENT_TITLE, '');
  FTitleLabel.Caption := FTitle;

  {..}
end;

function TMyComponent.IsTitleStored(): Boolean;
begin
  Result := FTitle <> MY_COMPONENT_TITLE;
end;

procedure TMyComponent.SetTitle(const ATitle: String);
begin
  if FTitle <> ATitle then
  begin
    FTitle := ATitle;
    FTitleLabel.Caption := ATitle;
  end;
end;
0

Dobra już wiem, w konstruktorze komponentu trzeba dodać sprawdzanie, w jakim stanie jest komponent i ustawiać Caption w FLabel tylko wtedy, gdy jest na etapie projektowania.

 if (csDesigning in ComponentState) then
    FLabel.Caption := 'Caption';

Jeśli komponent będzie w fazie uruchomienia (runtime), to domyślnie Caption w FLabel będzie pusty i jeśli property Caption mojego komponentu też będzie ustawione puste, to nie wykona się setter SetCaption i Caption w FLabel pozostanie pusty, czyli tak jak chciałem.

0

Tak szczerze pisząc, to jeśli Twój komponent ma mieć możliwość ustawienia pustego ciągu dla subkontrolki etykiety, to równie dobrze możesz sobie dodać właściwość logiczną, którą będziesz po prostu określać widoczność etykiety.

W swojej paczke kontrolek mam przycisk, w ktorego skład wchodzą dwa łańcuchy:

  • tytuł – krótki tekst, większym fontem w kolorze,
  • informacja – nieco dłuższy tekst, mniejszymi literami, w kolorze ~czarnym.

Gdzieniegdzie potrzebuję samego tytułu, bez dodatkowej, dłuższej informacji, więc dodałem sobie właściwość określającą styl kontrolki. Tyle że skorzystałem z enuma zamiast wartości logicznej. Z tej właściwości korzystam w metodzie Paint, w której renderowane są oba ciągi znaków, lub tylko sam tytuł (informacja jest ignorowana, ale tylko podczas renderowania).

1 użytkowników online, w tym zalogowanych: 0, gości: 1