• 0
Anasazi

Поочередная загрузка изображений в TImage

Вопрос

Всем доброго времени суток. Возникла необходимость решить такую задачу: в таблице базы MySQL хранится список изображений и их URL. Необходимо получить этот список массивом. Затем загрузить изображения и поочередно с интервалом показать их в TImage.

Понимаю, что получить список изображений правильнее при помощи PHP скрипта, но в каком виде скрип должен вернуть данные, чтобы в Delphi получить из них массив не знаю.

Раньше для получения изображений использовал такую процедуру. Но вопрос, где хранить изображения перед демонстрацией их в TImage? Создавать несколько MemoryStream?

procedure LoadWebImage(url: string; image: TBitmap);
var
  idhttp : TNetHTTPClient;
  ms : TMemoryStream;
begin
 IdHTTP := TNetHTTPClient.Create(nil);
  ms := TMemoryStream.Create;
  try

    idhttp.Get(url, ms);
    ms.Position := 0;
    image.LoadFromStream(ms);

  finally
    ms.Free;
    idhttp.Free;
  end;
end;

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

15 ответов на этот вопрос

  • 0

вместо TNetHttpClient вам нужен THttpClient

хотите - храните в TStream, хотите - в TBitmap

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
1 минуту назад, krapotkin сказал:

вместо TNetHttpClient вам нужен THttpClient

хотите - храните в TStream, хотите - в TBitmap

А как думаете, как лучше получить URL'ы? PHP пусть возвращает одной строкой и потом разбивать по разделителю?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

не понял вопроса. но в принципе вообще все равно. 
исходим из того, что запросы - медленные. а программа быстрая.

как выгоднее так и делаем

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Привет. Я не использовал такой путь. Организуйте свой проект.

procedure setLogo(ListView: TListView; code, url: string; id: Integer);
  var
   Cache: string;
   T: TThread;
 begin
   Cache := TPath.GetCachePath + '/AzerBoxPlus/Cache/';
   if not TFile.Exists(Cache + code + '.png') then
   begin
     T := TThread.CreateAnonymousThread(
     procedure
     var
       HTTP: TIdHTTP;
       MS: TMemoryStream;
     begin
       MS := TMemoryStream.Create;
       HTTP := TIdHTTP.Create(nil);
       try
         try
           HTTP.Get(url, MS);
           TThread.Synchronize(TThread.CurrentThread,
             procedure()
             begin
               ListView.Items[id].Bitmap.LoadFromStream(MS);
               MS.SaveToFile(Cache + code + '.png');
             end);
         except
           MS.Free;
         end;
       finally
         HTTP.Free;
		MS.Free;
		end;
     end);
     T.start;
   end else
   begin
     T := TThread.CreateAnonymousThread(
     procedure
     begin
       TThread.Synchronize(TThread.CurrentThread,
       procedure()
       begin
         ListView.Items[id].Bitmap.LoadFromFile(Cache + code + '.png');
       end);
     end);
     T.start;
   end;
 end;

setLogo(ListView, 'name', 'url', index);

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
18 часов назад, AliZairov сказал:

T := TThread.CreateAnonymousThread( procedure begin TThread.Synchronize(TThread.CurrentThread, procedure() begin ListView.Items[id].Bitmap.LoadFromFile(Cache + code + '.png'); end); end); T.start;

с учетом Thread и Synchronize  тут по сути написано

ListView.Items[id].Bitmap.LoadFromFile(Cache + code + '.png');

 

ENERGY понравилось это

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
14 часа назад, krapotkin сказал:

с учетом Thread и Synchronize  тут по сути написано

ListView.Items[id].Bitmap.LoadFromFile(Cache + code + '.png');

Я не до конца понимаю. Вы задали мне вопрос?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

нет. просто констатирую, что вместо этих 10 строк можно было оставить исходную одну

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
1 час назад, AliZairov сказал:

Я не до конца понимаю. Вы задали мне вопрос?

@AliZairov

Эта конструкция:

end else
   begin
     T := TThread.CreateAnonymousThread(
     procedure
     begin
       TThread.Synchronize(TThread.CurrentThread,
       procedure()
       begin
         ListView.Items[id].Bitmap.LoadFromFile(Cache + code + '.png');
       end);
     end);
     T.start;
   end;
 end;

равнозначна одной строчке (ее можно заменить:):

ListView.Items[id].Bitmap.LoadFromFile(Cache + code + '.png');

 

