![](https://fire-monkey.ru/uploads/set_resources_12/84c1e40ea0e759e3f1505eb1788ddf3c_pattern.png)
Евгений Корепов
-
Постов
738 -
Зарегистрирован
-
Посещение
-
Победитель дней
100
Сообщения, опубликованные Евгений Корепов
-
-
26 минут назад, Антон Емельянов сказал:
да я его видел. он не работает
Что именно означает "не работает"? Напишите Идентификатор отправителя который указываете в демо-приложении.
-
46 минут назад, Антон Емельянов сказал:
Эм.. ничего непонятно
.. тут куски кода..
1. что такое "MetodMinerProRegisterFCM" в GetHTTP(MetodMinerProRegisterFCM)
2. где процедура PushClientReceiveNotificationHandler
3. не определяется HDevicePushParams в HDevicePushParams.DeviceID:=FPushClient.DeviceID;
Пришлите рабочий архив с проектом - простая форма и кнопка получить токен... будем сильно благодарныВообще то я приложил к сообщению архив. Если бы удосужились его скачать и открыть, то обнаружили кроме готовой библиотеки для работы с пушами еще и демо-проект.
-
Выполняйте oItem.Adapter.ResetView(oItem) в OnScrollViewChange по мере необходимости. Вначале для всех видимых + еще пару экранов вниз. При прокрутке повторяем.
-
-
Скачал ваше тестовое приложение.
Во первых в манифесте добавьте разрешение на получение
<%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 для начала.
-
15 минут назад, Антон Емельянов сказал:
то есть ключ сервера вообще ненужно пихать в apikey ?
Это вообще разные вещи, туда ничего пихать не нужно вообще. Но если очень хочется, то это ключь ПРИЛОЖЕНИЯ из GooglePlayConsole
-
-
Что то тут вы сами себя запутали. Все просто (через жопу конечно с появлением 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 может ничего не работать. Токены начинаю выдаваться сразу.
-
В 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.
-
1 час назад, kami сказал:
Есть дикое ощущение, что могли поломать синхронизацию через TMonitor.Wait.
В Телеграме обсуждали подобный глюк, по stacktrace было похоже на это.
После переделки с TThread.Synchronize на TThreadedQueue приложение отработало 12 часов без проблем. Ни ошибок, ни утечек. Так что думаю проблема не в моем коде, а именно в TMonitor.
Правда на тестовом приложении, с 7 потоками и синхронизацией TThread.Synchronize воспроизвести проблему не удалось, так что черт его знает на каком этапе начинает глючить.
-
В 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();
вообще не доходит слава богу.
-
Долго мучался отсутствием штатного средства красивого вывода 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 строки.
-
Очень странно. Все настройки аналогичны вашим. Но не работает даблклик
-
4 часа назад, Виталий Иванов сказал:
Хм, у меня такой фокус не срабатывает :-( Двойной клик по заголовкам Табов с юнитами? Или я не правильно понял?
-
-
Подумал и сделал более изящно - изменил метод 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.
-
Тогда в вашем случае проще доработать сам компонент 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
Прошу прощение у Ярослава, за топорное вмешательство в его код :-)
-
В Токио изменена логика работы приложения на Андроид - пользовательский интерфейс выполняется в основном потоке приложения, возможно проблема из за этого. Вот похожая тема
-
Вот моя процедура переключения, все легко и просто:
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;
-
27 минут назад, x11 сказал:
Так в первом сообщении.
Может Вы не поняли? Переключение работает. Но нет анимации.
В вашем сообщении нет кода переключения с анимацией, вы используете глючную прокладку ActionList, в надежде что чужой код (заброшенный кстати несколько лет назад) выполнит за вас некую работу. Я же вам ответил вполне определенно и с примерами нужных методов для достижения результата.
-
31 минуту назад, x11 сказал:
Slide включен.
Пробовал и direction менять.
Покажите код
-
В своем коде вы останавливаете работу приложения, не давая отрисовать Диалог.
Попробуйте вот так:
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;
-
Для этого не нужно использовать муторную прокладку 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 указываете направление анимации. Работает на всех платформах.
-
Если вы понаблюдаете дальше, то обнаружите что выполняется гораздо больше раз. Попробуйте к примеру повернуть устройство горизонтально, потом опять вертикально - еще пара выполнений.
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 и прочих элементов, проверяйте их существование, возможно они уже были добавлены вашим кодом ранее.
Неадекватно отображается окно Options
в Вопросы
Опубликовано
Версия Windows? Тип монитора (обычный или UHD)? Правой кнопкой на ярлыке Delphi, вкладка совместимость, поиграйте параметрами совместимости (Переопределите режим совместимости высокого разрешения).