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

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

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

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

  • Посещение

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

    100

Активность репутации

  1. Like
    Евгений Корепов отреагировална Barbanel в Выполнение операции после скрытия меню   
    Процедура Invalidate не перерисовывает форму немедленно, она лишь добавляет сообщение на перерисовку в очередь сообщений.
    Соотв. форма перерисуется когда не будет других событий в очереди, в данном случае - после всех длительных операций или после вызова .ProcessMessages
  2. Like
    Евгений Корепов отреагировална krapotkin в Выполнение операции после скрытия меню   
    есть более интересный и по-мне, более правильный способ
    по нажатию в меню не сразу выполняете что-то, а ЗАПИСЫВАЕТЕ действие, которое ВЫПОЛНИТСЯ по событию закрытия мультивью
    тогда реакция наступает визуально правильная и дальше крутите колеса, запускайте потоки и все такое
  3. Like
    Евгений Корепов отреагировална Alex7wrt в Выполнение операции после скрытия меню   
    TForm.Invalidate
  4. Thanks
    Евгений Корепов получил реакцию от Wolfone в Работа с камерой - Rad 10.3   
    Вот кусок кода из боевого приложения, достаточно разрешения на доступ к камере, больше никаких разрешений не надо. Надеюсь вам поможет.
    FScanCamera : TCameraComponent;
    FScanManager - не обращайте внимания, это распознавание QR кодов.
    ImageCamera : TImage; - картинка на форме где отображаются кадры с камеры
    Работа начинается с ScanStart()
    {$IFDEF MOBILE} // *************************************************************** // ****** Сканирование QR кода ****** // *************************************************************** procedure TFormMain.ScanStart(); var AppEventSvc: IFMXApplicationEventService; APermissionCamera : String; begin if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, IInterface(AppEventSvc)) then AppEventSvc.SetApplicationEventHandler(AppEvent); FScanFrameTake := 0; CButtonScan.Text:='Отменить сканирование'; {$IFDEF IOS} ScanStarting(); {$ENDIF IOS} {$IFDEF ANDROID} APermissionCamera := JStringToString(TJManifest_permission.JavaClass.CAMERA); PermissionsService.RequestPermissions([APermissionCamera], CameraPermissionRequestResult, ExplainReason); {$ENDIF ANDROID} end; procedure TFormMain.ScanStop(); begin if Assigned(FScanCamera) then begin if FScanCamera.Active then FScanCamera.Active:=False; FScanCamera.Free; end; { if Assigned(FScanManager) then begin FScanManager.Free; end; } FScanInProgress := false; LayoutCamera.Height:=0; CButtonScan.Text:='Сканировать QR-код'; end; {$IFDEF ANDROID} procedure TFormMain.CameraPermissionRequestResult(Sender: TObject; const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>); begin if (Length(AGrantResults) = 1) and (AGrantResults[0] = TPermissionStatus.Granted) then begin ScanStarting(); end else TDialogService.ShowMessage('Сканирование QR-кода не возможно, требуемое разрешение не было дано') end; procedure TFormMain.ExplainReason(Sender: TObject; const APermissions: TArray<string>; const APostRationaleProc: TProc); begin TDialogService.ShowMessage('Приложению нужен доступ к камере для сканирования QR-кода ...', procedure(const AResult: TModalResult) begin APostRationaleProc; end) end; {$ENDIF ANDROID} procedure TFormMain.ScanStarting(); begin FScanInProgress := false; if Not Assigned(FScanManager) then FScanManager:= TScanManager.Create(TBarcodeFormat.QR_CODE, nil); if Not Assigned(FScanCamera) then FScanCamera:=TCameraComponent.Create(Self); FScanCamera.OnSampleBufferReady:=ScanCameraSampleBufferReady; FScanCamera.Quality := FMX.Media.TVideoCaptureQuality.MediumQuality; FScanCamera.Active := false; FScanCamera.Kind := FMX.Media.TCameraKind.BackCamera; FScanCamera.FocusMode := FMX.Media.TFocusMode.ContinuousAutoFocus; FScanCamera.Active := True; LayoutCamera.Height:=LayoutCamera.Width; end; { procedure TFormMain.btnStopCameraClick(Sender: TObject); begin end; } procedure TFormMain.ScanCameraSampleBufferReady(Sender: TObject; const ATime: TMediaTime); begin TThread.Synchronize(TThread.CurrentThread, GetImageCamera); end; procedure TFormMain.GetImageCamera; var scanBitmap: TBitmap; ReadResult: TReadResult; begin FScanCamera.SampleBufferToBitmap(ImageCamera.Bitmap, True); if (FScanInProgress) then exit; { This code will take every 4 frame. } Inc(FScanFrameTake); if (FScanFrameTake mod 4 <> 0) then exit; scanBitmap := TBitmap.Create(); scanBitmap.Assign(ImageCamera.Bitmap); ReadResult := nil; // There is bug in Delphi Berlin 10.1 update 2 which causes the TTask and // the TThread.Synchronize to cause exceptions. // See: https://quality.embarcadero.com/browse/RSP-16377?jql=project%20%3D%20RSP%20AND%20issuetype%20%3D%20Bug%20AND%20affectedVersion%20%3D%20%2210.1%20Berlin%20Update%202%22%20AND%20status%20%3D%20Open%20ORDER%20BY%20priority%20DESC TTask.Run( procedure begin try FScanInProgress := True; try ReadResult := FScanManager.Scan(scanBitmap); except on E: Exception do begin TThread.Synchronize(nil, procedure begin LabelAPIKey.Text := 'Ключ доступа : ' + E.Message; end); exit; end; end; TThread.Synchronize(nil, procedure begin if (ReadResult <> nil) then begin if ProcessingAPIKeyHex(ReadResult.Text) then begin ScanStop(); end; end; end); finally ReadResult.Free; scanBitmap.Free; FScanInProgress := false; end; end); end; { Make sure the camera is released if you're going away. } function TFormMain.AppEvent(AAppEvent: TApplicationEvent; AContext: TObject): Boolean; begin case AAppEvent of TApplicationEvent.WillBecomeInactive, TApplicationEvent.EnteredBackground, TApplicationEvent.WillTerminate: if Assigned(FScanCamera) then FScanCamera.Active := false; end; Result:=True; end;  
  5. Like
    Евгений Корепов отреагировална krapotkin в TBitmapData   
    Считалось, что до RIO TBitmap НЕ потокобезопасен. В RIO рапортовали, что справились с этим. Не помню, проверял кто или нет
    Но TBitmapSurface был потокобезопасен уже тогда. Возможно, стоит готовить данные там, а потом просто отдавать в Bitmap
    https://stackoverflow.com/questions/37602538/delphi-tbitmap-to-string-via-tbitmapsurface-and-back-to-tbitmap
    https://stackoverflow.com/questions/51523321/how-to-draw-fmx-surface-tbitmapsurface-on-fmx-graphics-tbitmap/51526855
     
  6. Like
    Евгений Корепов получил реакцию от Ingalime в [РЕШЕНО]: Как отловить кнопки пульта ДУ   
    Друзья, вы будете смеяться - Эмбаркадера наконец то обратила внимание на заявку по этой проблеме. Правда в стиле моя-твоя непонимай ))) 
    https://quality.embarcadero.com/browse/RSP-16910
  7. Like
    Евгений Корепов отреагировална CyberStorm в Умирает ли делфи? (С хабра)   
    Странно, что никто не обратил внимание на важную для всех делфистов статью на хабре:
    https://habr.com/ru/post/481534/
  8. Like
    Евгений Корепов получил реакцию от Barbanel в Логика авторизации по отпечатку пальца   
    В телефоне нет никаких гарантированных аппаратных данных - или по причине китайщины, или по тому что их можно изменить. Если уже вам так хочется "привязаться" к чему то неизменному, то привязывайтесь к телефонному номеру. Хотя и его может не быть. 
    Палец не панацея - у вас нет никаких гарантий что палец принадлежит владельцу персональных данных. 100% дактилоскопических данных пользователя у вас нет, а на этапе "привязки" пальца, телефон уже может быть в руках злоумышленника.
    У вас не получится сделать идеальную систему с абсолютной системой от дурака. Поэтому я и предложил исходить из того что приложение на телефоне запускает легальных пользователь. Все иное должно описываться в политике конфиденциальности, типа мы чтим закон о ПД, но если вы долбоклюй и отдали телефон и пинкод постороннему, то вы сами пролюбили свою медкарту.
    И пинкод никак не позволит войти на другом устройстве - пин код сохраняется локально на устройстве, в папке приложения. И если пользователь ввел его верно, то запросы на сервер авторизуются с заранее сохраненного на устройстве токена (guid, куки или что вам больше нравится). 
    Ситуации "А если кто взломает телефон и перенесет какой то файл на другое устройство" вас не должны волновать абсолютно. Вы предоставили пользователю приложение, а задача пользователя  - не пролюбить телефон и свои персональные данные. Дополнительно вы прикрываете свою задницу политикой конфиденциальности, где описываете что не обязаны охранять пользователя и его телефон круглые сутки.
  9. Like
    Евгений Корепов получил реакцию от Ingalime в Логика авторизации по отпечатку пальца   
    В телефоне нет никаких гарантированных аппаратных данных - или по причине китайщины, или по тому что их можно изменить. Если уже вам так хочется "привязаться" к чему то неизменному, то привязывайтесь к телефонному номеру. Хотя и его может не быть. 
    Палец не панацея - у вас нет никаких гарантий что палец принадлежит владельцу персональных данных. 100% дактилоскопических данных пользователя у вас нет, а на этапе "привязки" пальца, телефон уже может быть в руках злоумышленника.
    У вас не получится сделать идеальную систему с абсолютной системой от дурака. Поэтому я и предложил исходить из того что приложение на телефоне запускает легальных пользователь. Все иное должно описываться в политике конфиденциальности, типа мы чтим закон о ПД, но если вы долбоклюй и отдали телефон и пинкод постороннему, то вы сами пролюбили свою медкарту.
    И пинкод никак не позволит войти на другом устройстве - пин код сохраняется локально на устройстве, в папке приложения. И если пользователь ввел его верно, то запросы на сервер авторизуются с заранее сохраненного на устройстве токена (guid, куки или что вам больше нравится). 
    Ситуации "А если кто взломает телефон и перенесет какой то файл на другое устройство" вас не должны волновать абсолютно. Вы предоставили пользователю приложение, а задача пользователя  - не пролюбить телефон и свои персональные данные. Дополнительно вы прикрываете свою задницу политикой конфиденциальности, где описываете что не обязаны охранять пользователя и его телефон круглые сутки.
  10. Like
    Евгений Корепов отреагировална Slym в Передача параметров (с русскими буквами) в UTF8 в NetHTTPClient.Post   
    HTTPAnalyzer показывает:
    POST / HTTP/1.1 Connection: Keep-Alive Content-Type: application/x-www-form-urlencoded; charset=utf-8 User-Agent: Embarcadero URI Client/1.0 Host: www.yandex.ru Content-Length: 148 nOwnerOrganizMode=1&cRegNumber=%D1%81-5%2F1&cBegRegDate=22.05.2029&cFIO=%D1%81%D0%B5%D1%80%D0%B3&cDocContent=%D0%B9%D1%86%D1%83qwe%D0%B9%D1%86%D1%83 Обилие %D0 - показывают что уходит UNICODE, а кодирование цифр и английского одним символом указывает что это UTF8... и заголовки этому соответствуют
    Проблема на клиенте отсутствует... копай сервис
     
  11. Like
    Евгений Корепов отреагировална krapotkin в Свой APK updater. Использование Fileprovider   
    полезные ссылки 
    https://android-tools.ru/coding/delimsya-fajlami-v-android-s-pomoshhyu-fileprovider/
    https://www.delphiworlds.com/2018/06/targeting-android-8-and-higher-continued/
  12. Like
    Евгений Корепов отреагировална krapotkin в Свой APK updater. Использование Fileprovider   
    От программиста никаких действий не требуется. Система любезно сообщает, что откуда попало не ставит, но вот вам переход прямо на нужную настройку. Переходим, включаем, нажимаем back и продолжаем установку...
  13. Like
    Евгений Корепов отреагировална krapotkin в Свой APK updater. Использование Fileprovider   
    У меня в работе два приложения, и оба они не предназначены для 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.
    Для того, чтобы системный инсталлер запускался, нужно не забыть отметить еще одну галочку

     
     
     
     
     
  14. Like
    Евгений Корепов отреагировална krapotkin в Ошибка java.lang.IllegalArgumentException: Unable to load native library... libProject1.so   
    В процессе разработки столкнулся с очень странной ситуацией, корни которой до сих пор неясны, но решение нашлось.
    Итак. Делфи 10.3.3. Чистое приложение - пустая форма и кнопка. Отлично работает на разных устройствах кроме Samsung Galaxy Tab A (2016). Android 5.1.1
    Программа падает, не успев даже загрузиться. Любая. При этом она же, скомпилированная на другом компе, запускается нормально. И даже после изменения SDK/NDK на нем, ничего не падает.
    LogCat дает крайне странную картину
    java.lang.IllegalArgumentException: Unable to load native library: /data/app-lib/com.embarcadero.Project1-1/libProject1.so
    Начинаем экспериментировать с SDK, NDK и т.д. Поставил также хотфиксы для 10.3.3.
    Сразу скажу, SDK/NDK ставились отдельно через Android studio, не скачивались вместе с Delphi. Не торопитесь бросать чтение на этом месте!)) На другом компе, где все работает, все ставилось точно так же.
    Короче, очень много комбинаций версий SDK/NDK проверено.
    Результат такой. При постепенном понижении версии NDK все взлетело при NDK v22.

    При этом версия SDK видимо такого большого влияния не имеет, потому что этот вариант нормально работает

    Повторюсь. На других устройствах все работало и на более новых Ndk. Xiaomi Mi Pad4 , Samsung Galaxy Tab A (2019), Xiaomi Redmi 5 и 5Plus
     
    Спасибо за участие и помощь в разборе завалов @Andrey Efimov
     
  15. Like
    Евгений Корепов получил реакцию от Сергей Сергеев в Логика авторизации по отпечатку пальца   
    В телефоне нет никаких гарантированных аппаратных данных - или по причине китайщины, или по тому что их можно изменить. Если уже вам так хочется "привязаться" к чему то неизменному, то привязывайтесь к телефонному номеру. Хотя и его может не быть. 
    Палец не панацея - у вас нет никаких гарантий что палец принадлежит владельцу персональных данных. 100% дактилоскопических данных пользователя у вас нет, а на этапе "привязки" пальца, телефон уже может быть в руках злоумышленника.
    У вас не получится сделать идеальную систему с абсолютной системой от дурака. Поэтому я и предложил исходить из того что приложение на телефоне запускает легальных пользователь. Все иное должно описываться в политике конфиденциальности, типа мы чтим закон о ПД, но если вы долбоклюй и отдали телефон и пинкод постороннему, то вы сами пролюбили свою медкарту.
    И пинкод никак не позволит войти на другом устройстве - пин код сохраняется локально на устройстве, в папке приложения. И если пользователь ввел его верно, то запросы на сервер авторизуются с заранее сохраненного на устройстве токена (guid, куки или что вам больше нравится). 
    Ситуации "А если кто взломает телефон и перенесет какой то файл на другое устройство" вас не должны волновать абсолютно. Вы предоставили пользователю приложение, а задача пользователя  - не пролюбить телефон и свои персональные данные. Дополнительно вы прикрываете свою задницу политикой конфиденциальности, где описываете что не обязаны охранять пользователя и его телефон круглые сутки.
  16. Like
    Евгений Корепов получил реакцию от Ingalime в Прочитать DNS запрос в idUDPServer   
    Все правильно получаете, кодировка тут не при чем. Согласно спецификации "DNS Packet Structure", вы получаете не строку, а пакет который нужно разобрать. К примеру если запрос будет "nslookup www.google.ru 127.0.0.1", то там где вы получаете имя хоста будет строка "''#3'www'#6'google'#2'ru'#0#0#1#0#1".
    Парсинг простейший:
    #3 - означает что далее идут 3 символа хоста 'www' - вот ожидаемые 3 символа #6 - далее идут еще 6 символов хоста 'google' - ага, вот они #2 - ну и еще 2 символа 'ru' - ура, они здесь #0 - конец имени хоста, складываем в кучу, перемежая точками и получаем www.google.ru #0 - дальше у нас служебная информация... #1 #0 #1 Вот как то так.
    P.S. А зачем вам на таком низком уровне работать? Может использовать IdDNSServer : TIdDNSServer ?
    P.P.S. Правильно Memo1.Lines.Add(BytesToString(AData,12)); //(12, а не 13)
  17. Like
    Евгений Корепов отреагировална Yarpda в [DELPHI FMX Android] [6.0] Не удается загрузить SSL библиотеку   
    Спасибо! Действительно многое открылось. )) ThttpClient  заработал как и хотелось  и без танцев с бубном над библиотеками SSL.
  18. Thanks
    Евгений Корепов получил реакцию от Yarpda в [DELPHI FMX Android] [6.0] Не удается загрузить SSL библиотеку   
    Вам не нужен TNETHTTPClient, это всего лишь обертка для THTTPClient. Просто сделайте поиск по данному форуму по "THTTPClient" и вам откроется многое.
  19. Like
    Евгений Корепов получил реакцию от Ingalime в [DELPHI FMX Android] [6.0] Не удается загрузить SSL библиотеку   
    Вам не нужен TNETHTTPClient, это всего лишь обертка для THTTPClient. Просто сделайте поиск по данному форуму по "THTTPClient" и вам откроется многое.
  20. Like
    Евгений Корепов получил реакцию от Tumaso в [DELPHI FMX Android] [6.0] Не удается загрузить SSL библиотеку   
    В примере у вас получение данных по HTTPS. В рабочем проекте тоже самое? Может тогда не мучатся с Indy и его сторонними библиотеками, а использовать родной механизм андроида - THTTPClient?  
  21. Like
    Евгений Корепов получил реакцию от #WAMACO в [DELPHI FMX Android] [6.0] Не удается загрузить SSL библиотеку   
    В примере у вас получение данных по HTTPS. В рабочем проекте тоже самое? Может тогда не мучатся с Indy и его сторонними библиотеками, а использовать родной механизм андроида - THTTPClient?  
  22. Like
    Евгений Корепов отреагировална slav_z в Положение скролла.   
    function IsEndScroll(ScrollBox: TCustomScrollBox): Boolean; begin Result:=ScrollBox.ViewportPosition.Y>=ScrollBox.ContentBounds.Height-ScrollBox.ClientHeight; end;  
  23. Like
    Евгений Корепов получил реакцию от Anatoliy в Умный дом   
    К сожалению тема никакого отношения в Умному дому не имеет. В телеграмме я поднимал тему о реальных технологиях умного дома - датчиках (задымление, протечка, газ, открытие двери/окна, движение), протоколы и технологии соединения всего этого, к примеру ZigBee, ну и работа со всем этим хозяйством.
    Тема прикольная и интересная. Написал на delphi класс работы в ZigBee шлюзом, нормально опрашиваю все датчики, но запись реализовать не удалось из за отсутствия в delphi библиотек шифрования "из коробки". Наработок куча, но все они времен Delph 7 - абсолютно все используют короткие ANSI строки, и в современных версиях среды результат шифрования/дешифровки может быть какой угодно, но не правильный.
    Пока все что нужно по быстрому написал на php, там хоть с шифрованием порядок, не надо изобретать велосипед или адаптировать код двадцатилетней давности.
    Так что теперь могу включать/выключать свет с помощью умной розетки, включать светильник на основном хабе, выбирая яркость и палитру, но на php ))))
  24. Like
    Евгений Корепов отреагировална krapotkin в Фреймворк для стандартного ListView   
    еще один пример раскладки из реального проекта

    { "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" }  
  25. Like
    Евгений Корепов получил реакцию от qz5 в Где указать ownerBitmap := true (ImageListItemBottomDetail)   
    Смотрите, вот ваш код:
    procedure TfmMain.LoadBitmapFromURL(const AURL: string; const AItem: TListViewItem; aBitmap: TBitmap; aSourceBmp: TRectangle); var K: Integer; // Анонимная процедура захватывает локальную переменную, а не обращается к AItem, которой уже может не быть в момент _окончания_ скачивания фотки FHTTPClient : THTTPClient; ResourceStream: TResourceStream; begin Вы используете асинхронный вызов FHTTPClient.BeginGet , начинает выполнятся HTTP запрос, одновременно процедура LoadBitmapFromURL завершает работу и компилятор уничтожает локальные переменные, включая FHTTPClient. Асинхронные вызовы с получением результат происходят уже после уничтожения FHTTPClient и естественно ничего не работает. Вод виндой работает случайно - из за другой модели управления памятью.
    У вас несколько путей:
    1. Сделать FHTTPClient глобальным - лучший и простой путь.
    2. Создавать поток самостоятельно, использовать в нем FHTTPClient.Get (не асинхронный)
    3. И еще куча вариантов....
    Посмотрите как реализовано у меня (по первому варианту) 
     
×
×
  • Создать...