TThread.Synchronize - означает "остановить текущий поток, и запустить указанную процедуру в главном (GUI) потоке".

 

 

Еще один момент 

 

 

 except
    MS.Free;  << эта строка не нужна, т.к. код в finally будет выполнен при срабатывании исключения.
  end;
finally
  HTTP.Free;
  MS.Free;
end;

Если вам нужно загасить исключение - то можно сделать пустой блок, без кода. 

try 

except 

end;

Изменено пользователем ENERGY

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
В 19.05.2017 в 16:10, Anasazi сказал:

А как думаете, как лучше получить URL'ы? PHP пусть возвращает одной строкой и потом разбивать по разделителю?

Собрать массив на пхп и сделать json_encode, на стороне Делфи распарсить json и дальше грузить ссылки

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
11 час назад, ENERGY сказал:

равнозначна одной строчке (ее можно заменить:):

ListView.Items[id].Bitmap.LoadFromFile(Cache + code + '.png');

Это верно только в том случае, если мы заранее знаем, что процедура SetLogo будет всегда вызываться только из основного потока. Если что-то менять - я бы код

    T := TThread.CreateAnonymousThread(
     procedure
     begin
       TThread.Synchronize(TThread.CurrentThread,
       procedure()
       begin
         ListView.Items[id].Bitmap.LoadFromFile(Cache + code + '.png');
       end);
     end);
     T.start;

заменил бы следующим:

TThread.ForceQueue(TThread.CurrentThread,
  procedure()
  begin
    ListView.Items[id].Bitmap.LoadFromFile(Cache + code + '.png');
  end);

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
2 часа назад, dnekrasov сказал:

Это верно только в том случае, если мы заранее знаем, что процедура SetLogo будет всегда вызываться только из основного потока. 

Если так рассуждать, тогда нужно каждое обращение к элементу интерфейса облачать в ForceQueue конструкцию. "А вдруг с другого потока обратятся"?

Имхо "не следует множить сущности без необходимости".

Изменено пользователем ENERGY

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0
В 19.05.2017 в 14:05, AliZairov сказал:

Привет. Я не использовал такой путь. Организуйте свой проект.


procedure setLogo(ListView: TListView; code, url: string; id: Integer);

...

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

T := TThread.CreateAnonymousThread(
  procedure
  begin
    setLogo(ListView, 'name', 'url', index);
  end);
T.start;

Кстати, в этом случае, внутри нее можно вообще избавиться от CreateAnonymousThread

Изменено пользователем dnekrasov

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

@dnekrasov

Кстати у меня есть привычка, - методы, которые вызываются в отдельном потоке, к их именам обычно добавлю слово Thread. SetLogoThread. Очень рекомендую от путанницы.

Ну и если спорить дальше, то SetLogo не будет вызван в отдельном потоке, т.к. название метода уже намекает на GUI, а значит только главный поток, и анонимный поток внутри. :) 

 

 

Изменено пользователем ENERGY

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

@ENERGY

Хорошая привычка :). У меня тоже она есть, вот только слово - Operation :D.

Насчет вызова в отдельном потоке - была у меня недавно задачка: на всех открытых в данный момент окнах обновлять некую инфу с заданным интервалом. Так я её реализовал вызовом одной процедуры изнутри постоянно крутящегося потока. Но эту инфу надо было отобразить еще и при открытии формы - вот тогда мне очччень помог метод ForceQueue 

Кстати, для меня это не спор, а обыкновенный обмен опытом, ведь спорить о том как и что лучше реализовать в большинстве случаев бесполезно, а вот знать как реализовать ту или иную задачу разными способами - просто необходимо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
  • 0

Добрый вечер. Я использовал этот код для веб-телепроекта ABP. Были некоторые ошибки в коде он знает. Но, видя, полные необходимые процедуры. Мне нужно было, чтобы сделать эту систему из такой библиотеки. Picasso

5921c4936da2e_ScreenShot2017-05-21at20_47_09.png.d6c8093dced3feb177099152e5e98f55.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!


Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.


