2016-11-24 2 views
2

У меня проблема с простотой в Delphi 10.1 с Firemonkey. При создании нового компонента (на основе TLayout, где находятся некоторые еще компоненты, такие как TDateEdits) Я хотел создать свойствоDelphi 10.1 Firemonkey - значения свойств при разработке компонентов

property EditDate_Position:TPosition read FDateEdits_Position write FDateEdits_PositionSet stored True; 

где я объявил FDateEdits_Position как TPosition и FDateEdits_PositionSet является Функция FDateEdits_PositionSet (значение: TPosition).

Главный конструктор компонента состоит код:

PointF.X:=10; 
PointF.Y:=30; 
FDateEdits_Position:=TPosition.Create(PointF); 

Так у меня есть это свойство EditDate_Position в инспекторе объектов, и я могу изменить это значение. Но почему - после компиляции и запуска это значение сбрасывается до значений, как в Constructor? Я пытался использовать

If (csDesigning in ComponentState) then 
begin 
    PointF.X:=10; 
    PointF.Y:=30; 
    FDateEdits_Position:=TPosition.Create(PointF); 
end; 

исключить эти строки при запуске, но программа падает ( FDateEdits не создан). Я посмотрел на Object Inspector - значения правильно, и больше - в .fmx-файле я вижу правильные значения.

Так что я должен делать? Я заметил, что это значение находится в начальной точке, когда выполняется конструктор, но через некоторое время после него (проверяется с помощью TTimer с интервалом = 1) - он принимает правильные значения.

Переопределение Процедура AfterConstruction не устраняет эту проблему, и мне нужно что-то с пуском (момент создания) с соответствующими значениями. И еще: не все имеет такое поведение. Я вижу, что свойства типа Boolean аналогичны типу TPosition, но свойство TBitmap работает правильно ...

Я думаю, что это результат TPosition.Create (PointF), но как создать это без установки этих значений по умолчанию во время выполнения?

procedure TTest.FDateEdits_PositionSet(Value:TPosition); 
begin 
    FDateEdits_Position:=Value; 
    FDateEdits_Resize; 
end; 

FDateEdits_Resize перемещает некоторые компоненты (Self).

Существует код образца (но не то же самое, это упрощенно):

unit Layout1; 

interface 

uses 
    System.SysUtils, System.Classes, FMX.Types, FMX.Controls, FMX.Layouts, 
    FMX.StdCtrls, System.Types; 

type 
    TLayout1 = class(TLayout) 
    private 
    { Private declarations } 
    FBtn:TButton; 
    FPosition:TPosition; 

    procedure FPositionSet(Value:TPosition); 
    protected 
    { Protected declarations } 
    public 
    { Public declarations } 
    constructor Create(AOwner:TComponent); override; 
    destructor Destroy; override; 
    published 
    { Published declarations } 
    property BtnPosition:TPosition read FPosition write FPositionSet; 
    end; 

procedure Register; 

implementation 

constructor TLayout1.Create(AOwner:TComponent); 
var 
    PointF:TPointF; 
begin 
    inherited Create(AOwner); 
    FBtn:=TButton.Create(Self); 
    FBtn.Parent:=Self; 
    FBtn.Stored:=False; 
    FBtn.Text:='Text'; 

    PointF.X:=10; 
    PointF.Y:=10; 
    FPosition:=TPosition.Create(PointF); 

    FBtn.Position.Assign(FPosition); 
end; 

destructor TLayout1.Destroy; 
begin 
    If FPosition<>nil then FPosition.Free; 
    If FBtn<>nil then FBtn.Free; 

    inherited; 
end; 

procedure TLayout1.FPositionSet(Value:TPosition); 
begin 
    FPosition.Assign(Value); 
    FBtn.Position.Assign(Value); 
end; 

procedure Register; 
begin 
    RegisterComponents('Samples', [TLayout1]); 
end; 

end. 

Но я заметил, что просто позвонив

Layout11.BtnPosition.X:=50; 

не имеет никакого результата, структурной линии в коде не работает (но в разделе конструктора работает ...)

+0

