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

Лидеры

  1. krapotkin

    krapotkin

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


    • Баллы

      287

    • Постов

      2 179


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

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

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


    • Баллы

      182

    • Постов

      738


  3. OnePeople

    OnePeople

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


    • Баллы

      117

    • Постов

      322


  4. Tumaso

    Tumaso

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


    • Баллы

      102

    • Постов

      331


Популярный контент

Показан контент с высокой репутацией за 20.10.2018 во всех областях

  1. Привет Вчера была выпущена финальная версия RAD Studio 10.3 Rio, в которой много нововведений для Андройд. Но вот про статусбар снова "забыли". Хотя не совсем, добавили файлик styles-v21.xml, который превносит новую материальную тему на устройствах под управлением Android 5.0 и выше вместо устаревшей Holo. Но все равно свойство формы SystemStatusBar так и не реализовали. Поэтому при запуске статус бар будет окрашен в унылый серый цвет (см. скриншот). Для того, чтобы сделать статусбар прозрачным и поместить под него содержимое формы, то достаточно сделать несколько несложных шагов: 1. Убираем из деплоймента (Project -> Deployment) файл styles-v21.xml (можно просто снять галочку рядом с именем файла) 2. Добавить в деплоймент проекта новый файл styles-v21.xml (styles-v21.zip) и прописать ему путь res\values-v21\ 3. В результате получится следующий вид P.S. В новом файле по сравнению со стандартным добавилась строчка <item name="android:windowTranslucentStatus">true</item>, которая и отвечает за прозрачный статусбар P.P.S. Чтобы определять размер статус бара, все также можно воспользоваться решеним ZuBy - http://blog.rzaripov.kz/2016/12/android-ios.html P.P.P.S. Тестовый проектик - StatusBar.zip
    17 баллов
  2. Всем привет! После долгого творческого запоя я запилил альфу либы, которая позволяет юзать обычный, не-генномодифицированный ListView. Данные подаются в виде модели данных, описание раскладки итема лежит в JSON. Для работы пишется примитивный наследник класса-адаптера, который биндит данные модели на элементы из JSON. Я решил, что руками делать это дешевле чем через RTTI { TMyAdapter } procedure TMyAdapter.SetupDrawableContent(const ADrawable: TListItemDrawable; const AData: TMyData); begin if SameText( ADrawable.Name, 'text') then begin (ADrawable as TListItemText).Text := AData.Text; end else if SameText( ADrawable.Name, 'detail') then begin (ADrawable as TListItemText).Text := AData.Detail; end else if SameText( ADrawable.Name, 'balance') then begin (ADrawable as TListItemText).Text := FormatFloat('0.00', AData.Balance); end else if SameText( ADrawable.Name, 'reserved') then begin (ADrawable as TListItemText).Text := FormatFloat('0.00', AData.Reserved); end end; Главная хитрость и отличие от стандартного DynamicAppearance+LiveBinding - переменная высота итемов ListView и использование арифметики в описании раскладки. Можно указать Detail.Y = Text.Bottom + 5, ItemHeight = Detail.Bottom + 10, Detail.W = ItemWidth/2 - X {"Kind":"rect","Name":"BonusRect","Value":"", "Place":{"X":"itemwidth*3/4","Y":"Text.Y","W":"ItemWidth/4-5","H":"50"}, "BorderColor":"#FF005500", "Color":"lime", "LineWidth":3}, {"TextHAlign":2,"TextVAlign":1,"Kind":"text","Name":"Balance","Value":"", "Place":{"X":"BonusRect.x+5","Y":"Text.Y","W":"BonusRect.w-10","H":"50"}, "WordWrap":true, "Color" :"Black", "Font":{"Size":18,"Style":""}} ], "ItemHeight":"detail.bottom+10", Это дает довольно гибкую систему. Не на все случаи жизни, но все, что нужно, можно после автоматической раскладки дополнительно приписать в OnUpdateObjects Код для работы примерно такой procedure TForm1.FormCreate(Sender: TObject); begin data:= TMyDataList.CreateFromFile(ExePath()+'data.json'); // загрузка в модель данных Adapter := TMyAdapter.Create(lvWallets, data.Items, ExePath()+'pattern.json'); // создание адаптера и загрузка шаблона Adapter.Pattern.SetupListView(lvWallets); // задать отступы и разную мелочь Adapter.ResetView(); // здесь в цикле из модели данных создается нужное количество итемов ListView end; procedure TForm1.lvWalletsUpdatingObjects(const Sender: TObject; const AItem: TListViewItem; var AHandled: Boolean); begin Adapter.SetupContent(AItem); // загрузить текст, картинки и другое содержимое в элементы итема Adapter.Pattern.DoLayout(AItem); // поправить раскладку в соответствии с содержимым элементов итема end; Для использования кроме стандартных - текст, картинка, кнопка - создано несколько дополнительных элементов итема - прямоугольник, круг, уголок, линия. Отличие от ModernLV - , 1) все происходит без правки системных файлов 2) пока нет колонок и других особых изысков. На результат работы смотреть тут. Исходники пока не причесаны, будут чуть позже UPD. ссылки на репозитории ниже
    13 баллов
  3. Как сделать текст с подобными атрибутами? Очень просто! (Цвет текста не работает в XE8) Вот весь код: unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.UIConsts, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls, FMX.Objects, FMX.TextLayout; type TForm1 = class(TForm) Button1: TButton; Text1: TText; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.fmx} type TTextAccess = class(TText); procedure ClearTextAttribute(Text: TText); begin TTextAccess(Text).Layout.ClearAttributes; end; procedure AddTextAttribute(Text: TText; Pos,Length: Integer; FontStyles: TFontStyles; FontColor: TAlphaColor); var Font: TFont; begin Font:=TFont.Create; Font.Assign(Text.Font); Font.Style:=FontStyles; TTextAccess(Text).Layout.AddAttribute( TTextRange.Create(Pos,Length), TTextAttribute.Create(Font,FontColor)); end; procedure TForm1.Button1Click(Sender: TObject); begin AddTextAttribute(Text1,10,17,[TFontStyle.fsBold],claRed); AddTextAttribute(Text1,34,8,[TFontStyle.fsUnderline],claBlue); AddTextAttribute(Text1,47,8,[TFontStyle.fsStrikeOut],claGreen); Text1.Repaint; end; end.
    12 баллов
  4. У меня в работе два приложения, и оба они не предназначены для Play market, так как имеют ограниченный круг использования, по сути, чисто внутрикорпоративные. Так что нежелательно и выкладывание их и на альтернативные магазины приложений. Автоматически возникает вопрос обновления. Если в первый раз мы можем установить приложение сами при помощи админов, то обновлять их не так просто. А контингент пользователей не справится с "скачайте APK по ссылке, найдите, куда его скачал браузер, и запустите вручную именно последний скачанный, а не какой попало"... Простейший способ - дать приложению скачать свежую копию с сайта и натравить на полученный файл системный инсталлер. Вот только свежие Andoird делать это напрямик запрещают. Нужен filepropvider. Целый день шуровал по мануалам и YT, Вот то что получилось в результате. Если у вас 10.3.3 как у меня, уже можно не вносить <provider>...</provider> в манифест и свой файл file_paths.xml (или как вам его советуют назвать в интернетах) в деплой. Теперь все это делается хоть несколько странно и однобоко, но автоматически, путем установки галочки Secure File Sharing после этого в манифесте автоматически пропишется один из вариантов размещения файлов, которые вы можете найти в интернете. Используется алиас external-path файл, показанный на рисунке, создается автоматически самой делфи. теперь остается отгадать, какой путь реально подставится вместо "." Как показала практика, все пути выглядят не так, как кажется, если исходить из простого здравого смысла. Целый день использования GetHomeDir и других полезных методов TPath завел меня совсем в тупик. Оказалось все проще (?) st:TMemoryStream; OutputDir: JFile; ApkFile: JFile; ApkUri: Jnet_Uri; path, filename: string; ... OutputDir := TAndroidHelper.Context.getExternalCacheDir(); path := JStringToString(OutputDir.getAbsolutePath); filename := path+'/ASDroid2.apk'; ApkFile := TJfile.JavaClass.init( StringToJstring(filename)); FApkUri := TAndroidHelper.JFileToJURI(ApkFile); st.Position := 0; st.SaveToFile(filename); обратите внимание, в provider_paths мы задаем external-paths, а в коде ищем ExternalCacheDir.!!! (For.Unbelievably.Creative.Knowers!) Потом все просто. FApkUri передаем в интент и запускаем итоговый код примерно таков. (скачивание в потоке с использованием небольшого собственного API, но там ничего важного, можно не обращать внимания) procedure TasdSettingsFrame.bDownloadClick(Sender: TObject); begin {$IFDEF ANDROID} bDownload.Enabled := False; DownloadAndRun(); {$ENDIF} end; {$IFDEF ANDROID} procedure TasdSettingsFrame.DownloadAndRun(); begin ttask.Run(procedure var aapi:TasdAPI; st:TMemoryStream; OutputDir: JFile; ApkFile: JFile; ApkUri: Jnet_Uri; path, filename: string; begin st := TMemoryStream.Create; aapi := TasdAPI.Clone(_API); try aapi.OnReceiveData := OnReceiveData; aapi.getApk(st); if aapi.Err.Code=0 then begin OutputDir := TAndroidHelper.Context.getExternalCacheDir(); path := JStringToString(OutputDir.getAbsolutePath); filename := path+'/ASDroid2.apk'; ApkFile := TJfile.JavaClass.init( StringToJstring(filename)); FApkUri := TAndroidHelper.JFileToJURI(ApkFile); st.Position := 0; st.SaveToFile(filename); TThread.Synchronize(nil,procedure begin bDownload.Enabled := true; StartActivity(FApkUri); end); end; finally st.Free; aapi.Free; end; end); end; procedure StartActivity(ApkUri: Jnet_Uri); var Intent: JIntent; begin Intent := TJIntent.Create(); Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); Intent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK or TJIntent.JavaClass.FLAG_ACTIVITY_CLEAR_TOP or TJIntent.JavaClass.FLAG_GRANT_WRITE_URI_PERMISSION or TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION); Intent.setDataAndType(apkuri, StringToJString('application/vnd.android.package-archive')); TAndroidHelper.Activity.startActivity(Intent); end; procedure TasdSettingsFrame.OnReceiveData(const Sender: TObject; AContentLength: Int64; AReadCount: Int64; var Abort: Boolean); begin tthread.Synchronize(nil, procedure begin pb1.Max := AContentLength; pb1.Value := AReadCount; end); end; {$ENDIF} Вопросы остались конечно, почему так странно с каталогами, но выяснять пока нет желания. Работает - не трожь. Всем удачи. UPD. Для того, чтобы системный инсталлер запускался, нужно не забыть отметить еще одну галочку
    11 баллов
  5. Расскажу о том как я добился нормальной фоновой работы приложения. В моем понимании нормальная фоновая работа приложения - это сохранять геокоординаты и систематически (по мере их накопления передавать на сервер). По сути у нас получился трекер. Те кто считают что iOS такое не умеет делать, и все что будет написано ниже это фейк лучше закройти эту тему. Итак начнем, по пунктам: 1) Добавляем к проекту ключ NSLocationAlwaysAndWhenInUseUsageDescription - для новых иОС это обязательно, начиная с 11 или 12 версии уже не помню 2) Сообщаем приложению о намерении что мы будем использовать геокоординаты в фоне (редактируем ключ UIBackgroundModes выставляя галочку напротив location) 3) Далее для того чтобы не поломать другие приложения которые используют геолокацию создаем специальную дерективу, которая будет сообщать о том что наше приложение будет использовать геолокацию в фоне, я ее назвал iOS_RequestAlwaysAuthorization 4) Дальше намного сложнее, нам нужно исправить исходники самой Delphi, а именно System.iOS.Sensors. Изменять будем процедуру TiOSLocationSensor.DoStart, все что отличается от стандартного у меня в рамках описания моей директивы: function TiOSLocationSensor.DoStart: Boolean; var I: Integer; begin {$ifdef iOS_RequestAlwaysAuthorization} if TOSVersion.Check(8) and (FLocater <> nil) then FLocater.requestAlwaysAuthorization; {$else iOS_RequestAlwaysAuthorization} if TOSVersion.Check(8) and (FLocater <> nil) then FLocater.requestWhenInUseAuthorization; {$endif iOS_RequestAlwaysAuthorization} // check authorization if Authorized = TAuthorizationType.atUnauthorized then SensorError(SLocationServiceUnauthorized); // check if location sensor is enabled if not FLocater.locationServicesEnabled then SensorError(SLocationServiceDisabled); // start location updates if (LocationChange = TLocationChangeType.lctLarge) and CanUseSignifChangeNotifs then FLocater.startMonitoringSignificantLocationChanges else FLocater.startUpdatingLocation; // start heading updates if CanUseHeading then begin FLocater.startUpdatingHeading; end; // start monitoring regions if CanMonitorRegions then for I := 0 to Regions.Count - 1 do FLocater.startMonitoringForRegion(ConvLocationRegion(Regions[I])); Result := FLocater.locationServicesEnabled; if Result then Result := Authorized = TAuthorizationType.atAuthorized; {$ifdef iOS_RequestAlwaysAuthorization} FLocater.setAllowsBackgroundLocationUpdates(True); FLocater.setPausesLocationUpdatesAutomatically(False); {$endif iOS_RequestAlwaysAuthorization} end; Собственно усе, можно наслаждаться фоновой работой. Все это работает под Delphi 10.2.3. На телефоне iPhone 6s под управлением iOS 11. Как было сказано выше, работает как геолокация так и инет и вообще все остальные процессы внтури приложения, такие как TTimer Собственно вот результат данного трекера: Если приблизить то можно увидеть насколько точно и часто он обновляет координаты: И да, огромное спасибо человеку с ником Artyom Karapetyan, именно он натолкнул на мысль того как надо правильно все сделать
    11 баллов
  6. yooSee

    Runtime permissions in Delphi 10.3 Rio

    Всем привет, вот и я решил внести свою лепту в жизнь форума и сегодня мы разберемся с разрешениями на Delphi Rio под Андроид. Для примера мы будем использовать разрешения на чтение и запись с памяти устройства, для начала в нашем проекте выставим в Delphi>Project>Application>Uses Permissions галочки на Read External Storage и Write External Storage. в uses проекта добавьте следующее uses System.Permissions, Androidapi.Jni.Os, Androidapi.Helpers, далее создадим переменные var Form: TForm; .... FPermissionWrite: string; FPermissionRead: string; в Form.Create добавим следующий код procedure TForm.FormCreate(Sender: TObject); begin FPermissionWrite := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE); //Значение на запись FPermissionRead := JStringToString(TJManifest_permission.JavaClass.READ_EXTERNAL_STORAGE); //Значение на чтение end; и теперь сам не посредственно запрос на подтверждение наших прав procedure TForm.Button1Click(Sender: TObject); begin PermissionsService.RequestPermissions ([FPermissionWrite, FPermissionRead], nil); end; //это вызовет окно с запросом разрешения прав ну и для проверки бросим на форму TMemo и пару TButton , в них реализуем сохранение и чтение из файла с памяти устройства procedure TForm.Button1Click(Sender: TObject); begin Memo1.Lines.LoadFromFile(TPath.Combine(TPath.GetSharedDocumentsPath, 'test.txt')); end; procedure TForm.Button2Click(Sender: TObject); begin Memo1.Lines.SaveToFile(TPath.Combine(TPath.GetSharedDocumentsPath, 'test.txt')); end; P.S. Напоминаю что для работы TPath нам понадобится подключить в Uses uses System.system.ioutils; Надеюсь материал будет полезен! video_2019-02-08_00-11-36.mp4 Permissions.zip
    9 баллов
  7. Хочу от всей души поздравить с днем рождения нашего модератора Андрея Ефимова @Andrey Efimov. Человек, на которого можно положиться и который всегда готов прийти на помощь. Из года в год помогает нашему форуму становиться лучше. С днем рождения! Успехов тебе в работе, в личных делах. И не забывать про Делфи!
    9 баллов
  8. Задался вопросом, нашел ответ, может кому пригодится. uses Androidapi.JNI.Media, Androidapi.Helpers, Androidapi.JNIBridge, AndroidApi.Jni.JavaTypes, Androidapi.JNI.GraphicsContentViewText; .... procedure TFormMain.PlaySoundEffects(const ASoundID : Integer; AVolume : Single = 1.0); var AudioObj: JObject; Audio: JAudioManager; begin AudioObj:= TAndroidHelper.Context.getSystemService(TJContext.JavaClass.AUDIO_SERVICE); Audio:= TJAudioManager.Wrap((AudioObj as ILocalObject).GetObjectID); Audio.loadSoundEffects; Audio.playSoundEffect(ASoundID, AVolume); end; Константы звуковых эффектов тут https://developer.android.com/reference/android/view/SoundEffectConstants Правда у меня только звук "чпок" на всех константах. Но мне он и был нужен )
    9 баллов
  9. В общем удалось решить проблему с кнопками пульта. Теперь приложение распознает все кнопки с пульта. Если кому-то нужно, прикрепил архив. (Delphi 10.3.1 Rio) fmx_androidkey_fix.zip
    8 баллов
  10. OnePeople

    Монополия

    Делал чисто для себя! И только для своего удовольствия! Возможны ошибки!*(вернее точно есть))) Графика не окончательная! Скриншоты сервер: Скриншоты клиент: Сервер на комп, клиент Android (должны находиться в одной сети) P/S И так как все устройства у меня Full HD, проверял только на них( Monopoly.rar
    8 баллов
  11. Тема: "Сравнение возможностей кроссплатформенных мобильных библиотек нативных приложений FMX и FGX Native" Дата и время: 20 декабря 2018 года в 12:00 (по московскому времени) Участники: @Brovin Yaroslav, Андрей Совцов Регистрация: ссылка Ссылка на официальный телеграмм канал: https://t.me/fgx_native Участие бесплатное Под конец уходящего нового года сравним текущие возможности кроссплатформенной библиотеки мобильной разработки FGX Native и FMX. Поговорим о перспективах развития и ознакомимся с ближайшим планом до выпуска публичной бета версии. Посмотрим в живую на новый функционал библиотеки, разработанный за последнее время. У вас будет возможность задать любые вопросы автору. Не пропусти эту возможность!
    8 баллов
  12. brunnengi

    Android 10 (API уровня 29)

    Здравствуйте. Некоторые пользователи Delphi 10.3 столкнулись с тем что даже при указании SDK 29 в манифесте проекта, при запуске скомпилированного приложения на платформе Android 10 происходило его падение. В августе 30 числа 2020 года было дано решение как пофиксить эту проблему. Переход на версию Delphi 10.4 не для всех является приемлемым решением, по разным причинам, к примеру у кого то платные компоненты и нет возможности обновиться до актуальных версий. Ниже представлен перевод статьи. В конце будет ссылка на оригинал. Приведенное здесь решение нацелено на обновление функции 'dlopen' в файле 'ICU.inc' (он включен в файл 'System.pas'). Вот шаги, необходимые для решения указанной проблемы: Откройте проводник и перейдите в папку по следующему пути: C:\Program Files (x86)\Embarcadero\Studio\20.0\source Скопируйте файлы из архива "missing_source_files.zip", который приложен в посту, в папку source из пункта "1" (комментарий от переводчика: в "missing_source_files.zip" лежит папка "rtl" в которой две папки - "posix", "sys". Лично я сделал сначала backup папки rtl из папки source, что и вам советую. Затем скопировал rtl папку из "missing_source_files.zip" и вставил в папку source) Переходим по пути: C:\Program Files (x86)\Embarcadero\Studio\20.0\source\rtl\sys Открываем файл "ICU.inc" в текстовом редакторе (пожалуйста, сделайте backup файла 'ICU.inc' для пущей безопасности). (комментарий от переводчика: орудовать в этой папке без прав админа не вариант. Поэтому я советую сначала скопировать файл "ICU.inc" куда нибудь в другое место, к примеру в папку Documents и там уже открыть его в том же Блокноте и сделав необходимые изменения сохранить файл и затем уже переместить его в C:\Program Files (x86)\Embarcadero\Studio\20.0\source\rtl\sys с заменой) В текстовом редакторе надо изменить функцию InitICU: Было вот так: А сделать надо что было вот так: Сохраняем сделанные изменения в файле "ICU.inc" Возвращаемся в проводник и переходим в папку %USERPROFILE% Скопируйте файл "build.bat" из архива "build_script.zip" , который приложен в этому посту в папку из пункта 7. Запустите от имени Администратора файл "build.bat". (Он создаст папку %USERPROFILE%\build в которой будет несколько папок с файлами. Из них нам нужны будут только System.o, но об этом ниже) Возвращаемся в проводник и переходим в папку C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\android\debug Скопируйте файл "System.o" из папки %USERPROFILE%\build\android\debug в папку из шага 10 (не забывайте сделать backup всех файл что вы заменяете, на всякий случай). Теперь переходим в проводник в папку C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\android\release Скопируйте файл "System.o" из папки %USERPROFILE%\build\android\release в папку из шага 12 (не забывайте сделать backup всех файл что вы заменяете, на всякий случай). Переходим в проводник в папку C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\android64\debug Скопируйте файл "System.o" из папки %USERPROFILE%\build\android64\debug в папку из шага 14 (не забывайте сделать backup всех файл что вы заменяете, на всякий случай). Переходим в проводник в папку C:\Program Files (x86)\Embarcadero\Studio\20.0\lib\android64\release Скопируйте файл "System.o" из папки %USERPROFILE%\build\android64\release в папку из шага 16 (не забывайте сделать backup всех файл что вы заменяете, на всякий случай). На этом всё. Автор данного перевода лично прошел по всем шагам и сделал всё как было сказано, а также протестил на приложении что уже было в PlayMarket'е но не запускалось под Android 10. Я его обновил и запустил как на Android ниже 10, так и на Android 10. ЕСЛИ ВЫ НЕ ДОВЕРЯЕТЕ ПЕРЕВОДУ И/ИЛИ ВЫЛОЖЕННЫМ ФАЙЛАМ, ТО НИЖЕ ДАНА ССЫЛКА НА ОРИГИНАЛ СТАТЬИ // файлы выложенные здесь, взяты с форума где оригинал статьи. Ссылка на оригинал https://quality.embarcadero.com/browse/RSP-27218 Если нет логина, то под споллером скрины экрана с форума ссылки выше: Отдельное спасибо пользователю Stanislau Ihnatovich за сообщение в Telegram о том что есть решение build_script.zipmissing_source_files.zip
    7 баллов
  13. krapotkin

    Переезд на 10.3 Rio

    сколько бед принесла уже стрельба в ногу под названием ProcessMessages как хорошо, что в Андроиде наконец всех отучат от этого крайне вредного трюка давайте формально все что там у вас "высоконагруженное" выносите в потоки и пусть они работают. Ваши "потоки" пасутся в главном (Synchronize) и никакого толка нет концепцию надо поменять. запустили поток и занимайтесь своим делом. например покажите Splash а вернется поток - вот по возвращению и сделаете то, что этот Splash закроет. и уж точно потоки не должны ничего общего иметь с формами я писал статью про потоки, там про сплеши тоже есть в блоге и про ProcessMessages отдельная боль... http://www.cyberforum.ru/blogs/469693/blog4875.html
    7 баллов
  14. Для полноценной работы вам нужно добавить параметры в вызов (иначе вы не узнаете дал ли пользователь разрешение или нет) PermissionsService.RequestPermissions([FPermissionWrite, FPermissionRead], nil); Вот так: PermissionsService.RequestPermissions([FPermissionWrite, FPermissionRead], PermissionRequestResult, ExplainReason); PermissionRequestResult - это обработка ответа пользователя procedure TForm.PermissionRequestResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>); begin if (Length(AGrantResults) = 2) and (AGrantResults[0] = TPermissionStatus.Granted) and (AGrantResults[1] = TPermissionStatus.Granted) then begin // Ура! Пользователь дал разрешение на оба наших запроса. Выставялем глобальные флаги (к примеру) которые сигнализируют что можно читать/писать карту памти end else TDialogService.ShowMessage('Не возможно продолжить работу, требуемые разрешения не получены') end; И ExplainReason - если пользователь сдуру не дал разрешение, то вам нужно объяснить ему что без этого приложение работать не будет. procedure TForm.ExplainReason(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc); begin TDialogService.ShowMessage('Приложению нужен доступ к карте памяти для таких то целей, иначе приложение не сможет работать. Зайдите в настроки Андроид и дайте разрешение на доступ', procedure(const AResult: TModalResult) begin APostRationaleProc; end) end;
    7 баллов
  15. Недавно решил одну проблемку, которая долго мучала - решил поделиться, может кому ещё пригодится. При работе с двумя мониторами или с монитором и проектором часто возникает необходимость запретить окну "исчезать" при наведении курсора мыши на миниатюру другого приложения в панели задач. Чтобы это сделать надо: uses ... Winapi.DwmApi ... TMainForm = class(TForm) ... protected procedure CreateHandle; override; ... end; ... procedure TMainForm.CreateHandle; var Val, Res: Integer; begin inherited CreateHandle; Val := 1; Res := DwmSetWindowAttribute(FormToHWND(Self), DWMWA_EXCLUDED_FROM_PEEK, @Val, SizeOf(Val)); {$IFDEF DEBUG} if Res <> S_OK then ShowMessage(SysErrorMessage(Res)); {$ENDIF} end; Спасибо @Alex7wrt за наводку
    7 баллов
  16. сделано на Datasnap - 3х звенка MsSql- Сервис Https - Клиент ( Андроид, Ios, Win, Mac) Личный кабинет пациента клиники (www.familydoctor.ru) открывает зарегистрированным пользователям доступ к медицинской карте (результаты лабораторных исследований и функциональной диагностики, описание приемов врачей, направления и рекомендации, истории посещений клиники (дата, время, специалист), программам медицинского наблюдения (перечень, период прикрепления), информации о движении средств по депозитам. Для пересылки выписок (файлов) из медицинской карты используется электронная почта (в системе должен быть настроенный Майл Агент на отправку почты).Полной версией приложения могут воспользоваться только пациенты, подключившие услугу "Личный кабинет" в регистратуре любого корпуса клиники "Семейный доктор".В новой версии изменен дизайн, появились новые функции и разделы:вход по номеру медкарты или ФИО;запрос нового пароля;заявка на онлайн запись;отмена приема;прейскурант услуг клиники;справочник адресов клиники. сервис оплаты услуг клиники через приложение.В ближайшем будущем функционал личного кабинета будет дополнен онлайн расписанием специалистов, возможностью электронной записи на приём. в гугл плее https://play.google.com/store/apps/details?id=com.familydoctor.FD Есть тестовый вход, обращайтесь.
    6 баллов
  17. Это приложение для OS Windows выполняет: 1.Расчёт сцепления: -расчёт и подбор геометрических параметров нажимного и ведомого дисков, муфты выключения; -проверка параметров по теплонагруженности пар трения; -расчёт всех наиболее нагруженных деталей сцепления (пружины, пластины, подшипник). 2.Расчёт пневмогидравлического привода сцелпения: -подбор и проверка управляющего и исполнительного органов; -объём жидкости. 3.Возможность вноса и редактирования исходных данных и результатов в БД. 4.Распечатку всего расчёта с исходными данными, формулами, графиками, используемой литературой и результатами в MS Word. 5.Просмотр и изучение нажимного, ведомого дисков и муфты выключения в 3D. Изначально для работы в приложении необходимы некоторые знания конструкции сцепления и теории расчёта. Автор: Олег Киреев-ведущий инженер-конструктор, kireevoleg1966@gmail.com, +375 29 676 13 84 БЕЛАРУСЬ, г.Минск. Приму Ваши замечания и предложения. По совету Равиля Зарипова РАЗМЕСТИЛ на файлообменнике 12.08.2019г по этой: https://mega.dp.ua/a27WmeXKwY ссылке. На этом ресурсе обещают хранить 90 дней. Интересно услышать Ваши отзывы.
    6 баллов
  18. Пока тестировал хелпер в боевом проекте он потихоньку оброс исрпавлениями/улучшениями: Загрузка из потока сделана через TBitmapSurface - это позволяет избежать множества глюков. LoadFromStream вынесен из Synchronize (основного потока) в поток HTTPClient - по результатам бенчмарка операция оказалась самая жручая. После исправления интерфейс перестал залипать совсем. Добавлен overload вариант с передачей в процедуру TListItemImage - для использования в TListView и корректной перерисовки подгруженных картинок через AListItemImage.Invalidate. unit BitmapAsyncLoader; interface uses FMX.Graphics, FMX.Surfaces, System.Net.HttpClient, System.Types, System.Classes, FMX.ListView.Types, FMX.ListView.Appearances; type TBitmapAsyncLoader = class helper for TBitmap procedure LoadFromURLAsync(const AUrl : String); overload; procedure LoadFromURLAsync(const AUrl : String; const AListItemImage : TListItemImage); overload; end; implementation var AHTTPClient : THTTPClient; procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String); begin try AHTTPClient.BeginGet( procedure (const ASyncResult: IAsyncResult) var AHTTPResponse : IHTTPResponse; ABitmapSurface : TBitmapSurface; begin if Not ASyncResult.IsCompleted then exit; try AHTTPResponse:=THTTPClient.EndAsyncHTTP(ASyncResult); except end; if Assigned(AHTTPResponse) and (AHTTPResponse.StatusCode = 200) then begin ABitmapSurface:=TBitmapSurface.Create; if TBitmapCodecManager.LoadFromStream(AHTTPResponse.ContentStream, ABitmapSurface, CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize)) then TThread.Synchronize(Nil, procedure begin if Assigned(Self)then Assign(ABitmapSurface); ABitmapSurface.Free; end ) else ABitmapSurface.Free; end; end, AURL ); except end; end; procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage); begin try AHTTPClient.BeginGet( procedure (const ASyncResult: IAsyncResult) var AHTTPResponse : IHTTPResponse; ABitmapSurface : TBitmapSurface; begin if Not ASyncResult.IsCompleted then exit; try AHTTPResponse:=THTTPClient.EndAsyncHTTP(ASyncResult); except end; if Assigned(AHTTPResponse) and (AHTTPResponse.StatusCode = 200) then begin ABitmapSurface:=TBitmapSurface.Create; if TBitmapCodecManager.LoadFromStream(AHTTPResponse.ContentStream, ABitmapSurface, CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize)) then TThread.Synchronize(Nil, procedure begin if Assigned(Self) and Assigned(AListItemImage) then begin AListItemImage.BeginUpdate; Assign(ABitmapSurface); AListItemImage.Invalidate; AListItemImage.EndUpdate; end; ABitmapSurface.Free; end ) else ABitmapSurface.Free; end; end, AURL ); except end; end; initialization AHTTPClient:=THTTPClient.Create; finalization if Assigned(AHTTPClient) then AHTTPClient.DisposeOf; end. Тестовый проект, на этот раз с ListView (по кнопке добавляется 100 итемов) прилагаю. BitmapAsyncLoaderListView.7z
    6 баллов
  19. Делаем как обычно, если надо переопределить какое-то событие окна interface uses {$IFDEF MSWINDOWS} Winapi.Windows, Winapi.Messages, FMX.Platform.Win, {$ENDIF} System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs; type TMainForm = class(TForm) private procedure CreateHandle; override; {$IFDEF MSWINDOWS} procedure WMIMENotify(var Msg: TMessage); message WM_IME_NOTIFY; {$ENDIF} public end; var MainForm: TMainForm; implementation {$R *.fmx} {$IFDEF MSWINDOWS} var OldWndProc: Pointer = nil; function NewWndProc(Wnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall; var Mess : TMessage; begin case Msg of WM_IME_NOTIFY: begin Mess.Msg := Msg; Mess.WParam := wParam; Mess.lParam := lParam; Mess.Result := 0; MainForm.Dispatch(Mess); Result := Mess.Result; end; else Result := CallWindowProc(OldWndProc, Wnd, Msg, WParam, LParam); end; end; {$ENDIF} { TMainForm } procedure TMainForm.CreateHandle; begin inherited CreateHandle; {$IFDEF MSWINDOWS} OldWndProc:= Pointer(SetWindowLong(WindowHandleToPlatform(Handle).Wnd, GWL_WNDPROC, Integer(@NewWndProc))); {$ENDIF} end; {$IFDEF MSWINDOWS} procedure TMainForm.WMIMENotify(var Msg: TMessage); begin {что-то делаем} end; {$ENDIF}
    6 баллов
  20. slav_z

    FMX: Скроллинг и нажатия

    Все разработчики при работе с FMX рано или поздно сталкиваются с одной и той же проблемой: необходимо исключить "случайное" срабатывание нажатий элементов внутри скроллбокса во время его скроллинга. Идут годы, а решения так и нет. Давайте попробуем это исправить. Поехали! Запускаем IDE, создаем новый проект, кидаем на форму TVertScrollBox и на него чего-нибудь побольше... запускаем на мобильном устройстве, пытаемся скроллировать, получаем проблемы в виде срабатывания разных событий типа OnClick элементов. Решение состоит в том, чтобы сделать элементы "невидимыми" для событий связанных с действиями пользователя с экраном во время скроллинга. Делаем следующее: Все. Переносим код в базовую форму, делаем его более гибким, убираем все те костыли, которые мы уже успели сделать ранее... Удачи! https://github.com/slav-libx/scroll-click.git
    5 баллов
  21. Линковка Kotlin (Котлин) библиотек в Delphi, как делаю: Хедеры линкуемых библиотек обычно громадны описанием всех типов... Я обычно делаю свой jar на java в нем линкую зависимости и наружу для дельфи оставляю один объект с простыми функциями. Хедер дельфи получается компактным и понятным: package com.MyCompany.evotor; public interface J2DCallback { void Log(String str); String Trans(String str); String GetValue(String name); void SetValue(String name, String value); Activity GetActivity(); Context GetContext(); } public class FiscalCoreConnection { final private Global Instance; public FiscalCoreConnection(J2DCallback aj2d) throws NullPointerException { Instance = new Global(aj2d); } public String SendJSON(String JSON){ try{ return Instance.SendJson(JSON); } catch (Exception e) { return FiscalCoreException.MakeJson(e); } } } type J2DCallbackClass = interface(IJavaClass) ['{856654D5-7939-44DF-ACD5-E2EF8C6D3AA4}'] end; [JavaSignature('com/MyCompany/evotor/J2DCallback')] J2DCallbackIntf = interface(IJavaInstance) ['{025B14E9-C041-4105-9E85-83CC127CC340}'] procedure Log(str:JString); cdecl; function Trans(str:JString):JString; cdecl; function GetValue(name:JString):JString; cdecl; procedure SetValue(name:JString; value:JString); cdecl; function GetActivity():JActivity; cdecl; function GetContext():JContext; cdecl; end; TJ2DCallbackImp = class(TJavaGenericImport<J2DCallbackClass, J2DCallbackIntf>) end; [JavaSignature('com/MyCompany/evotor/FiscalCoreConnection')] JFiscalCoreConnection = interface(JObject) ['{5797747D-D61D-4EF6-94F7-5E8994545CC2}'] function SendJSON(JSON:JString):JString; cdecl; end; JFiscalCoreConnectionClass = interface(JObjectClass) ['{81782882-DFCF-4FA9-BD37-02CCCF2409EA}'] function init(j2d : J2DCallbackIntf) : JFiscalCoreConnection; cdecl; end; TJFiscalCoreConnection = class(TJavaGenericImport<JFiscalCoreConnectionClass, JFiscalCoreConnection>) end; TJ2DCallback = class(TJavaLocal, J2DCallbackIntf) public procedure Log(str:JString); cdecl; function Trans(str:JString):JString; cdecl; function GetValue(name:JString):JString; cdecl; procedure SetValue(name:JString; value:JString); cdecl; function GetActivity():JActivity; cdecl; function GetContext():JContext; cdecl; end; Все зависимости в build.gradle: dependencies { implementation 'com.github.evotor:integration-library:v0.4.50' implementation 'com.google.zxing:core:3.4.0' } В Дереве External Libraries забираем jarы зависимостей ПКМ Show in Explorer. Копируем в папку своего проекта и даем осознанное имя. Там же забираем kotlin-stdlib ПКМ Show in Explorer. Копируем в папку своего проекта и даем осознанное имя. Но в kotlin-stdlib.jar есть "лишний" файл kotlin-stdlib-1.5.10.jar\META-INF\versions\9\module-info.class Открываем архиватором и удаляем файл или всю папку versions Почти все готово... Но котлин еще и посыпан сахаром и не хочет Дельфей dexится, хочет -min-sdk-version=26 Поможем Delphi: Ищем CodeGear.Common.Targets, у меня он в "C:\Program Files (x86)\Embarcadero\Studio\21.0\bin"\ Ищем в нем --output, и перед ним вставим все про sdk. У меня получилось так: <DxCmd>PATH $(JDKPath)\bin;$(PATH); %26 set JAVA_HOME=$(JDKPath)%26 "$(JavaDxPath)" --dex --min-sdk-version=26 --output=</DxCmd> Далее цепляем все jar в проект Либа производителя, Либа своя обертка, и котлин Иии собираем! Если есть еще зависимости делаем аналогично: находим jar, выпиливаем META-INF\versions\9\module-info.class, линкуем в проект и собираем... Не все зависимости используются и нужны, поэтому добавляем поштучно до тех пор пока не заведется.
    5 баллов
  22. Alex7wrt

    9-Patch PNG FMX Generator

    Сделал небольшую программу-генератор 9-patch заставок. Достаточно выбрать цвет фона, логотип и его видимый размер, и программа сгенерирует 9-patch для всех необходимых в FMX размеров. Примеры Рисунок: Полученные 9-Patch png: Рисунок: Полученные 9-Patch png: Исходники: 9Patch Generator.zip
    5 баллов
  23. gonzales

    поломались ПУШи в 10.4

    Нашел причину, В недрах класса TPushService TPushService = class abstract public type TPropPair = TPair<string, string>; TPropArray = TArray<TPropPair>; // commonly used names TServiceNames = record public const GCM = 'gcm'; // deprecated 'Is not available anymore. Please use FCM instead'; // Google cloud messaging FCM = 'fcm'; // Google Firebase cloud messaging APS = 'aps'; // Apple end; Соответственно нужно исправить FPushService := TPushServiceManager.Instance.GetServiceByName(TPushService.TServiceNames.GCM); на FPushService := TPushServiceManager.Instance.GetServiceByName(TPushService.TServiceNames.FCM); Все работает
    5 баллов
  24. krapotkin

    Не подключается Huawei

    Короче, действуем примерно так. Я надеюсь, что базовые действия - скачать google latest adb driver - мы уже провели, но наш No- или Brand- name телефон недоступен Тогда 1) идем в диспетчер устройств, находим там наше невстающее устройство, кликаем дважды, и на закладке Сведения выбираем свойство ИД оборудования. Копируем себе что-то типа 2) идем к файлам того самого драйвера, открываем android_winusb.inf находим разделы [Google.NTx86] и [Google.NTamd64] и вписываем туда, прямо в оба ;galaxy tab a 2019 %SingleAdbInterface% = USB_Install, USB\VID_04E8&PID_6866 %CompositeAdbInterface% = USB_Install, USB\VID_04E8&PID_6866&MI_01 3) делаем обновить драйвер, выбираем вариант Вручную, и указываем тот модифицированный файл если не берет автоматом, то "Выбрать из списка уже установленных..." --> "Есть диск" --> "Да, мне пофиг что он не подписан" 4) The End
    5 баллов
  25. Результат следующий Мой проект корректно работает под 1) Windows 32/64 2) Android 32/64 3) iOS 32/64 (обязательно настроить сертификаты, которые можно создать и прикрепить в Xcode + настроить их в Rad Studio в разделе Project-Deployment-Provisioning, выбрать там ключи как вы их настроили на вашем маке + ОБЯЗАТЕЛЬНО в version info удалить текст в CFBundleIdentifier, должно быть пусто) 4) MacOS 32/64 5) iOS 32/64 simulator - не работает!!!
    5 баллов
  26. Обновлена серия статей на тему использования Uses Permissions. Uses Permissions: Теория Uses Permissions: Добавляем метод onRequestPermissionsResult в приложение (для Delphi 10.1/10.2) Uses Permissions: Практика (для Delphi 10.3) Автор: Андрей Ефимов
    5 баллов
  27. еще один пример раскладки из реального проекта { "Columns":[], "Variables": [ {"Y_UNIT":"12"}, {"GAP":"8"}, {"ITEM_H":"2*GAP+5*Y_UNIT"}, {"IMG_H":"76"}, {"IMG_W":"76"}, {"STOCK_SIZE":"48"}, {"PRICE_COLW":"53"} ], "Objects": [ {"Name":"ID","Kind":"data"}, , {"Name":"img","Kind":"image", "Place":{"X":"0","Y":"0","W":"IMG_W","H":"IMG_H"}, } , {"Name":"Text","Kind":"text","TextHAlign":"leading","TextVAlign":"leading", "Place":{"X":"img.right","Y":"GAP","W":"itemwidth - IMG_W - GAP - 2*PRICE_COLW - GAP","H":"52"}, "WordWrap":true, "Color":"black", "Font":{"Size":12} } , {"Name":"earlier","Kind":"text","TextHAlign":"leading","TextVAlign":"leading", "Place":{"X":"text.left","Y":"ITEM_H-2*GAP+2","W":"itemwidth - 2*PRICE_COLW","H":"Y_UNIT"}, "WordWrap":false, "Color":"green", "Font":{"Size":10} } , {"Name":"price1","Kind":"text","TextHAlign":"trailing","TextVAlign":"trailing", "Place":{"X":"itemwidth-GAP-PRICE_COLW-W","Y":"GAP+2*Y_UNIT","W":"auto","H":"Y_UNIT*1.5", "priority":"WXYH"}, "WordWrap":false, "Color":"black", "Font":{"Size":15} } , {"Name":"imgstrike","Kind":"image", "Place":{"X":"price1.x-5","Y":"price1.y","W":"price1.w+8","H":"price1.h"}, } , {"Name":"price2","Kind":"text","TextHAlign":"trailing","TextVAlign":"trailing", "Place":{"X":"price1.right-W","Y":"ITEM_H-GAP-Y_UNIT*1.5","W":"auto","H":"Y_UNIT*1.5", "priority":"WXYH"}, "WordWrap":false, "Color":"black", "Font":{"Size":15, "style":"bold"} } , {"Name":"qty","Kind":"text","TextHAlign":"trailing","TextVAlign":"center", "Place":{"X":"itemwidth-PRICE_COLW-GAP","Y":"GAP","W":"PRICE_COLW","H":"2*Y_UNIT"}, "WordWrap":false, "Color":"black", "Font":{"Size":27, "style":"bold"} } , {"Name":"imgstock","Kind":"image", "Place":{"X":"itemwidth-STOCK_SIZE-3","Y":"ITEM_H-STOCK_SIZE-4","W":"STOCK_SIZE","H":"STOCK_SIZE"}, } ], "ItemHeight":"ITEM_H", "ItemSpaces": {"X":"0","Y":"0","W":"0","H":""}, "SideSpace":"0" }
    5 баллов
  28. Собственно понадобился подобный компонент для FMX, но готового решения найти не смог - пришлось ваять свой. Использовать проще простого: var scenaries: TDictionary<TFmxObject, string>; begin scenaries := TDictionary<TFmxObject, string>.Create; scenaries.Add(btn_1, '1 Button'); scenaries.Add(btn_2, '2 Button'); scenaries.Add(btn_3, '3 Button'); scenaries.Add(rctngl, 'Rectangle'#13#10'Rectangle'#13#10'Rectangle'#13#10'Rectangle'#13#10'Rectangle'#13#10'Rectangle'#13#10'Rectangle'); scenaries.Add(pnl_1, 'Panel Panel Panel Panel Panel Panel Panel Panel Panel Panel'#13#10'Panel'); scenaries.Add(nil, 'Msg without target control!'); try instructor.LoadSteps(scenaries); finally FreeAndNil(scenaries); end; Репозиторий GitHub: https://github.com/ange007/TInstructor/
    5 баллов
  29. Протокол SNTP Помимо NTP, существует упрощенная версия этого протокола - SNTP (Simple Network Time Protocol). Он реализован для синхронизации времени конечным клиентом, поскольку все преимущества протокола NTP проявляются именно в сети серверов, а для получения показаний конечным пользователем NTP излишне сложен. Поэтому для синхронизации времени конечными компьютерами и серверами был предложен протокол SNTP (SNTPv3: 1992 г., RFC1361 и 1995 г., RFC1769; SNTPv4 включён как подпротокол в NTPv4). На самом деле SNTP - это не новый протокол, а способ использования NTP-пакетов и NTP-серверов в приложениях, где не требуется высокоточное время, либо оно недостижимо. В этом случае клиент использует только часть информации UDP-пакета NTP-сервера. SNTP-клиент может работать с любыми версиями NTP-серверов, и кроме них - с особыми SNTP-серверами, которые в откликах заполняют только необходимые данные UDP-пакета. Таким образом, "облегченный" SNTP образует не сеть синхронизирующихся серверов, а пары "клиент-сервер". Любой NTP-сервер является одновременно SNTP-сервером. Клиент, который не передаёт полученное время дальше, может работать как NTP- или SNTP-клиент, в зависимости от условий. Для SNTP, как и для NTP, зарезервирован 123-й UDP-порт. Uses IdSNTP, IdBaseComponent, IdComponent, IdUDPBase, IdUDPClient; .... procedure TForm1.Button2Click(Sender: TObject); Var IdSNTP: TIdSNTP; begin IdSNTP:=TIdSNTP.Create(Self); IdSNTP.Host := 'ntp1.stratum2.ru'; ShowMessage(DateTimeToStr(IdSNTP.DateTime)); IdSNTP.Free; end;
    5 баллов
  30. Не ссоритесь девочки пож. Возвращаясь к сути вопроса. Основная сложность тут в том, что в Delphi нельзя разрушать экземпляр класса внутри метода этого класса за исключением тех случаев, когда метод использует только для разрушения Free, DisposeOf. Почему так, а не иначе, какие есть исключения и почему "уменяфсёработает" объяснять долго, поэтому в первом приближении предлагаю принять это за аксиому. Обработчики событий OnClick и пр. вызываются из методов классов, так что разрушать контрол внутри события нельзя от слова совсем. Кроме очевидных случаев типа Self.DisposeOf существуют более запутанные варианты, когда к примеру закрывает и разрушается форма, что приводит к разрушению всех дочерних контролов. Образно говоря, самоубийства строго запрещены, но не запрещено нанимать киллера и в качестве жертвы указывать себя. Т.е. должен быть некий другой (глобальный) объект который будет разрушать объекты, которые хотели бы самоубицо. Реализацию такого объекта можете придумать сами, или использовать TPurgatory (чистилище, в католическом учении — промежуточное место между раем и адом). Но чтобы убедиться в правильности работы можно создать своего наследника TButton в котором перекрыть деструктор и поставить в нем точку останова. При запуске в режиме отладки посмотрите стек вызова деструктора (надо быть внимательным, он может быть длиннющим), ни где в этом стеке не должно быть метода разрушаемого экземпляра. Если в Вы нашли метод разрушаемого объекта (за исключением вышеуказанных), то Ваш способ удаления работает не правильно и с некоторой долей вероятности будет приводить к AV и другим "неприятностям" которые почти невозможно отловить в режиме отладки.
    5 баллов
  31. Slym

    Артефакты на экране (Android)

    Боролись как-то с артефактами отображения (мы их прозвали "крокодилами" из-за сходства на первом скриншоте с этим багом)... Могли отображаться также левые спрайты, или обрезки скролившихся контролов... Коллега выяснил что не надо трогать Form.Fill, из-за переключения в недрах FMX нативной и не нативной канвы: если нужен фон - брось Rect по контенту и в нем делай заливку...
    5 баллов
  32. В конце концов получилось исправить. Для interlaced гифок проблема была вообще пустяковая. Одна строчка не в том месте. А вот для optimized все оказалось несколько сложней, но в итоге теперь все гифки отображаются правильно. Пользуйтесь на здоровье! FMX.GifUtils.zip
    5 баллов
  33. ну как так то? условная компиляция! посмотрите в исходных кодах дельфи... там куча примеров... КУЧА!!!
    4 балла
  34. Большое количество - это сколько? 100, 100 000, 100 000 000? Каждый раз увеличивая размер на один элемент, менеджер памяти ищет непрерывный незанятый кусок памяти такой длины, чтобы уместить все элементы. Хорошо если место под уже выделенный массив позволяет увеличить размер, не упираясь в участики памяти занятые другими данными. Иногда после очередного увеличения массива, уже выделенного участка памяти более не хватает. В таком случае менеджеру приходится искать новый, и копировать старые данные в новый участок памяти, а старый участок помечать как свободный. Разумеется это занимает время. Именно это и приводит к "не так быстро, как хотелось бы". Чтобы избежать этого: 1 Способ курильщика, простой: Увеличиваем размер массива не на 1 элемент, а сразу на 16/32/128/1024 элемента (вам виднее, в зависимости от того сколько у вас может быть элементов в массиве). Также заводим счетчик - номер последнего занятого элемента в массиве, и после каждого добавления - увеличиваем этот счетчик на единицу. Этот способ не избавит от проблемы, но будет приводить к менее частому перераспределению памяти. 2 Способ здорового человека, чуть сложнее: используйте указатели. Заведите массив указателей (либо TList), выделяйте место под каждую новую запись (ваш record) вручную, и помещайте указатель на него в ваш массив указателей (или в TList). Не забывайте освобождать выделенную память, когда ваши обьекты больше не нужны. Этот спобоб более правильный, так как в этом случае перераспределение происходит очень редко. Кстати, реализация TList использует внутри себя первый способ.
    4 балла
  35. Maka

    переход к x64?

    Отвечают долго, 10-14 дней, а потом еще около 7 дней переписка, проверки и ожидание решения. Наберитесь терпения
    4 балла
  36. правильный ответ - не делать так )) нужно хранить настройки приложения в отдельном классе тогда кроме самого класса нужны методы, которые 1) читают пишут его из ... файла, БД, интернета и т.д. 2) в нужный момент (обычно чтобы изобразить форму и заполнить св-ва компонентов или еще для чего угодно) использовать эти настройки 3) вытекает из 2) сохранять в нужный момент новые значения в переменную, где лежат настройки для хранения настроек отлично подходит JSON. Т.к. он может иметь иерархическую структуру, что очень удобно. Его и хранить в БД. Можно и прямо поля, строки и все такое, но все равно, собирать их нужно в некое хранилище в программе. Пример разбирал тут http://www.cyberforum.ru/blogs/469693/blog4883.html
    4 балла
  37. Отвечу сам себе. Проблема решена. Всего два дня поисков и вот он, случай - краеугольный камень поиска ошибок! Меня аж забомбило, когда я это откопал. Оказалось, что мой грид лежит на лайоуте, у которого hittest = false. Так вот до тех пор, пока я не перевел его в true грид отказывался принимать ondragover. Но как только layout.hittest:=true все заработало. Дальше дело техники.
    4 балла
  38. Окончательный вариант. Долго бился с изменением размера картинки внутри потока (к примеру что бы в ListView не грузить картинки больше чем нужно). Средствами TBitmap это оказалось сделать невозможно (именно в потоке), чтение форумов, issue Эмбаркадеро, привело к туманному выводу что проблема в архитектуре FMX. В Токио, TBitmap стал потокобезопасным - это означает что никогда не пытайтесь использовать Bitmap в потоке, рано или поздно получите артефакты и глюки. Я решил проблему отказавшись от работы с TBitmap в потоке, и использовав для этого TBitmapSurface (загрузка из stream, изменение размеров). Что умеет хелпер: 1. Загрузка картинки в Bitmap и подгонкой размера (размер можно и не менять - не передавайте параметр ASize) procedure LoadFromURLAsync(const AURL : String; const ASize : TControlSize = nil); overload; 2. Загрузка картинки в TListItemImage ListView. После Окончания загрузки хелпер выполнит AListItemImage.Invalidate в основном потоке приложения для отрисовки картинки. procedure LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage); overload; 3. Создание картинки. Тоже самое что и предыдущие, но можно сэкономить строчку кода ABitmap:=TBitmap.Create ? constructor CreateFromUrlAsync(const AURL : String; const AListItemImage : TListItemImage = nil); По картинкам в ListView - можете на свой страх и риск грузить 100500 картинок, но лучше использовать загрузку только для видимой части (+- еще сколько то итемов). Хелпер тупо грузит картинки и не обеспечивает механизм оптимальной загрузки. Протестировано на Windows и Android. Ответы на вопросы которые мне задавали: Почему не создавать отдельный поток для каждой картинки, в нем создавать THTTPClient и делать запрос - пробовал этот вариант, он медленнее на порядок, даже под виндой это чертовски медленно. AHTTPClient.BeginGet и так создает отдельный поток на каждый запрос. Почему AHTTPClient глобальный для юнита - в хелпере нельзя вводить свои переменные, а создавать AHTTPClient внутри функции не выйдет - он убьется до завершения потока. И текущий вариант быстрее. Код хелпера и архив с тестовым проектом: unit BitmapAsyncLoader; interface uses System.Net.HttpClient, System.Net.URLClient, System.SysUtils, System.Types, System.Classes, FMX.Graphics, FMX.Surfaces, FMX.Types, FMX.ListView.Types; type TBitmapAsyncLoader = class helper for TBitmap private function ResizeBitmapSurface(const ABitmapSurface : TBitmapSurface; const AWidth, AHeight : Integer) : TBitmapSurface; procedure SynchronizeAssignFromBitmapSurface(const ABitmapSurface : TBitmapSurface; const AListItemImage : TListItemImage = nil); procedure StartHTTPThread(const AURL : String; const AWidth, AHeight : Integer; const AListItemImage : TListItemImage = nil); public procedure LoadFromURLAsync(const AURL : String; const ASize : TControlSize = nil); overload; procedure LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage); overload; constructor CreateFromUrlAsync(const AURL : String; const AListItemImage : TListItemImage = nil); end; implementation type THTTPClientListener = class class procedure HTTPClientValidateServerCertificate(const Sender: TObject; const ARequest: TURLRequest; const Certificate: TCertificate; var Accepted: Boolean); end; var AHTTPClient : THTTPClient; constructor TBitmapAsyncLoader.CreateFromUrlAsync(const AURL : String; const AListItemImage : TListItemImage = nil); begin Create; LoadFromURLAsync(AURL, AListItemImage); end; procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String; const AListItemImage : TListItemImage); var AWidth, AHeight : Integer; begin if Assigned(AListItemImage) then begin AWidth:=Round(AListItemImage.Width); AHeight:=Round(AListItemImage.Height); end else begin AWidth:=-1; AHeight:=-1; end; StartHTTPThread(AURL, AWidth, AHeight, AListItemImage); end; procedure TBitmapAsyncLoader.LoadFromURLAsync(const AURL : String; const ASize : TControlSize = nil); var AWidth, AHeight : Integer; begin if Assigned(ASize) then begin AWidth:=Round(ASize.Width); AHeight:=Round(ASize.Height); end else begin AWidth:=-1; AHeight:=-1; end; StartHTTPThread(AURL, AWidth, AHeight); end; function TBitmapAsyncLoader.ResizeBitmapSurface(const ABitmapSurface : TBitmapSurface; const AWidth, AHeight : Integer) : TBitmapSurface; begin if (AWidth <> -1) and (AHeight <> -1) then begin try Result:=TBitmapSurface.Create; Result.StretchFrom(ABitmapSurface, AWidth, AHeight, ABitmapSurface.PixelFormat); finally ABitmapSurface.Free; end; end else Result:=ABitmapSurface; end; procedure TBitmapAsyncLoader.SynchronizeAssignFromBitmapSurface(const ABitmapSurface : TBitmapSurface; const AListItemImage : TListItemImage = nil); begin TThread.Synchronize(Nil, procedure begin Assign(ABitmapSurface); ABitmapSurface.Free; if Assigned(AListItemImage) then AListItemImage.Invalidate; end ); end; procedure TBitmapAsyncLoader.StartHTTPThread(const AURL : String; const AWidth, AHeight : Integer; const AListItemImage : TListItemImage = nil); begin AHTTPClient.BeginGet( procedure (const ASyncResult: IAsyncResult) var AHTTPResponse : IHTTPResponse; ABitmapSurface : TBitmapSurface; begin if Not ASyncResult.IsCompleted then exit; try AHTTPResponse:=THTTPClient.EndAsyncHTTP(ASyncResult); except exit; end; if Assigned(AHTTPResponse) and (AHTTPResponse.StatusCode = 200) then begin ABitmapSurface:=TBitmapSurface.Create; if TBitmapCodecManager.LoadFromStream(AHTTPResponse.ContentStream, ABitmapSurface, Self.CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize)) then begin ABitmapSurface:=ResizeBitmapSurface(ABitmapSurface, AWidth, AHeight); SynchronizeAssignFromBitmapSurface(ABitmapSurface, AListItemImage); end; end; end, AURL ); end; class procedure THTTPClientListener.HTTPClientValidateServerCertificate(const Sender: TObject; const ARequest: TURLRequest; const Certificate: TCertificate; var Accepted: Boolean); begin Accepted:=True; end; initialization AHTTPClient:=THTTPClient.Create; AHTTPClient.OnValidateServerCertificate:=THTTPClientListener.HTTPClientValidateServerCertificate; finalization if Assigned(AHTTPClient) then AHTTPClient.DisposeOf; end. BitmapAsyncLoader.7z
    4 балла
  39. Ingalime

    переход к x64?

    https://community.idera.com/developer-tools/b/blog/posts/google-play-store-android-32-bit-extension-for-delphi-and-c-builder-customers
    4 балла
  40. qz5

    Версия андроид

    Я разбавлю своим вариантом: Leagoo Power 2. У него цена около 3000 рублей, из коробки идет Андроид 8.1, но можно поставить Андроид 9 и даже... Android 10!!! С одной стороны у меня среди родственников есть смарты от 4ой до 9-ой версии Андроид, да и моя прога сейчас на всех работает (пока она простая). Но с другой стороны решил поискать дешевый смарт, на который можно несколько разных версий Андроид поставить, но: 1. чтобы это было легко, без всяких разблокировок и т.п. (у новых Xiaomi, Huawei как раз проблемы с заблокированным загрузчиком) 2. чтобы был максимально дешевый 3. чтобы можно было поставить Андроид 8.1 и Андроид 9, причем разные сборки 4. чтобы не надо было ставить всякие Flash Tools и т.п. - искал, чтобы прошивка была простой и максимально без лишних программ Оказалось, что Leagoo Power 2 Pro: 1. Поддерживает GSI-прошивки от Project Treble (Андроид 8.1, Андроид 9 и Android 10) 2. стоит около 3000 рублей 3. Для прошивки не нужно никаких лишних программ! Достаточно ADB, а он и так уже идет вместе с Delphi (можно и самому ADB ставить на комп, если Delphi нет например) Взял на будущее, чтобы было дешевое устройство, на котором можно экспериментировать с прошивками Правда сам пока не пробовал - телефон получил, всё работает, но пока закинул его в коробочку, тестирую на смартфоне с Андроид 7 (он всё равно постоянно на столе и там нужные мне программы). Как прошить ТВРП: https://4pda.ru/forum/index.php?showtopic=928803&st=120#entry81458052 Другие версии Андроид брать здесь: https://4pda.ru/forum/index.php?showtopic=892755 Где купить: решайте сами, многие покупают на Пандао, но я почитал отзывы - Пандао какой-то странный магазин, ничего там не покупал и не стал из-за 200 рублей рисковать. Я взял там, где советует официальный производитель: https://vk.com/wall-148943419_19677 Доставила почта Сингапура за 20 дней. p.s. я кучу разных вариантов пересмотрел и остановился именно на нем. Самая легкая перепрошивка из всех, недорогой смарт, есть запчасти, возможность ставить разные кастомы. может кому пригодится ?
    4 балла
  41. Это будет имя Bluetooth-адаптера. //uses System.Bluetooth; TBluetoothManager.Current.CurrentAdapter.AdapterName
    4 балла
  42. Barbanel

    Аналог TDBGrid для FMX

    Вы случайно не в Эппл работаете? "Если у нас чего-либо нет - значит пользователям это не нужно" (С) Шучу-шучу))) Разумеется я отдаю себе отчет о накладных расходах, и о траффике. Миллион записей мы и за год не сгенерируем, а больше пары тысяч отображать и не требуется, а если и потребуется то был бы инструмент - проблема решится. Вопрос был лишь в том, есть ли такой аналог как DBGrid. Пытаюсь написать нечто похожее через хелпер к TGridModel, пока получается. Когда меня все будет устраивать - выложу в общий доступ.
    4 балла
  43. по вопросам. 1) выбор на хостингах невелик - MySQL, Postgres. Я PG выбрал чисто в силу интереса и он вроде поближе к стандартам, и у него ХП и другие всякие штуки.... Сижу на SWEB.RU. Опять же просто потому что давно. Есть и masterhost и любой другой крупный провайдер подойдет. 2) не путаем хостинг с бэкенд-сервером (BAS). Типа Firebase или Amazon или еще туча. на хостинге у вас все свое. что написали то и работает. на BAS есть много приятных плюшек. Довольно платных ессно. Зато и push и email рассылки и админка... 3) MSSQL не вариант. Веб в основном на Linux. 4) обычно просто THttpClient. На нем нормально пишется клиентская часть API 5) обычная схема. просто с нуля некоторые вещи пилить. зато бесплатно. Практика показывает что иногда лучше заплатить и получить богатое приложение сразу. но иногда как написал Евгений, потом можно упереться в ограничения сервисов. Но можно решать проблемы по мере поступления...
    4 балла
  44. krapotkin

    Переезд на 10.3 Rio

    научили конечно ))) все придумано до нас вот статья вот так в грубом приближении должно это быть p.s. Забыл удалить из ваших форм эти циклы, которых там быть не должно Форма - это интерфейс взаимодействия с пользователем. Данные должны жить отдельно. test10.3.zip
    4 балла
  45. Вот и картинки подвезли. Идиотский Deployment отказывается переписывать старые файлы на новые.... Пока полностью не удалил приложение, файл-описание раскладки был старый, без картинок Как видно из заголовка 3000+ итемов с авторасчетом высоты. 6 секунд Крутится плавно... ListViewTest.apk.rar
    4 балла
  46. Barbanel

    Runtime permissions in Delphi 10.3 Rio

    В поставке 10.3 есть примеры работы с правами. Один из них можно найти по такому пути: C:\Users\Public\Documents\Embarcadero\Studio\20.0\Samples\Object Pascal\Multi-Device Samples\Media\PhotoEditorDemo Что интересно, этот же код можно без изменений использовать под любой другой платформой. На других платформах приложение будет считать что ему выдали все права, и соответственно запускать все коллбеки без каких-либо вопросов.
    4 балла
  47. Dev

    Анимированная смена форм

    https://www.youtube.com/watch?v=YU7MlY58n9U&t=59s
    4 балла
  48. Проблема сохранилась и в IDE Delphi Rio 10.3 . Причиной оказалось то, что в модуле FMX.StdCtrls в процедуре TExpander.UpdateControlSize указана переменная FContentHeight вместо FContent.Height procedure TExpander.UpdateControlSize(const ChangingState: Boolean); begin FChangingState := ChangingState; try if FIsExpanded then begin FContent.Visible := FIsExpanded; if FButton <> nil then Height := FButton.Height + FContent.Height; // здесь заменил FContentHeight на FContent.Height и заработало Repaint; end else begin Repaint; FContent.Visible := FIsExpanded; if FButton <> nil then Height := FButton.Height; end; finally FChangingState := False; end; end;
    4 балла
  49. Обнаружил, что на некоторых телефонах с вытянутым экраном не отображается Smart Banner (TBannerAD.Size = Auto). Оказалось, что причиной тому неверный расчет высоты баннера в исходниках FMX.Advertising.Android. Может быть, эта информация кому-нибудь поможет В документации Android высота баннера должна вычисляться так: Тогда как в коде FMX.Advertising.Android она вычисляется в процедуре UpdateControlMetrics следующим образом: const AdHeightPortrait = 90; AdHeightLandscape = 90; AdHeightPhonePortrait = 50; AdHeightPhoneLandscape = 32; AndroidSW600DP = 600; AndroidSW600DPLandscape = 552; AdMobBannerHeight = 50; AdMobFullBannerHeight = 60; AdMobLeaderboardHeight = 90; begin if (FAdControl <> nil) and not Assigned(FAdControl.OnResize) then begin case FAdControl.AdSize of TBannerAdSize.Auto: begin if Screen.Size.Height > Screen.Size.Width then if Screen.Size.Width < AndroidSW600DP then FAdControl.Height := AdHeightPhonePortrait else FAdControl.Height := AdHeightPortrait else if Screen.Size.Height < AndroidSW600DPLandscape then FAdControl.Height := AdHeightPhoneLandscape else FAdControl.Height := AdHeightLandscape; end; Также, учитывая, что на вытянутых экранах (по крайней мере на тех устройствах, на которых я тестил), Screen.Width и Screen.Height далеко не всегда дают верные значения, то более правильный код процедуры TAndroidBannerAd.UpdateControlMetrics будет таким: procedure TAndroidBannerAd.UpdateControlMetrics; var Frame: TRectF; Form: TCommonCustomForm; Disp: JDisplayMetrics; Window: JWindow; h: integer; const AdHeightLandscape = 90; AdHeightPhoneLandscape = 32; AndroidSW600DP = 600; AndroidSW600DPLandscape = 552; AdMobBannerHeight = 50; AdMobFullBannerHeight = 60; AdMobLeaderboardHeight = 90; begin if (FAdControl <> nil) and not Assigned(FAdControl.OnResize) then begin Disp := TJDisplayMetrics.Create; Window:=TJWindow.Wrap((MainActivity.getWindow as ILocalObject).GetObjectID); Window.getWindowManager.getDefaultDisplay.getRealMetrics(disp); h:=round(Disp.heightPixels/Disp.density); case FAdControl.AdSize of TBannerAdSize.Auto: begin if Screen.Size.Height > Screen.Size.Width then begin if h <= 400 then FAdControl.Height := 32 else if (h>400) and (h<=720) then FAdControl.Height:=50 else FAdControl.Height := 90 end else if Screen.Size.Height < AndroidSW600DPLandscape then FAdControl.Height := AdHeightPhoneLandscape else FAdControl.Height := AdHeightLandscape; end; TBannerAdSize.Small: FAdControl.Height := AdMobBannerHeight; TBannerAdSize.Medium: FAdControl.Height := AdMobFullBannerHeight; TBannerAdSize.Large: FAdControl.Height := AdMobLeaderboardHeight; end; if Screen.ActiveForm <> nil then Form := Screen.ActiveForm else if Application.MainForm <> nil then Form := Application.MainForm else Form := nil; if Form <> nil then begin Frame := WindowHandleToPlatform(Form.Handle).Bounds; FAdControl.Width := Round(Frame.Width); end; end; end;
    4 балла
Эта таблица лидеров рассчитана в Москва/GMT+03:00
×
×
  • Создать...