Войти сейчас

  • Похожие публикации

    • Автор: Роман Фил
      Привет ребят, созрел такой вопрос который меня мучает ! Вобщем пытаюсь загрузить картинку по прямой слыке с сервера. Картинка не грузится, не сохраняется не отображается. 
      Конечная платформа - Андроид. Пишу на Delphi xe 10 seatle.
      Что я делаю? при нажатии на сам компонент TImage (созданный динамически), должна грузится картинка по адресу преждевременно записанное в hint (TImage) при создании вида (http://блаблабла.jpg)
      Раньше код ниже работал сейчас нет не пойму что не так. Почему стал ковырять? потому что форма встает колом при загрузке изображений.
       
      var s: string; fs: TFileStream; begin fs := TFileStream.Create(tpath.Combine(tpath.GetDownloadsPath, 'load.jpg'), fmCreate); NetHTTPClient1.Get((Sender as TImage).Hint, fs); fs.Free; (Sender as TImage).MultiResBitmap.Bitmaps[1].LoadFromFile (tpath.Combine(tpath.GetDownloadsPath, 'load.jpg')); подключал еще pas нашел на этом форуме FMX.Features.Bitmap.Helpers.pas
      (Sender as TImage).MultiResBitmap.Bitmaps[1].LoadFromUrl ((Sender as TImage).Hint); как проще сделать посоветуете чтоб и грузилось и форма не висла?
    • Автор: ENERGY
      Как залить с Delphi Android в базу MySql строки, я примерно понял - составляем GET запрос и вставляем строки в параметры, затем считываем их в PHP скрипте и в базу.
      А вот как быть с картинкой. Как добавить картинку через PHP скрипт из программы на Android?
      POST запрос? Кто нибудь делал такое уже?
      Спасибо 
       
      P.s. На данный момент FireDAC не поддерживает работу с MySQL из под Android. Пока только SQLite и  InterBase ToGo. Даже если в будущем будет поддерживать, многие на этом форуме рекомендуют не использовать прямое подключение к базам из под мобильных систем, а использовать прямые GET запросы к примеру к PHP скриптам. Это связано с нестабильностью интернета т.к. так интернет может часто переключаться (от вышки к вышке) и менять параметры подключения. 
    • Автор: denprox
      Доброго времени суток! Подскажите, как узнать оригинальный размер картинки, загруженной в TImage ?
    • Автор: Илья Захаров
      Пишу приложение под iOS и Android... Создал базу данных на хостинге написал скрипты на PHP для получения данных. Пробовал GET запросом получить данные, возвращает пустые значения. Если через браузер смотреть то массивы данных возвращает правильно. Кто ни буть цепочки может написать как правильно это все реализовать.... Какие компоненты и какие статьи почитать... Заранее спасибо...
    • Автор: Илья Захаров
      Помогите пожалуйста, поделитесь информацией или примерчиком. Есть база данных MySQL на хостинге Макхост. Мне нужно для соединения,работы с ней использовать SSH протокол я не понимаю как это сделать... может в компонентах FireDAC есть какая ни будь фича?  
    • Автор: Anasazi
      Всем добрый день! Получаю координаты с помощью yandex api. Использую вот такой код:
          try
          ////Запрос на Яндекс для получения координат
           MainForm.NetHTTPClient1.Get
          ('https://geocode-maps.yandex.ru/1.x/?geocode='+
          'Кунгур'+
          ',+'
          +street+
          '+улица,+дом+'+
          house, Result);
          finally
          end;
       
      Код отрабатывает нормально, но если ну устройстве нет интернета, то приложение просто вылетает. Подскажите пожалуйста как поправить.
      Приложение для iOS.
    • Автор: netlink
      Коллеги, добрый день!
      Есть некий набор байт, который представляет собой пришедший через HTTP поток байт, который внутри JPEG.
      vImagesBytes: TBytes; Получаю, запихиваю это в MemoryStream
      vBMPMemoryStream := TMemoryStream.Create; try vMemoryStream.WriteData(vImagesBytes, Length(vImagesBytes)); vMemoryStream.Seek(0, TSeekOrigin.soBeginning);  
      Вопрос:
      как из стрима получить сначала JPEG, в потом конвертнуть его в BMP, чтобы загрузить в TBITMAP?
      Или есть более простой путь?
    • Автор: Rusland
      Как реализовать показ ProgressBar при загрузке фотографии на сервер? Интересует как именно определять сколько байт передано?
      Используется компонент NetHTTPClient.
    • Автор: Rusland
      Вроде видел где-то пример передачи через NetHTTPClient файла (*.png или *.jpg) на сервер, но не могу вспомнить где.
      Помогите с кодом отправки файла.
       
      PS. Инди компоненты не интересуют, не хочется их инспользовать
    • Автор: Satellite
      Возможно ли вывести 9-patch в Timage? Если нет, то куда можно импортировать изображение такого формата? 
  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу