Перейти к содержанию
Fire Monkey от А до Я

Евгений Корепов

Пользователи
  • Постов

    738
  • Зарегистрирован

  • Посещение

  • Победитель дней

    100

Сообщения, опубликованные Евгений Корепов

  1. 46 минут назад, Антон Емельянов сказал:

    Эм.. ничего непонятно :unsure:.. тут куски кода..
    1. что такое  "MetodMinerProRegisterFCM" в  GetHTTP(MetodMinerProRegisterFCM)
    2. где процедура PushClientReceiveNotificationHandler
    3. не определяется   HDevicePushParams в  HDevicePushParams.DeviceID:=FPushClient.DeviceID;


    Пришлите  рабочий  архив с проектом - простая форма  и кнопка получить токен...  будем сильно благодарны

    Вообще то я приложил к сообщению архив. Если бы удосужились его скачать и открыть, то обнаружили кроме готовой библиотеки для работы с пушами еще и демо-проект. 

  2. Скачал ваше тестовое приложение.

    Во первых в манифесте добавьте разрешение на получение

    <%uses-permission%>
        <!-- FCM push notifications permission -->
        <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

    Во вторых чтобы не было каши из кода, просто используйте готовый модуль для пуш оповещений, я его публиковал уже здесь, искать лень, закину еще разок.

     

    Использование элементарное:

    1. В Uses добавьте DW.PushClient и возможно понадобиться System.PushNotification (а может и нет).

    FPushClient : TPushClient;

    Код:

    procedure TFormMain.InitPush;
    begin
    {$IFDEF ANDROID}
      if FSetting.GUID.IsEmpty then
        Exit;
      if Not Assigned(FPushClient) then
        FPushClient := TPushClient.Create
      else
        FPushClient.Active:=False;
      FPushClient.GCMAppID := ConstGCMAppID;
      FPushClient.ServerKey := '';
      FPushClient.BundleID := '';
      FPushClient.UseSandbox := Debug; // Change this to False for production use!
      FPushClient.OnChange := PushClientChangeHandler;
      FPushClient.OnReceiveNotification := PushClientReceiveNotificationHandler;
      try
        FPushClient.Active:=True;
      except
      end;
    {$ENDIF ANDROID}
    end;

    А PushClientChangeHandler вот:

    procedure TFormMain.PushClientChangeHandler(Sender: TObject; AChange: TPushService.TChanges);
    begin
      if TPushService.TChange.DeviceToken in AChange then
      begin
        HDevicePushParams.DeviceID:=FPushClient.DeviceID;
        HDevicePushParams.DeviceToken:=FPushClient.DeviceToken;
        GetHTTP(MetodMinerProRegisterFCM);
      end;
    end;

    GetHTTP(MetodMinerProRegisterFCM); - это отправка токена на свой сервер, замените на свое. К примеру в Memo для начала.

    PushClient.zip

  3. 15 минут назад, Антон Емельянов сказал:

    то есть ключ сервера вообще ненужно пихать в apikey ?

    Это вообще разные вещи, туда ничего пихать не нужно вообще.  Но если очень хочется, то это ключь ПРИЛОЖЕНИЯ из GooglePlayConsole

  4. 1 минуту назад, Антон Емельянов сказал:

    Так вот какраз проблема в том что не выдаются токены

    Clip2net_180227130005.png

    Из этого скрина вам нужен только Пункт 4. Пункты 2 и 3 никак не повлияют. Пункт 3 испольнять не вздумайте, не зачем ваш СЕРВЕРНЫЙ ключ светить в приложении. Это из другой оперы ключ.

  5. Что то тут вы сами себя запутали. Все просто (через жопу конечно с появлением Firebase, но ничего не поделаешь, у американцев вслед за датой-задом-наперед и имперской системой исчисления, все остальное тоже немного наперекосяк) :

    1. Идете в https://console.firebase.google.com/ , нажимаете "Добавить проект", произвольное, понятное вам название проекта, страна. Нажимаем сохранить.

    2. Попадаем на https://console.firebase.google.com/project/test005-e3e15/overview, красочные квадратики и разные перделки-свистелки, вверху страницы нажимаем "Добавьте Fiebase в свое приложение на Андроид". В открывшемся окне вводите Название пакета (В предыдущих сообщения вам показывали где оно), остальное не надо, нажимайте сохранить. Вам предложат скачать файл google-services.json, он вам нафик не нужен, это только для андроид студии, Эмбаркадера про это еще дочитала документацию.

    3. Далее нужно найти на странице малюсенькое колесико, нажать на него, Настройки, вверху Cloud Messaging, вот на этой странице есть все что вам нужно. Скриншот прилагаю.

    Ключ сервера - для отправки пушей с вашего сервера.

    Идентификатор отправителя - для получения Токенов в вашем андроид приложении.

    Всякий бред в консоли разработчика (типа Подключения идентификатора отправителя ) игнорируйте, это индусские аутсорсеры пишут, с ними потеряна связь несколько лет назад из за наводнения в Индийском океане, но коммитить код они не перестали).

    Вот и все.

    P.S. Имейте ввиду, что пушсообщения могут начать приходить не сразу, у них притормаживает слегка и после добавления проекта часов 10-20 может ничего не работать. Токены начинаю выдаваться сразу.

     

    Снимок.PNG

  6. В 19.02.2018 в 22:43, wamaco сказал:

    Вы бы хоть код выложили с TThreadedQueue, как использовать вместо TThread.Synchronize, чтобы сообщество было  в курсе. Спасибо!

    Вот простой пример накидал. Главная форма, поток, две очереди (очередь запросов и очередь ответов). Вы в главной форме вбивате два числа, и нажимаете кнопку по своему усмотрению (прибавить, умножить, разделить). Числа отправляются в Очередь запросов, поток получает задачу, выполняет и отправляет ответ в очередь ответов. Главная форма, в Application.OnIdle ждет получения результатов проверяя Очередь ответов, при получении добавляет их в Memo. Все. Проект прилагаю в архиве, вот листинг:

    unit UnitFormMain;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
      System.Generics.Collections, FMX.StdCtrls, FMX.Edit, FMX.EditBox,
      FMX.NumberBox, FMX.Layouts, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo;
    
    type
      TThreadOperation = (Sum, Mult, Divinity);
      TThreadDataRequest = record
        A : Double;
        B : Double;
        Operation : TThreadOperation;
      end;
      TThreadDataAnswer = record
        Operation : TThreadOperation;
        A : Double;
        B : Double;
        X : Double;
        ErrorMessage : String;
      end;
      TQueueRequest = TThreadedQueue<TThreadDataRequest>;
      TQueueAnswer = TThreadedQueue<TThreadDataAnswer>;
    
      TExcampleThread = class(TThread)
      protected
        FQueueRequest: TQueueRequest;
        FQueueAnswer: TQueueAnswer;
        procedure Execute; override;
      public
        constructor Create(AQueueRequest : TQueueRequest; AQueueAnswer : TQueueAnswer); reintroduce;
      end;
    
      TFormMain = class(TForm)
        Memo: TMemo;
        Layout1: TLayout;
        Label1: TLabel;
        Label2: TLabel;
        ButtonSum: TButton;
        ButtonMult: TButton;
        ButtonDiv: TButton;
        EditA: TEdit;
        EditB: TEdit;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure ButtonClick(Sender: TObject);
      private
        { Private declarations }
        FQueueRequest: TQueueRequest; // Очередь запросов
        FQueueAnswer : TQueueAnswer;  // Очередь ответов
        FExcampleThread : TExcampleThread;
        procedure OnApplicationIdle(Sender : TObject; var Done: Boolean);
      public
        { Public declarations }
      end;
    
    var
      FormMain: TFormMain;
    
    implementation
    
    {$R *.fmx}
    
    procedure TFormMain.FormCreate(Sender: TObject);
    begin
      FQueueRequest:=TQueueRequest.Create(10, 1000, 10);
      FQueueAnswer:=TQueueAnswer.Create(10, 1000, 10);
      Application.OnIdle:=OnApplicationIdle;
      FExcampleThread:=TExcampleThread.Create(FQueueRequest, FQueueAnswer);
    end;
    
    procedure TFormMain.FormDestroy(Sender: TObject);
    begin
      if Assigned(FExcampleThread) then
      begin
        FExcampleThread.Terminate;
        FExcampleThread.WaitFor;
        FExcampleThread.Free;
      end;
      if Assigned(FQueueRequest) then
        FQueueRequest.Free;
      if Assigned(FQueueAnswer) then
        FQueueAnswer.Free;
    end;
    
    procedure TFormMain.OnApplicationIdle(Sender : TObject; var Done: Boolean);
    Var AThreadDataAnswer : TThreadDataAnswer;
        S : String;
    begin
      if FQueueAnswer.PopItem(AThreadDataAnswer) = TWaitResult.wrSignaled then
      begin
        case AThreadDataAnswer.Operation of
          TThreadOperation.Sum : S:=' + ';
          TThreadOperation.Mult : S:=' * ';
          TThreadOperation.Divinity : S:=' / ';
        end;
        S:=AThreadDataAnswer.A.ToString + S + AThreadDataAnswer.B.ToString + ' = ';
        if Not AThreadDataAnswer.ErrorMessage.IsEmpty then
          S:=S + AThreadDataAnswer.ErrorMessage
        else
          S:=S + AThreadDataAnswer.X.ToString;
        Memo.Lines.Add(S);
      end;
    end;
    
    constructor TExcampleThread.Create(AQueueRequest : TQueueRequest; AQueueAnswer : TQueueAnswer);
    begin
      FQueueRequest:=AQueueRequest;
      FQueueAnswer:=AQueueAnswer;
      Inherited Create(False);
    end;
    
    procedure TExcampleThread.Execute;
    Var AThreadDataRequest : TThreadDataRequest;
        AThreadDataAnswer : TThreadDataAnswer;
    begin
      while Not Terminated do
      begin
        if FQueueRequest.PopItem(AThreadDataRequest) = TWaitResult.wrSignaled then
        begin
          AThreadDataAnswer.Operation:=AThreadDataRequest.Operation;
          AThreadDataAnswer.ErrorMessage:='';
          AThreadDataAnswer.A:=AThreadDataRequest.A;
          AThreadDataAnswer.B:=AThreadDataRequest.A;
          AThreadDataAnswer.X:=0;
          try
            case AThreadDataRequest.Operation of
              TThreadOperation.Sum : AThreadDataAnswer.X:=AThreadDataRequest.A + AThreadDataRequest.B;
              TThreadOperation.Mult : AThreadDataAnswer.X:=AThreadDataRequest.A * AThreadDataRequest.B;
              TThreadOperation.Divinity : AThreadDataAnswer.X:=AThreadDataRequest.A / AThreadDataRequest.B;
            end;
          except
            on E : Exception do
              AThreadDataAnswer.ErrorMessage:=E.Message;
          end;
          FQueueAnswer.PushItem(AThreadDataAnswer);
        end;
        TThread.Sleep(10);
      end;
    end;
    
    procedure TFormMain.ButtonClick(Sender: TObject);
    Var AThreadDataRequest : TThreadDataRequest;
    begin
      AThreadDataRequest.A:=EditA.Text.ToDouble;
      AThreadDataRequest.B:=EditB.Text.ToDouble;
      Case TButton(Sender).Tag of
        1 : AThreadDataRequest.Operation:=TThreadOperation.Sum;
        2 : AThreadDataRequest.Operation:=TThreadOperation.Mult;
        3 : AThreadDataRequest.Operation:=TThreadOperation.Divinity;
      End;
      FQueueRequest.PushItem(AThreadDataRequest);
    end;
    
    end.

     

    test116 TThreadedQueue.zip

  7. 1 час назад, kami сказал:

    Есть дикое ощущение, что могли поломать синхронизацию через TMonitor.Wait.

    В Телеграме обсуждали подобный глюк, по stacktrace было похоже на это.

    После переделки с TThread.Synchronize на TThreadedQueue приложение отработало 12 часов без проблем. Ни ошибок, ни утечек. Так что думаю проблема не в моем коде, а именно в TMonitor. 

    Правда на тестовом приложении, с 7 потоками и синхронизацией TThread.Synchronize воспроизвести проблему не удалось, так что черт его знает на каком этапе начинает глючить.

  8. В 08.02.2018 в 16:27, Akad сказал:

    Заменил код. Сделал ребилд. Упало в этом-же месте в CheckSynchronize.
     

    Тоже самое, один в один. Причем проект на VCL. Та же самая ошибка была в ранних версиях XE. Потом ее пофиксили. 

    В моем случае помогло (надеюсь. пока еще тестирую) избавление от всех TThread.Synchronize в проекте. Заменил на обмен через TThreadedQueue. Теперь до строк 

     if Assigned(SyncProc.SyncRec.FMethod) then
     	SyncProc.SyncRec.FMethod()
    else if Assigned(SyncProc.SyncRec.FProcedure) then
        SyncProc.SyncRec.FProcedure();

    вообще не доходит слава богу.

  9. Долго мучался отсутствием штатного средства красивого вывода JSON в текст, все что есть в комплекте, в REST к примеру, выводит убогую, не читаемую кашу. Плюнул и на написал свою функцию, на базе REST TSON.Format.

    function JsonPrettyPrint(AJsonValue : TJsonValue; AIndent : string = '  ') : string;
    var SourceContent: string;
        AChar: char;
        EOL: string;
        LeftIndent: string;
        isEOL: boolean;
        isInString: boolean;
        isInArray: boolean;
        isEscape: boolean;
    begin
      Result:='';
      EOL:=#13#10;
      AIndent:= '  ';
      LeftIndent:='';
      isEOL:=true;
      isInString:=false;
      isInArray:=false;
      isEscape:=false;
      SourceContent := AJsonValue.ToString; //This will basically display all strings as Delphi strings. Technically we should show "Json encoded" strings here.
      for AChar in SourceContent do
      begin
        case AChar of
          '{' :
            if not isInString and not isInArray then
            begin
              Result := Result + AChar + EOL;
              LeftIndent := LeftIndent + AIndent;
              Result := Result + LeftIndent;
              isEOL := true;
            end;
          ',' :
            if not isInString and (AChar = ',') then
            begin
              isEOL := false;
              if isInArray then
                Result := Result + AChar + ' '
              else
                Result := Result + AChar + EOL + LeftIndent;
            end;
          '}' :
            if not isInString then
            begin
              Delete(LeftIndent, 1, Length(AIndent));
              if not isEOL then
                Result := Result + EOL;
              Result := Result + LeftIndent + AChar;
            end;
          ':' :
            if not isInString and (AChar = ':') then
              Result := Result + AChar + ' ';
           else
            begin
              isEOL := false;
              Result := Result + AChar;
            end;
        end;
        isEscape := (AChar = '\') and not isEscape;
        if not isEscape and (AChar = '"') then
          isInString := not isInString;
        if not isEscape and (AChar = '[') then
          isInArray:=True;
        if not isEscape and (AChar = ']') then
          isInArray:=False;
      end;
    end;

    Результат налицо:

    {
      "Rig": {
        "Name": "node07",
        "Account": "3DQ9fRMVfxHaT7noy7molmuhlCI3RQkxt2y8BB",
        "PowerCost": [4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43, 4.43]
      },
      "ExcavatorInstance": {
        "Host": "192.168.0.156",
        "Port": 38080,
        "APIToken": "asevsdrbdrtnetyjer34yb435t",
        "ConnectionType": "HTTP"
      },
      "Devices": {
        "DeviceType": "",
        "UseDevices": [0, 1, 2, 3, 4]
      },
      "Algorithms": {
        "cryptonight": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [32, "M=2", 876],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "lbry": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [95, 120, -1000],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "pascal": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "decred": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "neoscrypt": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "daggerhashimoto": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "daggerhashimoto_decred": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "daggerhashimoto_sia": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "lyra2rev2": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [95, 120, -1000],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "blake2s": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "equihash": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": ["2", "M=1", "676556"],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "daggerhashimoto_pascal": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "keccak": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        },
        "sia": {
          "Enable": true,
          "Devices_TDP_CoreDelta_MemoryDelta": [108, 150, 500],
          "WorkerPerDevice": 1,
          "WorkerParameters": [],
          "Speed": 1506138068.81243,
          "Power": 851
        }
      }
    }

    Конкретно в текущем случае, массивы мне нужны были в одну строку. Кому понадобиться иное - закомментируйте последние 4 строки.

  10. 4 часа назад, Виталий Иванов сказал:

    А двойной клик по закладке с юнитами (я этим часто пользуюсь)? Оно же вроде как прячет все кроме мешюшки и доп кнопок, так сказать почти во весь экран, я думаю если перенастроить панель инструментов то можно добиться максимально пустого пространства

     

    2018-01-09.thumb.png.4e756e61ddfc3a5dad034129979211cf.png

    Хм, у меня такой фокус не срабатывает :-( Двойной клик по заголовкам Табов с юнитами? Или я не правильно понял? 

  11. 13 часа назад, GoldenEalge сказал:

    5a527855c1c47_.PNG.ee9264d60e973f76ccea374942bee22c.PNG

    одни куки по несколько раз

    Вот блин. А можно кусок кода при котором проблема воспроизводится? При повторном запросе к сайту или как? А то сейчас как раз буду писать кусок модуль и использованием куки для текущего проекта...

  12. Подумал и сделал более изящно - изменил метод Show. 

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      fgActivityDialog.Message := 'Teste';
      fgActivityDialog.Show(3000);
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      fgActivityDialog.Message := 'Teste';
      fgActivityDialog.Cancellable:=True;
      fgActivityDialog.Show;
    end;

    Вот код :

    Скрытый текст


    
    {*********************************************************************
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * Autor: Brovin Y.D.
     * E-mail: y.brovin@gmail.com
     *
     ********************************************************************}
    
    unit FGX.ProgressDialog;
    
    interface
    
    uses
      System.Classes, FGX.ProgressDialog.Types, FGX.Consts, FMX.Types;
    
    type
    
      /// <summary>
      ///   Generic Abstract base class provide base functionality for creation and using progress/activity dialog.
      ///   Each dialog has Message and Title and holds instance of wrapper native dialog.
      /// </summary>
      TfgCustomDialog<T: TfgNativeDialog> = class abstract(TComponent)
      public const
        DefaultCancellable = False;
        DefaultTheme = TfgDialogTheme.Auto;
        DefaultThemeID = TfgNativeDialog.UndefinedThemeID;
      private
        FNativeDialog: T;
        FTitle: string;
        FMessage: string;
        FCancellable: Boolean;
        FTheme: TfgDialogTheme;
        FThemeID: Integer;
        FOnShow: TNotifyEvent;
        FOnHide: TNotifyEvent;
        FOnCancel: TNotifyEvent;
        FAutoCloseTimer : TTimer;
        procedure OnAutoCloseTimerTimer(Sender: TObject);
        procedure SetCancellabel(const Value: Boolean);
        procedure SetMessage(const Value: string);
        procedure SetTitle(const Value: string);
        procedure SetTheme(const Value: TfgDialogTheme);
        procedure SetThemeID(const Value: Integer);
        procedure SetOnCancel(const Value: TNotifyEvent);
        procedure SetOnHide(const Value: TNotifyEvent);
        procedure SetOnShow(const Value: TNotifyEvent);
      protected
        /// <summary>
        ///   Returning a instance of wrapper native dialog. You should override this method for using custom native dialog.
        /// </summary>
        function CreateNativeDialog: T; virtual; abstract;
        /// <summary>
        ///   Way for perform additional initialization before showing dialog
        /// </summary>
        procedure DoInitDialog; virtual;
      public
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
        /// <summary>
        ///   Return Does current platform has implementation of native dialog or not
        /// </summary>
        function Supported: Boolean;
    //    procedure Show; virtual;
        procedure Show(AAutoCloseTimer : Integer = -1); virtual;
    //    procedure ShowWithAutoClose(AAutoCloseTimer : Integer);
        procedure Hide; virtual;
        function IsShown: Boolean;
        property NativeDialog: T read FNativeDialog;
      public
        property Cancellable: Boolean read FCancellable write SetCancellabel default DefaultCancellable;
        property Message: string read FMessage write SetMessage;
        property Title: string read FTitle write SetTitle;
        property Theme: TfgDialogTheme read FTheme write SetTheme default DefaultTheme;
        property ThemeID: Integer read FThemeID write SetThemeID default DefaultThemeID;
        property OnCancel: TNotifyEvent read FOnCancel write SetOnCancel;
        property OnShow: TNotifyEvent read FOnShow write SetOnShow;
        property OnHide: TNotifyEvent read FOnHide write SetOnHide;
      end;
    
      { TfgActivityDialog }
    
      TfgCustomActivityDialog = class(TfgCustomDialog<TfgNativeActivityDialog>)
      protected
        function CreateNativeDialog: TfgNativeActivityDialog; override;
      end;
    
      /// <summary>
      ///   Native Modal dialog with activity indicator, title and message
      /// </summary>
      [ComponentPlatformsAttribute(fgMobilePlatforms)]
      TfgActivityDialog = class(TfgCustomActivityDialog)
      published
        property Cancellable;
        property Message;
        property Title;
        property Theme;
        property ThemeID;
        property OnCancel;
        property OnShow;
        property OnHide;
      end;
    
      { TfgProgressDialog }
    
      TfgCustomProgressDialog = class(TfgCustomDialog<TfgNativeProgressDialog>)
      public const
        DefaultKind = TfgProgressDialogKind.Determinated;
        DefaultMax = 100;
      private
        FKind: TfgProgressDialogKind;
        FProgress: Single;
        FMax: Single;
        procedure SetKind(const Value: TfgProgressDialogKind);
        procedure SetMax(const Value: Single);
        procedure SetProgress(const Value: Single);
      protected
        { inherited }
        function CreateNativeDialog: TfgNativeProgressDialog; override;
        procedure DoInitDialog; override;
      public
        constructor Create(AOwner: TComponent); override;
        procedure ResetProgress;
      public
        property Kind: TfgProgressDialogKind read FKind write SetKind default DefaultKind;
        property Max: Single read FMax write SetMax;
        /// <summary>
        ///    Current progress value of dialog in range [0..100]. When dialog is displayed, progress will set with animation
        /// </summary>
        property Progress: Single read FProgress write SetProgress;
      end;
    
      /// <summary>
      ///   <para>
      ///     Native Modal dialog with progress bar, title and message
      ///   </para>
      ///   <note type="note">
      ///     <list type="table">
      ///       <item>
      ///         <term>iOS</term>
      ///         <description>Doesn't support <see cref="TfgProgressDialog.Kind">Kind</see> property and
      ///         <see cref="TfgProgressDialog.Kind">OnCancel</see></description>
      ///       </item>
      ///       <item>
      ///         <term>Android</term>
      ///         <description>All property is supported</description>
      ///       </item>
      ///     </list>
      ///   </note>
      /// </summary>
      [ComponentPlatformsAttribute(fgMobilePlatforms)]
      TfgProgressDialog = class(TfgCustomProgressDialog)
      published
        property Cancellable;
        property Kind;
        property Message;
        property Max;
        property Progress;
        property Title;
        property Theme;
        property ThemeID;
        property OnCancel;
        property OnShow;
        property OnHide;
      end;
    
    implementation
    
    uses
      System.Math, System.SysUtils, {FMX.Types,} FMX.Platform, FGX.Helpers, FGX.Asserts
    {$IFDEF IOS}
       , FGX.ProgressDialog.iOS
    {$ENDIF}
    {$IFDEF ANDROID}
       , FGX.ProgressDialog.Android
    {$ENDIF}
    ;
    
    { TfgCustomProgressDialog }
    
    constructor TfgCustomDialog<T>.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      FTheme := DefaultTheme;
      FThemeID := DefaultThemeID;
      FCancellable := DefaultCancellable;
      FNativeDialog := CreateNativeDialog;
    end;
    
    destructor TfgCustomDialog<T>.Destroy;
    begin
      if Assigned(FAutoCloseTimer) then
      begin
        FAutoCloseTimer.Enabled:=False;
        FAutoCloseTimer.OnTimer:=Nil;
        FAutoCloseTimer.Free;
      end;
    
      FreeAndNil(FNativeDialog);
      inherited Destroy;
    end;
    
    procedure TfgCustomDialog<T>.DoInitDialog;
    begin
      TfgAssert.IsNotNil(FNativeDialog);
    
      FNativeDialog.Cancellable := Cancellable;
      FNativeDialog.Message := Message;
      FNativeDialog.Title := Title;
      FNativeDialog.Theme := Theme;
      FNativeDialog.ThemeID := ThemeID;
      FNativeDialog.OnCancel := OnCancel;
      FNativeDialog.OnShow := OnShow;
      FNativeDialog.OnHide := OnHide;
    end;
    
    procedure TfgCustomDialog<T>.Hide;
    begin
      if Supported then
        FNativeDialog.Hide;
    end;
    
    function TfgCustomDialog<T>.IsShown: Boolean;
    begin
      if Supported then
        Result := NativeDialog.IsShown
      else
        Result := False;
    end;
    
    procedure TfgCustomDialog<T>.SetCancellabel(const Value: Boolean);
    begin
      if Cancellable <> Value then
      begin
        FCancellable := Value;
        if Supported then
          FNativeDialog.Cancellable := Cancellable;
      end;
    end;
    
    procedure TfgCustomDialog<T>.SetMessage(const Value: string);
    begin
      if Message <> Value then
      begin
        FMessage := Value;
        if Supported then
          FNativeDialog.Message := Message;
      end;
    end;
    
    procedure TfgCustomDialog<T>.SetOnCancel(const Value: TNotifyEvent);
    begin
      FOnCancel := Value;
      if Supported then
        FNativeDialog.OnCancel := FOnCancel;
    end;
    
    procedure TfgCustomDialog<T>.SetOnHide(const Value: TNotifyEvent);
    begin
      FOnHide := Value;
      if Supported then
        FNativeDialog.OnHide := FOnHide;
    end;
    
    procedure TfgCustomDialog<T>.SetOnShow(const Value: TNotifyEvent);
    begin
      FOnShow := Value;
      if Supported then
        FNativeDialog.OnShow := FOnShow;
    end;
    
    procedure TfgCustomDialog<T>.SetTheme(const Value: TfgDialogTheme);
    begin
      if Theme <> Value then
      begin
        FTheme := Value;
        if Supported then
          FNativeDialog.Theme := Theme;
      end;
    end;
    
    procedure TfgCustomDialog<T>.SetThemeID(const Value: Integer);
    begin
      if ThemeID <> Value then
      begin
        FThemeID := Value;
        if Supported then
          FNativeDialog.ThemeID := ThemeID;
      end;
    end;
    
    procedure TfgCustomDialog<T>.SetTitle(const Value: string);
    begin
      if Title <> Value then
      begin
        FTitle := Value;
        if Supported then
          FNativeDialog.Title := Title;
      end;
    end;
    
    procedure TfgCustomDialog<T>.Show(AAutoCloseTimer : Integer = -1);
    begin
      if Supported then
      begin
        DoInitDialog;
    
        if AAutoCloseTimer <> -1 then
        begin
          FAutoCloseTimer:=TTimer.Create(Self);
          FAutoCloseTimer.Interval:=AAutoCloseTimer;
          FAutoCloseTimer.OnTimer:=OnAutoCloseTimerTimer;
          FAutoCloseTimer.Enabled:=True;
        end;
    
        FNativeDialog.Show;
      end;
    end;
    {
    procedure TfgCustomDialog<T>.ShowWithAutoClose(AAutoCloseTimer : Integer);
    begin
      if Supported then
      begin
        DoInitDialog;
        FAutoCloseTimer:=TTimer.Create(Self);
        FAutoCloseTimer.Interval:=AAutoCloseTimer;
        FAutoCloseTimer.OnTimer:=OnAutoCloseTimerTimer;
        FAutoCloseTimer.Enabled:=True;
        FNativeDialog.Show;
      end;
    end;
    }
    procedure TfgCustomDialog<T>.OnAutoCloseTimerTimer(Sender: TObject);
    begin
      FAutoCloseTimer.Enabled:=False;
      Hide;
    end;
    
    
    function TfgCustomDialog<T>.Supported: Boolean;
    begin
      Result := FNativeDialog <> nil;
    end;
    
    { TfgCustomActivityDialog }
    
    function TfgCustomActivityDialog.CreateNativeDialog: TfgNativeActivityDialog;
    var
      ProgressService: IFGXProgressDialogService;
    begin
      if TPlatformServices.Current.SupportsPlatformService(IFGXProgressDialogService, ProgressService) then
        Result := ProgressService.CreateNativeActivityDialog(Self)
      else
        Result := nil;
    end;
    
    { TfgCustomProgressDialog }
    
    constructor TfgCustomProgressDialog.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      FKind := DefaultKind;
      FMax := DefaultMax;
    end;
    
    function TfgCustomProgressDialog.CreateNativeDialog: TfgNativeProgressDialog;
    var
      ProgressService: IFGXProgressDialogService;
    begin
      if TPlatformServices.Current.SupportsPlatformService(IFGXProgressDialogService, ProgressService) then
        Result := ProgressService.CreateNativeProgressDialog(Self)
      else
        Result := nil;
    end;
    
    procedure TfgCustomProgressDialog.DoInitDialog;
    begin
      inherited DoInitDialog;
      FNativeDialog.Kind := Kind;
      FNativeDialog.Progress := Progress;
      FNativeDialog.Max := Max;
    end;
    
    procedure TfgCustomProgressDialog.SetKind(const Value: TfgProgressDialogKind);
    begin
      if Kind <> Value then
      begin
        FKind := Value;
        if Supported then
          NativeDialog.Kind := Kind;
      end;
    end;
    
    procedure TfgCustomProgressDialog.SetMax(const Value: Single);
    begin
      TfgAssert.StrickMoreThan(Value, 0, 'Max Value cannot be less than 0');
    
      if not SameValue(Max, Value, Single.Epsilon) then
      begin
        FMax := Value;
        if Supported then
          NativeDialog.Max := Max;
        Progress := EnsureRange(Progress, 0, Max);
      end;
    end;
    
    procedure TfgCustomProgressDialog.SetProgress(const Value: Single);
    begin
      TfgAssert.InRange(Value, 0, Max, 'Progress value must be in range [0..Max]');
    
      if not SameValue(Progress, Value, Single.Epsilon) then
      begin
        FProgress := EnsureRange(Value, 0, Max);
        if Supported then
          NativeDialog.Progress := Progress;
      end;
    end;
    
    procedure TfgCustomProgressDialog.ResetProgress;
    begin
      FProgress := 0;
      if Supported then
        NativeDialog.ResetProgress;
    end;
    
    initialization
      RegisterFmxClasses([TfgCustomActivityDialog, TfgActivityDialog, TfgCustomProgressDialog, TfgProgressDialog]);
    
    {$IF Defined(ANDROID) OR Defined(IOS)}
      RegisterService;
    {$ENDIF}
    finalization
    {$IF Defined(ANDROID) OR Defined(IOS)}
      UnregisterService;
    {$ENDIF}
    end.

     

     

  13. Тогда в  вашем случае проще доработать сам компонент fgActivityDialog. Я добавил метод  fgActivityDialog.ShowWithAutoClose(3000) :

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      fgActivityDialog.Message := 'Teste';
      fgActivityDialog.ShowWithAutoClose(3000);
    end;

    Вот измененный исходный код unit FGX.ProgressDialog :

    Скрытый текст

     

    
    {*********************************************************************
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * Autor: Brovin Y.D.
     * E-mail: y.brovin@gmail.com
     *
     ********************************************************************}
    
    unit FGX.ProgressDialog;
    
    interface
    
    uses
      System.Classes, FGX.ProgressDialog.Types, FGX.Consts, FMX.Types;
    
    type
    
      /// <summary>
      ///   Generic Abstract base class provide base functionality for creation and using progress/activity dialog.
      ///   Each dialog has Message and Title and holds instance of wrapper native dialog.
      /// </summary>
      TfgCustomDialog<T: TfgNativeDialog> = class abstract(TComponent)
      public const
        DefaultCancellable = False;
        DefaultTheme = TfgDialogTheme.Auto;
        DefaultThemeID = TfgNativeDialog.UndefinedThemeID;
      private
        FNativeDialog: T;
        FTitle: string;
        FMessage: string;
        FCancellable: Boolean;
        FTheme: TfgDialogTheme;
        FThemeID: Integer;
        FOnShow: TNotifyEvent;
        FOnHide: TNotifyEvent;
        FOnCancel: TNotifyEvent;
        FAutoCloseTimer : TTimer;
        procedure OnAutoCloseTimerTimer(Sender: TObject);
        procedure SetCancellabel(const Value: Boolean);
        procedure SetMessage(const Value: string);
        procedure SetTitle(const Value: string);
        procedure SetTheme(const Value: TfgDialogTheme);
        procedure SetThemeID(const Value: Integer);
        procedure SetOnCancel(const Value: TNotifyEvent);
        procedure SetOnHide(const Value: TNotifyEvent);
        procedure SetOnShow(const Value: TNotifyEvent);
      protected
        /// <summary>
        ///   Returning a instance of wrapper native dialog. You should override this method for using custom native dialog.
        /// </summary>
        function CreateNativeDialog: T; virtual; abstract;
        /// <summary>
        ///   Way for perform additional initialization before showing dialog
        /// </summary>
        procedure DoInitDialog; virtual;
      public
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
        /// <summary>
        ///   Return Does current platform has implementation of native dialog or not
        /// </summary>
        function Supported: Boolean;
        procedure Show; virtual;
        procedure ShowWithAutoClose(AAutoCloseTimer : Integer);
        procedure Hide; virtual;
        function IsShown: Boolean;
        property NativeDialog: T read FNativeDialog;
      public
        property Cancellable: Boolean read FCancellable write SetCancellabel default DefaultCancellable;
        property Message: string read FMessage write SetMessage;
        property Title: string read FTitle write SetTitle;
        property Theme: TfgDialogTheme read FTheme write SetTheme default DefaultTheme;
        property ThemeID: Integer read FThemeID write SetThemeID default DefaultThemeID;
        property OnCancel: TNotifyEvent read FOnCancel write SetOnCancel;
        property OnShow: TNotifyEvent read FOnShow write SetOnShow;
        property OnHide: TNotifyEvent read FOnHide write SetOnHide;
      end;
    
      { TfgActivityDialog }
    
      TfgCustomActivityDialog = class(TfgCustomDialog<TfgNativeActivityDialog>)
      protected
        function CreateNativeDialog: TfgNativeActivityDialog; override;
      end;
    
      /// <summary>
      ///   Native Modal dialog with activity indicator, title and message
      /// </summary>
      [ComponentPlatformsAttribute(fgMobilePlatforms)]
      TfgActivityDialog = class(TfgCustomActivityDialog)
      published
        property Cancellable;
        property Message;
        property Title;
        property Theme;
        property ThemeID;
        property OnCancel;
        property OnShow;
        property OnHide;
      end;
    
      { TfgProgressDialog }
    
      TfgCustomProgressDialog = class(TfgCustomDialog<TfgNativeProgressDialog>)
      public const
        DefaultKind = TfgProgressDialogKind.Determinated;
        DefaultMax = 100;
      private
        FKind: TfgProgressDialogKind;
        FProgress: Single;
        FMax: Single;
        procedure SetKind(const Value: TfgProgressDialogKind);
        procedure SetMax(const Value: Single);
        procedure SetProgress(const Value: Single);
      protected
        { inherited }
        function CreateNativeDialog: TfgNativeProgressDialog; override;
        procedure DoInitDialog; override;
      public
        constructor Create(AOwner: TComponent); override;
        procedure ResetProgress;
      public
        property Kind: TfgProgressDialogKind read FKind write SetKind default DefaultKind;
        property Max: Single read FMax write SetMax;
        /// <summary>
        ///    Current progress value of dialog in range [0..100]. When dialog is displayed, progress will set with animation
        /// </summary>
        property Progress: Single read FProgress write SetProgress;
      end;
    
      /// <summary>
      ///   <para>
      ///     Native Modal dialog with progress bar, title and message
      ///   </para>
      ///   <note type="note">
      ///     <list type="table">
      ///       <item>
      ///         <term>iOS</term>
      ///         <description>Doesn't support <see cref="TfgProgressDialog.Kind">Kind</see> property and
      ///         <see cref="TfgProgressDialog.Kind">OnCancel</see></description>
      ///       </item>
      ///       <item>
      ///         <term>Android</term>
      ///         <description>All property is supported</description>
      ///       </item>
      ///     </list>
      ///   </note>
      /// </summary>
      [ComponentPlatformsAttribute(fgMobilePlatforms)]
      TfgProgressDialog = class(TfgCustomProgressDialog)
      published
        property Cancellable;
        property Kind;
        property Message;
        property Max;
        property Progress;
        property Title;
        property Theme;
        property ThemeID;
        property OnCancel;
        property OnShow;
        property OnHide;
      end;
    
    implementation
    
    uses
      System.Math, System.SysUtils, {FMX.Types,} FMX.Platform, FGX.Helpers, FGX.Asserts
    {$IFDEF IOS}
       , FGX.ProgressDialog.iOS
    {$ENDIF}
    {$IFDEF ANDROID}
       , FGX.ProgressDialog.Android
    {$ENDIF}
    ;
    
    { TfgCustomProgressDialog }
    
    constructor TfgCustomDialog<T>.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      FTheme := DefaultTheme;
      FThemeID := DefaultThemeID;
      FCancellable := DefaultCancellable;
      FNativeDialog := CreateNativeDialog;
    end;
    
    destructor TfgCustomDialog<T>.Destroy;
    begin
      if Assigned(FAutoCloseTimer) then
      begin
        FAutoCloseTimer.Enabled:=False;
        FAutoCloseTimer.OnTimer:=Nil;
        FAutoCloseTimer.Free;
      end;
    
      FreeAndNil(FNativeDialog);
      inherited Destroy;
    end;
    
    procedure TfgCustomDialog<T>.DoInitDialog;
    begin
      TfgAssert.IsNotNil(FNativeDialog);
    
      FNativeDialog.Cancellable := Cancellable;
      FNativeDialog.Message := Message;
      FNativeDialog.Title := Title;
      FNativeDialog.Theme := Theme;
      FNativeDialog.ThemeID := ThemeID;
      FNativeDialog.OnCancel := OnCancel;
      FNativeDialog.OnShow := OnShow;
      FNativeDialog.OnHide := OnHide;
    end;
    
    procedure TfgCustomDialog<T>.Hide;
    begin
      if Supported then
        FNativeDialog.Hide;
    end;
    
    function TfgCustomDialog<T>.IsShown: Boolean;
    begin
      if Supported then
        Result := NativeDialog.IsShown
      else
        Result := False;
    end;
    
    procedure TfgCustomDialog<T>.SetCancellabel(const Value: Boolean);
    begin
      if Cancellable <> Value then
      begin
        FCancellable := Value;
        if Supported then
          FNativeDialog.Cancellable := Cancellable;
      end;
    end;
    
    procedure TfgCustomDialog<T>.SetMessage(const Value: string);
    begin
      if Message <> Value then
      begin
        FMessage := Value;
        if Supported then
          FNativeDialog.Message := Message;
      end;
    end;
    
    procedure TfgCustomDialog<T>.SetOnCancel(const Value: TNotifyEvent);
    begin
      FOnCancel := Value;
      if Supported then
        FNativeDialog.OnCancel := FOnCancel;
    end;
    
    procedure TfgCustomDialog<T>.SetOnHide(const Value: TNotifyEvent);
    begin
      FOnHide := Value;
      if Supported then
        FNativeDialog.OnHide := FOnHide;
    end;
    
    procedure TfgCustomDialog<T>.SetOnShow(const Value: TNotifyEvent);
    begin
      FOnShow := Value;
      if Supported then
        FNativeDialog.OnShow := FOnShow;
    end;
    
    procedure TfgCustomDialog<T>.SetTheme(const Value: TfgDialogTheme);
    begin
      if Theme <> Value then
      begin
        FTheme := Value;
        if Supported then
          FNativeDialog.Theme := Theme;
      end;
    end;
    
    procedure TfgCustomDialog<T>.SetThemeID(const Value: Integer);
    begin
      if ThemeID <> Value then
      begin
        FThemeID := Value;
        if Supported then
          FNativeDialog.ThemeID := ThemeID;
      end;
    end;
    
    procedure TfgCustomDialog<T>.SetTitle(const Value: string);
    begin
      if Title <> Value then
      begin
        FTitle := Value;
        if Supported then
          FNativeDialog.Title := Title;
      end;
    end;
    
    procedure TfgCustomDialog<T>.Show;
    begin
      if Supported then
      begin
        DoInitDialog;
        FNativeDialog.Show;
      end;
    end;
    
    procedure TfgCustomDialog<T>.ShowWithAutoClose(AAutoCloseTimer : Integer);
    begin
      if Supported then
      begin
        DoInitDialog;
        FAutoCloseTimer:=TTimer.Create(Self);
        FAutoCloseTimer.Interval:=AAutoCloseTimer;
        FAutoCloseTimer.OnTimer:=OnAutoCloseTimerTimer;
        FAutoCloseTimer.Enabled:=True;
        FNativeDialog.Show;
      end;
    end;
    
    procedure TfgCustomDialog<T>.OnAutoCloseTimerTimer(Sender: TObject);
    begin
      FAutoCloseTimer.Enabled:=False;
      Hide;
    end;
    
    
    function TfgCustomDialog<T>.Supported: Boolean;
    begin
      Result := FNativeDialog <> nil;
    end;
    
    { TfgCustomActivityDialog }
    
    function TfgCustomActivityDialog.CreateNativeDialog: TfgNativeActivityDialog;
    var
      ProgressService: IFGXProgressDialogService;
    begin
      if TPlatformServices.Current.SupportsPlatformService(IFGXProgressDialogService, ProgressService) then
        Result := ProgressService.CreateNativeActivityDialog(Self)
      else
        Result := nil;
    end;
    
    { TfgCustomProgressDialog }
    
    constructor TfgCustomProgressDialog.Create(AOwner: TComponent);
    begin
      inherited Create(AOwner);
      FKind := DefaultKind;
      FMax := DefaultMax;
    end;
    
    function TfgCustomProgressDialog.CreateNativeDialog: TfgNativeProgressDialog;
    var
      ProgressService: IFGXProgressDialogService;
    begin
      if TPlatformServices.Current.SupportsPlatformService(IFGXProgressDialogService, ProgressService) then
        Result := ProgressService.CreateNativeProgressDialog(Self)
      else
        Result := nil;
    end;
    
    procedure TfgCustomProgressDialog.DoInitDialog;
    begin
      inherited DoInitDialog;
      FNativeDialog.Kind := Kind;
      FNativeDialog.Progress := Progress;
      FNativeDialog.Max := Max;
    end;
    
    procedure TfgCustomProgressDialog.SetKind(const Value: TfgProgressDialogKind);
    begin
      if Kind <> Value then
      begin
        FKind := Value;
        if Supported then
          NativeDialog.Kind := Kind;
      end;
    end;
    
    procedure TfgCustomProgressDialog.SetMax(const Value: Single);
    begin
      TfgAssert.StrickMoreThan(Value, 0, 'Max Value cannot be less than 0');
    
      if not SameValue(Max, Value, Single.Epsilon) then
      begin
        FMax := Value;
        if Supported then
          NativeDialog.Max := Max;
        Progress := EnsureRange(Progress, 0, Max);
      end;
    end;
    
    procedure TfgCustomProgressDialog.SetProgress(const Value: Single);
    begin
      TfgAssert.InRange(Value, 0, Max, 'Progress value must be in range [0..Max]');
    
      if not SameValue(Progress, Value, Single.Epsilon) then
      begin
        FProgress := EnsureRange(Value, 0, Max);
        if Supported then
          NativeDialog.Progress := Progress;
      end;
    end;
    
    procedure TfgCustomProgressDialog.ResetProgress;
    begin
      FProgress := 0;
      if Supported then
        NativeDialog.ResetProgress;
    end;
    
    initialization
      RegisterFmxClasses([TfgCustomActivityDialog, TfgActivityDialog, TfgCustomProgressDialog, TfgProgressDialog]);
    
    {$IF Defined(ANDROID) OR Defined(IOS)}
      RegisterService;
    {$ENDIF}
    finalization
    {$IF Defined(ANDROID) OR Defined(IOS)}
      UnregisterService;
    {$ENDIF}
    end.

     

    Добавлен метод procedure ShowWithAutoClose(AAutoCloseTimer : Integer); и TTimer

    Прошу прощение у Ярослава, за топорное вмешательство в его код :-)

  14. Вот моя процедура переключения, все легко и просто:

    procedure TFormMain.SetActiveTab(ATabControl : TTabControl; ATabItem : TTabItem; ATransition : Boolean);
    Var ATabTransitionDirection : TTabTransitionDirection;
        ATabTransition : TTabTransition;
    begin
      if ATabControl.TabIndex = ATabItem.Index Then
        Exit;
      if ATransition then
        ATabTransition:=TTabTransition.Slide
      Else
        ATabTransition:=TTabTransition.None;
      if ATabControl.TabIndex < ATabItem.Index Then
        ATabTransitionDirection:=TTabTransitionDirection.Normal
      Else
        ATabTransitionDirection:=TTabTransitionDirection.Reversed;
      ATabControl.SetActiveTabWithTransition(ATabItem,ATabTransition,ATabTransitionDirection);
    end;
    

     

  15. 27 минут назад, x11 сказал:

    Так в первом сообщении.

    Может Вы не поняли? Переключение работает. Но нет анимации.

    В вашем сообщении нет кода переключения с анимацией, вы используете глючную прокладку ActionList, в надежде что чужой код (заброшенный кстати несколько лет назад) выполнит за вас некую работу. Я же вам ответил вполне определенно и с примерами нужных методов для достижения результата.

  16. В своем коде вы останавливаете работу приложения, не давая отрисовать Диалог.

    Попробуйте вот так:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      fgActivityDialog1.Message := 'Teste';
      fgActivityDialog1.Show;
      Timer.Interval:=3000;
      Timer.Enabled:=True;
    end;
    
    procedure TForm1.TimerTimer(Sender: TObject);
    begin
      Timer.Enabled:=False;
      fgActivityDialog1.Hide;
    end;

     

  17. Для этого не нужно использовать муторную прокладку ActionList, у TabControl есть свои замечательные методы:

      TabControl.Next(TTabTransition.Slide, TTabTransitionDirection.Normal); // Следующий Таб
      TabControl.Previous(TTabTransition.Slide, TTabTransitionDirection.Reversed); // Предыдущий Таб
      TabControl.GotoVisibleTab(ATabIndex, TTabTransition.Slide, TTabTransitionDirection.Normal); // Переключение на произвольный Таб

    С помощью TTabTransition.Slide указываете тип переключения (анимация) и  с помощью TTabTransitionDirection.Normal  указываете направление анимации. Работает на всех платформах.

  18. Если вы понаблюдаете дальше, то обнаружите что выполняется гораздо больше раз. Попробуйте к примеру повернуть устройство горизонтально, потом опять вертикально - еще пара выполнений. 

    OnUpdateObjects и OnUpdatingObjects выполняется постоянно - при изменении размеров,  скрытии и повторном показе, переключении приложений и т.д. В справке так и написано "Occurs immediately after the list view component is updated."

    Так что надо придерживаться двух правил :

    1. При добавлении/изменении TListViewItem отключайте обработку вышеуказанных процедур. 

    Setting.Flags.ListViewUpdating:=True; // Глобальная переменная или ListView.OnUpdatingObjects:=nil;
    AItem:=ListView.Items.Add;
    AItem.Data['Type']:='MySuperPuperItem';
    AItem.Data['Name']:=AName;
    AItem.Data['Value']:=AValue;
    Setting.Flags.ListViewUpdating:=False; // Глобальная переменная или ListView.OnUpdatingObjects:=ListViewUpdatingObjects;
    AItem.Adapter.ResetView(AItem); // принудительно вызываем ListViewUpdatingObjects 
    
    ...
    
    procedure TFormMain.ListViewUpdatingObjects(const Sender: TObject;
      const AItem: TListViewItem; var AHandled: Boolean);
    begin
      if Setting.Flags.ListViewUpdating then // Если используете глобальную переменную
        Exit;
    ...

    2. Внутри OnUpdateObjects и OnUpdatingObjects при добавлении TListItemText и прочих элементов, проверяйте их существование, возможно они уже были добавлены вашим кодом ранее.

×
×
  • Создать...