-
Постов
55 -
Зарегистрирован
-
Посещение
-
Победитель дней
17
Сообщения, опубликованные Fedor K
-
-
Из приведенного выше кода ничего вручную удалять не нужно, кроме самого TListBoxItem, как и выполняется в примере выше (listbox1.Items.Delete(indexclick) или Form1.listbox1.Items.Delete(0)) . Все создаваемые дополнительные контролы (TGridPanelLayout, TRectangle, TText) создаются здесь с AOwner = TListBoxItem + задается Parent, который мы и удаляем, а при удалении родительского все дочерние удаляются вместе с ним. Можете убедиться в этом проверив утечку памяти:
ReportMemoryLeaksOnShutdown := True;
Sashar333 не используйте никогда .Name в качестве хранилища или идентификатора, это плохая практика. Для этих целей отлично подходят тэги (TagString или TagFloat), которые имеют все TFmxObject.
-
elxanders скиньте пожалуйста пример своего проекта, я посмотрю в чем дело.
-
6 часов назад, elxanders сказал:
Речь не о TListBox (с ним как раз проблем нет) а о TComboBox - который выпадающий список.
Опять столкнулся с этой же проблемой - заполняю список называниями папок, он вместо Black вводит Чёрный, т.к. на соседней форме есть такая Label с Autotranslate.
Пожалуйста, внимательно посмотрите пример выше: cbbFiles: TComboBox;
TComboBox содержит внутри себя TComboListBox с элементами списка, которые у вас автопереводятся. При помощи предоставленного выше примера автоперевод отключается. Если у Вас множество TComboBox, которым нужно запретить перевод, то можно воспользоваться таким способом:
//Создаем helper для TComboBox type TComboBoxHelper = class helper for TComboBox public procedure SetAutoTranslate(AEnabled: Boolean = false); end; ... implementation ... { TComboBoxHelper } //Согласно примеру выше procedure TComboBoxHelper.SetAutoTranslate(AEnabled: Boolean); var i, count : integer; begin count := Self.Count - 1; for i := 0 to count do Self.ListBox.ListItems[i].AutoTranslate := AEnabled; end; ... //Пример использования helper в Вашем коде <Ваш TComboBox 1>.SetAutoTranslate; ... <Ваш TComboBox N>.SetAutoTranslate;
-
8 минут назад, Rusland сказал:
@Fedor K в вашем примере принимается любой SSL сертификат (даже просроченные)?
Да, любой сертификат.
-
В 16.12.2014 в 18:27, SVTX сказал:
В юните FMX.WebBrowser.Android.pas есть метод TWebBrowserListener.onReceivedSslError.
По документации Андроид в нем можно обработать данную ошибку. Но команда proceed; не дает никакого результата((
Причина такого поведения довольно простая - java библиотеки FMX часто передают в Delphi только уведомление о событии, без непосредственного влияния на процесс. Открываем библиотеку fmx.jar и смотрим код класса WebClient (package com.embarcadero.firemonkey.webbrowser;):
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { super.onReceivedSslError(view, handler, error);// обработка ошибки происходит здесь по дефолту if (this.mListener != null) { this.mListener.onReceivedSslError(view, handler, error);//передача в Delphi лишь уведомления, что событие произошло } }
Одно из решений*:
1. Заменяем** код на:
public void onReceivedSslError(WebView paramWebView, SslErrorHandler paramSslErrorHandler, SslError paramSslError) { if (this.mListener != null) { this.mListener.onReceivedSslError(paramWebView, paramSslErrorHandler, paramSslError);//Delphi обработчик } else { super.onReceivedSslError(paramWebView, paramSslErrorHandler, paramSslError);//обработчик по умолчанию } }
После манипуляций получаем свою версию библиотеки, мой пример здесь (Delphi Berlin).
2. Подключаем библиотеку к проекту (скриншот ниже).
3. Копируем unit FMX.WebBrowser.Android в папку своего проекта и меняем следующие строки:
procedure TAndroidWebBrowserService.TWebBrowserListener.onReceivedSslError( P1: JWebView; P2: JSslErrorHandler; P3: JSslError); begin P2.proceed;//добавляем разрешение для истекших сертификатов FWBService.FailLoadingWithError;//стандартный обработчик OnDidFailLoadWithError end;
*Если вариант изменения кода java библиотек совсем не подходит, можно реализовать все средствами Delphi. Для этого создаем свою реализация класса WebViewClient (или WebClient) и задаем его для JWebBrowser:
//все тот же unit FMX.WebBrowser.Android; procedure TAndroidWebBrowserService.InitUIThread; var lClient : TWebBrowserCLientFix;//наш класс begin FJWebBrowser := TJWebBrowser.JavaClass.init(TAndroidHelper.Activity); FJWebBrowser.getSettings.setJavaScriptEnabled(True); lClient := TWebBrowserCLientFix.Create(Self); FJWebBrowser.setWebViewClient(lClient);//меняем на наш класс FListener := TWebBrowserListener.Create(Self); lClient.SetWebViewListener(FListener); //комментируем //FJWebBrowser.SetWebViewListener(FListener);
**Замена кода происходит по тому же сценарию, как и создание своих собственных классов на java. Если кому потребуется помощь - пишите, я помогу ответами и примером.
-
2 часа назад, ENERGY сказал:
Я так понял сообщения можно удалить только все (CancelAll) - т.е. юзер тапнул на одно сообщение, прочитал и затем программа очистила все остальные.. Вот в чем проблема. Странно почему нет нормального механизма..
Для того, чтобы при нажатии на уведомление оно автоматически исчезало из StatusBar при его создании необходимо добавлять флаг:
localBuilder.setAutoCancel(true);
В библиотеке fmx.jar этот код отсутствует (package com.embarcadero.rtl.notifications, public class NotificationPublisher). У меня есть перекомпиленная библиотека для Seattle. Изменение библиотек выполняется таким же образом, как и создание своих всем известным методов через .bat файл.
-
ENERGY Для получения всех активных уведомлений в Android существует метод:
getActiveNotifications added in API level 23 StatusBarNotification[] getActiveNotifications ()
FMX (Berlin и ниже точно, Tokyo не смотрел) не предоставляет доступ к этому методу, в исходниках (Androidapi.JNI.App.pas) он закомментирован. Возможно при использовании своего wrapper для класса JNotificationManager или отсюда можно получить доступ к требуемому функционалу.
-
Цитата
Говорит, что su not found.
Да, команда работает только на телефонам с root правами.
Попробуйте эти команды (выполнить нужно обе по порядку):
#adb root
#adb remount
-
Golovanyuk, такое случается, когда кабель не достаточно хорошего качества/расшатан разъем/кастомная прошивка + недостаточно прав на телефоне. Если приложение первый раз запускается - то проблема не в настройках IDE.
Попробуйте сделать следующее:
- Подключите телефон по USB
- Перейдите в папку platform-tools, лежит в Android SDK. У меня например такой путь: F:\18.0\PlatformSDKs\android-sdk-windows\platform-tools.
- Откройте окно команд (зажимаете "Shift" + правая кнопка мыши -> "Открыть окно команд").
- Выполните "adb devices" - отобразиться список подключенных устройств.
- Выполните "adb shell su 0 setenforce 0" - на телефоне может появится окно запроса прав.
-
Ingalime этой настройкой нельзя управлять программно по политики безопасности системы. Из приложения программно можно лишь проверить эту галочку и предложить пользователю открыть эти настройки. Есть 2 решения:
- (самый простой способ) не отправлять уведомление с сервера. Т.к. у Вас устройства хранятся в таблице, то необходимо просто добавить туда новый столбец (например "PushEnabled") и изменить sql запрос, которым выбираете токены устройств с БД. PHP код в этом случае не затрагивается.
- (если править сервер невозможно или у вас нет доступа) запретить уведомления в BroadcastReceiver, который их обрабатывает и непосредственно создает уведомление в статус баре (приложение свернуто/закрыто) или передает обработку в код FMX (приложение открыто).
2-ой способ является не тривиальным, т.к. требуется изменить стандартную библиотеку FMX cloud-messaging.jar, либо написать свой собственный BroadcastReceiver и его использовать в проекте + придется использовать SharedPreferences, чтобы хранить флаг состояния уведомлений для BroadcastReceiver.
Я рекомендую воспользоваться первым способом. Опишите логику "включения/отключения" пушей, по каким правилам и где изменяется эта настройка, чтобы легче было Вам помочь.
-
Дело в том, что TComboBox лишь контейнер, вам нужно обращаться именно к списку элементов в ListBox. Чтобы запретить перевод можно поступить так:
var i, count : integer; begin count := cbbFiles.Count - 1; for i := 0 to count do cbbFiles.ListBox.ListItems[i].AutoTranslate := False; end;
-
У стандартного TListView уже все есть:
//устанавливаем режим редактирования у списка либо в редакторе свойств выставляем ListView1.EditMode := True; //... //Получаем список всех выбранных элементов ListView1.Items.CheckedIndexes(true); //обращаться к свойству текущего элемента так: ListView1.Items.SetChecked(const Index: Integer; const Value: Boolean); ListView1.Items.GetChecked(const Index: Integer): Boolean;
-
Для таких таблиц лучше ее рисовать на ListView. Пока не видел достойных гридов для Андроид.
Пример реализации:
Спойлер//Обрабатываем событие отрисовки procedure TBaseView.lvBaseUpdateObjects(const Sender: TObject; const AItem: TListViewItem); var item : TListViewItem; begin item := AItem; //предотвращаем повторную прорисовку if item.Tag = TAG_UPDATE then exit; item.Tag := TAG_UPDATE; case item.Purpose of //рисуем заголовок TListItemPurpose.Header : begin item.UpdateHeader; end; //рисуем строку TListItemPurpose.None : begin item.UpdateItem(BookCashier[item.Index - 1].Values); end; end; end;
//для моей задачи было достаточно задать размеры константами, т.к. экран был задан заранее. const RH = 25; CW = 66.5; TAG_UPDATE = 10; //UpdateHeader аналогичен этому procedure TListViewItemHelper.UpdateItem(const AValues: TArray<string>); var i, count : integer; begin count := Length(AValues) - 1; for i := 0 to count do begin CreateText(0 + i, 0, 1, 1, AValues[i]); CreateLine(0 + i, 0, 1, TLineType.ltV); end; end; function TListViewItemHelper.CreateLine(ACol, ARow, ARowCount: integer; ALineType: TLineType): TListItemObject; var lineItem : TListItemImage; begin lineItem := TListItemImage.Create(self); lineItem.PlaceOffset.X := CW - 1 + ACol * CW; lineItem.PlaceOffset.Y := 0 + ARow * RH; case ALineType of ltH: begin lineItem.Height := 1; lineItem.Width := CW * ARowCount; end; ltV: begin lineItem.Height := ARowCount * RH; lineItem.Width := 1; end; end; lineItem.Visible := true; //bitmap - просто черный фон, рисуем сетку) lineItem.Bitmap := self.Bitmap; lineItem.ScalingMode := TImageScalingMode.Stretch; lineItem.Opacity := 0.3; Result := lineItem; end; function TListViewItemHelper.CreateText(ACol, ARow, AColCount, ARowCount: integer; AText: string): TListItemObject; var textItem : TListItemText; begin textItem := TListItemText.Create(self); textItem.PlaceOffset.X := 0 + ACol * CW; textItem.PlaceOffset.Y := 0 + ARow * RH; textItem.Width := CW * AColCount - 1; textItem.Visible := true; textItem.Text := AText; textItem.Height := RH * ARowCount - 1; textItem.TextAlign := TTextAlign.Center; textItem.TextVertAlign := TTextAlign.Center; textItem.WordWrap := True; textItem.Trimming := TTextTrimming.Character; textItem.Opacity := 1; textItem.TextColor := TAlphaColorRec.Black; textItem.Font.Family := 'Arial'; textItem.Font.Size := 11; Result := textItem; end;
-
-
-
12 часов назад, Pax Beach сказал:
Вот с какой стати модуль будет доступен, если приложение и сервис — это разные проекты.
Да, Вы правы, у приложения и сервиса общий только Context, обмен инфой возможен только стандартными способами Android.
-
2 минуты назад, Pax Beach сказал:
Спасибо, полезные примеры.
А как реализовать функцию «поделиться». Например, из своего приложения хочу поделиться фотографией в вотцап?
1. TMS iCL
2. DPF- смотрите в сторону TDPFQLPreviewController
3. Ручками, что-то вроде такого (документация apple):
var controller : UIDocumentInteractionController; URL: NSURL; {$ENDIF} path : string; temp : Boolean; begin path := ExtractFilePath(ParamStr(0)) + '/Sample.pdf'; {$IFDEF IOS} URL := TNSUrl.Wrap(TNSUrl.OCClass.fileURLWithPath(StrToNSStr(path))); controller := TUIDocumentInteractionController.Wrap( TUIDocumentInteractionController.OCClass.interactionControllerWithURL(URL)); TNSUrl.Wrap(TNSUrl.OCClass.fileURLWithPath(StrToNSStr(path))); temp := controller.presentOpenInMenuFromRect( WindowHandleToPlatform(self.Handle).View.frame, WindowHandleToPlatform(self.Handle).View,true); {$ENDIF} end;
-
3 часа назад, Сергей Сергеев сказал:
LargeHeap не помогает, Lifecicle Restart ит после нажатия кнопки home..
Сервис - приделал к Lifecicle сервис как на видео , теперь все равно рестатрит основная форма - но в списке работающих приложений ( в настройках) - вижу его после нажатия домой ..
могу ли я в сервис положить свой DataModuel в котором есть sqlconnection на сервер, который собственно и держит сессию на нем, несколько TclientDataSet, MemTable и TDSPProviderConnection ,
и как это связывать с TListView, TEdit на форме, котороя получается "перерождается" постоянно..
1. Возможно я где-то пропустил в теме, но зачем держать соединение в сервисе ?
2. Связать можно как и обычно, из вашего приложения доступен DM сервиса, на котором может находится TMemData.
3.Опишите пожалуйста более подробнее задачи, которые перед Вами стоят, тогда ответы будут более продуктивны. Данная тема скорей всего архитектурный вопрос, а не вопрос потребления памяти.
-
Один из вариантов открытия одного приложения из другого - это использование URL schemes (Ярослав давал выше ссылку).
Из приложение А:
//отправка uses Macapi.Helpers, FMX.Helpers.iOS; //делаем намерение открыть URL (по сути тоже самое Intent в Android) SharedApplication.openURL(StrToNSUrl(Url));
Приложение Б (подробнее, хотя немного устарело):
//подписываемся на события if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, IInterface(aFMXApplicationEventService)) then aFMXApplicationEventService.SetApplicationEventHandler(HandleAppEvent); //обработчик function HandleAppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean; var lURL : string; begin case AAppEvent of TApplicationEvent.OpenURL : begin lURL := (AContext as TiOSOpenApplicationContext).URL; //реализуем логику end;
Как передать файлы я вижу несколько вариантов:
- использовать буфер обмена (класс UIPasteboard - думаю не сложно его использовать в FMX, я им пользовался только в Xamarin, на FMX возможно (нужно проверить) можно использовать FMX.Platform.IFMXClipboardService). Перед открытием URL в "А" - сохраняем картинку/файл в буфер обмена, в "Б" при открытии считываем.
- передавать в URL путь к файлу (это возможно только, если и "А" и "Б" являются приложением одной группы). пример с Object-C.
-
36 минут назад, Pax Beach сказал:
Что-то я совсем нить рассуждений потерял. О каком "том" событии идет речь? В компоненте TfgApplicationEvents нет такого события.
Вот задача: Из приложения "Папа" запустить приложение "Дочка", при этом сообщив "Помой посуду!". И чтобы приложение "Дочка" сообщила "Хорошо, папа" и открыло форму "Мойка посуды". ))) Как ее решить на разных платформах?
Для Android достаточно в приложении "Дочка" обработать стартовый Intent:
uses System.StartUpCopy, Androidapi.Helpers, Androidapi.JNI.GraphicsContentViewText; ... var Intent: JIntent; lStartIndex : Integer = -1; begin Application.Initialize; Intent := TAndroidHelper.Activity.getIntent; if (Intent <> nil) and (Intent.getExtras <> nil) and Intent.getExtras.containsKey(StringToJString('START_FORM')) then begin lStartIndex := Intent.getExtras.getInt(StringToJString('START_FORM')); end; //создание нужной формы в зависимости от lStartIndex
Для мобильных платформ я бы советовал использовать TFrame, вместо TForm, оперирую лишь одной главной формой. Много форм оставьте для VCL.
-
При реализации OAuth 2.0 при помощи TWebBrowser главное отследить Redirect. В случае успешной авторизации в URL будет содержаться необходимый токен. Посмотрите в сторону использования вот этих форм (находятся в ..\source\data\rest):
{$IFDEF MSWINDOWS} REST.Authenticator.OAuth.WebForm.Win {$ELSE} REST.Authenticator.OAuth.WebForm.FMX {$ENDIF}
У них есть событие:
property OnAfterRedirect: TOAuth2WebFormRedirectEvent read FOnAfterRedirect write FOnAfterRedirect; TOAuth2WebFormRedirectEvent = procedure(const AURL: string; var DoCloseWebView : boolean) of object;
Вот обработчик:
procedure TframeAutch.AfterRedirect(const AURL: string; var DoCloseWebView: boolean); var i:integer; Str: string; Params: TStringList; begin i := pos('#access_token=',AURL); if (i>0) then begin Str := AURL; Delete(Str,1,i); Params:=TStringList.Create; try Params.Delimiter:='&'; Params.DelimitedText := Str; token := Params.Values['access_token']; DoCloseWebView := True; finally Params.Free; end; end; end;
**Код выше из XE7, сейчас мб что-то изменилось. Использовал такой подход для авторизации в vk, facebook, google+.
***Если нужно, могу сделать демку, но это только на выходных.
-
В 08.09.2016 в 20:11, Kitty сказал:
Видела приложение, которое автоматом публиковало в фейсбук картинку и комментарий.
Выглядело так: человек идет в МакДональдс. Запускает приложение и приложение автоматом постит в фейсбук предопределенную внутри приложения картинку и комментарий типа "Ура я иду в МакДональдст!", при этом пользователь не предпринимает никаких доп. усилий.
Как такое можно реализовать?
Общая схема такая:
1. Регистрация своего приложения в API соцсетей (facebook, vk).
2. Реализуете в своем приложении авторизацию через OAuth 2.0:
- можно использовать легкий вариант через WebBrowser, т.о. образом сразу поддерживая Android/IOS.
- можно сделать красиво, используя "Intent" и "startActivityForResult".
- можно использовать SDK соцсетей, но это совсем другая история...
3. После регистрации сохраняем токен, при помощи которого мы можем через API автоматически постить сообщения. Учитываем здесь время действия токена, периодически его обновляя.
-
1. Перед подобными вызовами активностей с указанием пакета, всегда рекомендуется проверять наличие их в системе:
//получаем список пакетов, которые могут обработать ваше намерение tempList := TAndroidHelper.Activity.getPackageManager. queryIntentActivities(Intent); //стартуем только в случае наличия пакета if tempList.size > 0 then TAndroidHelper.Activity.startActivity(Intent);
2. При отправке сторонним приложениям файлов (изображения в частности) всегда рекомендуется создавать копию изображения:
а) с УНИКАЛЬНЫМ именем - необходимо для разрешения проблем с кешированием в других приложениях. Например Facebook кеширует по имени и при повторном вызове не обновляет;
б) сохранять нужно в CacheDir, т.к. другим приложениям может попросту не быть доступа к файлу вашего приложения (использование Uri обязательно).
3. Т.к. у подобных приложений шарингом занимаются отдельные активности, то не забудьте про флаги NewTask | ClearTask у намерения.
п.с. Не забудьте потом периодически удалять свой кеш.
-
Необходимо использовать
TJContext.JavaClass.NOTIFICATION_SERVICE
вместо
TJActivity.JavaClass.NOTIFICATION_SERVICE
Для получения менеджера лучше использовать контекст (данный код работает на версии 4.4 и 5+):
function GetNotificationService: JNotificationManager; var NotificationServiceNative: JObject; begin NotificationServiceNative := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.NOTIFICATION_SERVICE); Result := TJNotificationManager.Wrap((NotificationServiceNative as ILocalObject).GetObjectID); end;
Не могу поменять стиль TabControl (disable)
в BitmapStyleDesigner - дизайнер растровых стилей
Опубликовано
Как вариант в стиле вынести картинку с текстом в отдельный TLayout и добавить TFloatAnimation с триггером на IsSelected на свойство Opacity :