Добавлено в конце поста – Wojtek

+0

До сих пор не работают. Работайте только тогда, когда я добавлю TTimer с интервалом. Тогда это значение правильно. Похоже, что после создания в Designtime RunTime создается снова - с заводскими настройками, но после построения значения отображаются из файла fmx (или что-то подобное) ... – Wojtek

ответ

2

Что вы описываете - это нормальное поведение. TPosition Подпрограммы определены как nodefault, поэтому они всегда хранятся в файле FMX независимо от значения. Ваш конструктор вызывается во время разработки и времени выполнения, поэтому сначала вы должны установить значения по умолчанию. При открытии существующей формы/кадра во время разработки или запуска проекта во время выполнения FMX загружается для перезаписывания значений по умолчанию. Совершенно нормальное поведение.Если вы не хотите, чтобы ваш компонент действовал по умолчанию при загрузке FMX-файла, вам необходимо проверить свойство ComponentState и переопределить виртуальный метод Loaded().

Для того чтобы присвоить BtnPosition.X (или Y), чтобы иметь эффект, вам необходимо назначить обработчик события для события TPosition.OnChange.

Попробуйте это:

unit Layout1; 

interface 

uses 
    System.SysUtils, System.Classes, FMX.Types, FMX.Controls, FMX.Layouts, 
    FMX.StdCtrls, System.Types; 

type 
    TLayout1 = class(TLayout) 
    private 
    { Private declarations } 
    FBtn: TButton; 
    FPosition: TPosition; 

    procedure FPositionChanged(Sender: TObject); 
    procedure FPositionSet(Value: TPosition); 
    protected 
    { Protected declarations } 
    procedure Loaded; override; 
    procedure Notification(AComponent: TComponent; Operation: TOperation); override; 
    public 
    { Public declarations } 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    published 
    { Published declarations } 
    property BtnPosition: TPosition read FPosition write FPositionSet; 
    end; 

procedure Register; 

implementation 

constructor TLayout1.Create(AOwner: TComponent); 
var 
    PointF: TPointF; 
begin 
    inherited Create(AOwner); 
    FBtn := TButton.Create(Self); 
    FBtn.Parent := Self; 
    FBtn.Stored := False; 
    FBtn.Text := 'Text'; 

    PointF.X := 10; 
    PointF.Y := 10; 
    FPosition := TPosition.Create(PointF); 
    FPosition.OnChange := FPositionChanged; 

    If not (csLoading in ComponentState) then 
    FBtn.Position.Assign(FPosition); 
end; 

destructor TLayout1.Destroy; 
begin 
    FPosition.Free; 
    FBtn.Free;  
    inherited; 
end; 

procedure TLayout1.FPositionChanged(Sender: TObject); 
begin 
    if (FBtn <> nil) and not (csLoading in ComponentState) then 
    FBtn.Position.Assign(FPosition); 
end; 

procedure TLayout1.FPositionSet(Value: TPosition); 
begin 
    if Value <> FPosition then 
    FPosition.Assign(Value); 
end; 

procedure TLayout1.Loaded; 
begin 
    inherited; 
    FBtn.Position.Assign(FPosition); 
end; 

procedure TLayout1.Notification(AComponent: TComponent; Operation: TOperation); 
begin 
    inherited; 
    if (Operation = opRemove) and (AComponent = FBtn) then 
    FBtn := nil; 
end; 

procedure Register; 
begin 
    RegisterComponents('Samples', [TLayout1]); 
end; 

end. 
+0

Привет, Remy, спасибо за это. Он решает только проблему с Layout11.BtnPosition.X: = 50, но только это. У меня все еще есть проблема, описанная сверху - значение свойства при запуске программы находится в режиме «конструктор», а затем свойство берет мои значения (взятые из Object Inspector). – Wojtek

+0

@Wojtek: это совершенно нормальное поведение. Я обновил свой ответ. –

+0

очень хорошо - это полезно! И еще один вопрос: как заставить обновить позицию Btn во время разработки? Я вижу все еще в том же месте при изменении свойства i Object Inspector – Wojtek

Смежные вопросы