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

Мультивопрос по мобильным платформам: хранение изображений, загрузка изображений из сети, правильная организация приложения (создание форм, фреймов, объектов)


Ivan B.

Вопрос

Всем привет!

Друзья, проконсультируйте по следующим вопросам:

1. Как правильно хранить изображения, которые используются в приложении: динамически размещаются в TImage, на кнопки, панели т .д.;

2. Приложение будет получать от сервиса текстовые и графические данные (base64) - куда временно записывать загруженные картинки, прежде, чем, к примеру, разместить их на панельки;

3. Как лучше всего (в плане производительности и вообще по "фен шую") организовать приложение, в котором должно быть много разных "окон" - создавать много форм? Может использовать фреймы? Или создавать все на одной форме?

Если несколько форм, то создавать эти формы с запуском приложения или создавать и уничтожать по мере необходимости (как правильно уничтожать и освобождать память?)

4. Как правильно организовать прорисовку создаваемых компонентов?

К примеру мне нужно создать на VertScrollBox много TPanel с TImage и TLabel, делаю это так:

Но прорисовка !первый раз происходит медленно. Это можно как-то ускорить?

И вообще правильно ли делаю, что использую массивы объектов?

это в отдельном потоке:

TThread.Synchronize(TThread.CurrentThread,
    PROCEDURE ()
      begin
        thVBox:=TVertScrollBox.Create(FMain.ATabs.Tabs[thTabNo]);
        thVBox.Parent:=FMain.ATabs.Tabs[thTabNo];
        thVBox.StyleLookup:='_scrollboxstyleWhite';
        thVBox.Align:=TAlignLayOut.Client;
      end);

For i:=0 to Count do
    BEGIN
       ... тут без графики, вычисление PosX и PosY

      TThread.Synchronize(TThread.CurrentThread,
        PROCEDURE ()
          begin
            vPanel[i]:=TPanel.Create(thVBox);
            vPanel[i].Parent:=thVBox;
            vPanel[i].StyleLookup:='_PanelStyleTile';
            vPanel[i].Width:=PanelW;
            vPanel[i].Height:=PanelH;
            vPanel[i].Position.X:=PosX;
            vPanel[i].Position.Y:=PosY;

            vShadowE:=TShadowEffect.Create(vPanel[i]);
            vShadowE.Parent:=vPanel[i];
            vShadowE.Distance:=3;
            vShadowE.Opacity:=0.2;
            vShadowE.Softness:=0.2;
            vShadowE.Enabled:=True;

            vImg[i]:=TImage.Create(vPanel[i]);
            vImg[i].Parent:=vPanel[i];
            vImg[i].Height:=Trunc(PanelH*ImageSizePercent);
            vImg[i].Margins.Left:=2;
            vImg[i].Margins.Right:=2;
            vImg[i].Margins.Top:=2;
            vImg[i].Align:=TAlignLayOut.Top;
            vImg[i].Bitmap:=pImageList.Bitmap(szImage,i);
            vImg[i].WrapMode:=TImageWrapMode.Fit;
            vImg[i].OnTap:=FMain.ConClick;

            vLblText[i]:=TLabel.Create(vPanel[i]);
            vLblText[i].Parent:=vPanel[i];
            vLblText[i].Height:=Trunc(PanelH*TextSizePercent);
            vLblText[i].Margins.Top:=3;
            vLblText[i].Margins.Left:=2;
            vLblText[i].Margins.Right:=2;
            vLblText[i].Align:=TAlignLayOut.Client;
            vLblText[i].StyledSettings:=
              vLblText[i].StyledSettings-[TStyledSetting.Family, TStyledSetting.Size,
                TStyledSetting.Style, TStyledSetting.FontColor, TStyledSetting.Other];
            vLblText[i].TextSettings.Font.Family:='Open Sans';
            vLblText[i].TextSettings.Font.Size:=12;
            vLblText[i].TextSettings.Font.Style:=[TFontStyle.fsBold];
            vLblText[i].TextSettings.HorzAlign:=TTextAlign.Leading;
            vLblText[i].TextSettings.VertAlign:=TTextAlign.Leading;
            vLblText[i].Text:=sText[i];
          end)
      end;
    END;

 

Заранее спасибо)!

 

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

Я бы сам присоединился к такому вопросу.
Советовать не стану, расскажу лишь как мы сделали.

35 минут назад, Ivan B. сказал:

1. Как правильно хранить изображения, которые используются в приложении: динамически размещаются в TImage, на кнопки, панели т .д.;

Иконки для кнопок, их цвета и прочее что относится к внешнему виду/интерфейсу мы вставили в стили, конкретнее - прямо на битмап темы приложения.
Изображения же, типа там фоток, примеров из "что нового" вставили в imageList, причем все используемые imageList вынесены в отдельный DataModule.

38 минут назад, Ivan B. сказал:

2. Приложение будет получать от сервиса текстовые и графические данные (base64) - куда временно записывать загруженные картинки, прежде, чем, к примеру, разместить их на панельки;

Мы получаем только текст и сразу парсим, соотв. храним в оперативке, нам нет смысла писать на диск. 

39 минут назад, Ivan B. сказал:

3. Как лучше всего (в плане производительности и вообще по "фен шую") организовать приложение, в котором должно быть много разных "окон" - создавать много форм? Может использовать фреймы? Или создавать все на одной форме?

Тут можно разводить холивары.

Мы перенесли опыт настольной разработки - создаем формы по мере необходимости. Плюс очевиден, но он же автоматически имеет и минус - когда вам эта форма понадобится, ее создание занимает время, и иногда это заметно.
В целом у нас одна главная форма с табконтролом и отключенными вкладками, по мере необходимости мы переключаем табы и их порядок, это позволяет анимировать переходы с одной "формы" т.е. вкладки на другую.

44 минуты назад, Ivan B. сказал:

(как правильно уничтожать и освобождать память?)

Ембаркадеро советует использовать object.DisposeOf() вместо object.Free() так и делаем. Минусов не обнаружили (или не заметили).

46 минут назад, Ivan B. сказал:

4. Как правильно организовать прорисовку создаваемых компонентов?

К примеру мне нужно создать на VertScrollBox много TPanel с TImage и TLabel, делаю это так:

Но прорисовка !первый раз происходит медленно. Это можно как-то ускорить?

Попробуйте поэкспериментировать с другими контролами, ListView или ListBox. Они все позволяют использовать стили для элементов списка (имхо, могу ошибаться).
Мы используем TListBox (что не рекомендуется данным форумом) и кидаем стили на элементы списка (лид сказал оставляем так, потом будем решать).

50 минут назад, Ivan B. сказал:

И вообще правильно ли делаю, что использую массивы объектов?

Ну, это не запрещено)))
Попробуйте дженерики, удобная фича. Пример нужен?

 

PS. это все имхо, я с удовольствием послушаю коллег.

Ссылка на комментарий
  • 0
25 минут назад, Barbanel сказал:

Я бы сам присоединился к такому вопросу.
...

Спасибо за ответ)

TabControl с отключенными вкладками, кстати, прикольная идея! Надо попробовать.

Я тоже уничтожаю методом DisposeOf(), пробегаясь по всем компонентам главного объекта. 

Попробую сегодня TListBox заполнять данными, может быстрее будет. Те панели, что создаю - конечно прикольно отрисовываются одна за другой, но долго

Стыдно, не не знаю, что такое дженерики - с удовольствием посмотрю пример

Ссылка на комментарий
  • 0
4 минуты назад, Ivan B. сказал:

Стыдно, не не знаю, что такое дженерики - с удовольствием посмотрю пример

По сути это TList, который возвращает вам не TObject, а сразу объект нужного типа.

type
    TMobBaseObject = class(TBaseObject);

...

var
    FItems : TObjectList<TMobBaseObject>;
    
...
var
    myObj : TMobBaseObject;
    i : integer;
begin
    FItems := TObjectList<TMobBaseObject>.Create;
    
    for i:=0 to 99 do
    begin
        myObj := TMobBaseObject.Create();
        myObj.SetProperties();
        FItems.add(myObj);
    end;
end;

...

var
    myObj : TMobBaseObject;
    i : integer;
begin
    for i:=0 to 99 do
      myObj := FItems[i];
end;

 

Ссылка на комментарий
  • 0

Не стыдитесь)

Мне как-то на собеседовании сказали: вы даже не знаете что такое дженерики, мы не будем с вами работать.
После этого придя домой я сразу же полез искать что это.

Каково же было мое разочарование, когда я узнал что это обертка над TList, не передать словами!!!

Изменено пользователем Barbanel
Ссылка на комментарий
  • 0

я наоборот, за фреймы. логику гораздо проще строить. Да и переключение форм свайпом вправо влево не сделать, например. Форм пара тройка достаточно.

По приведенному примеру - компоненты создавать в потоке - не только бесполезно но и вредно. 

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

про картинки и прочее - нужно понимать, что золотой пули нет. если вы превысите разумные пределы по памяти, ваше приложение грохнется. так что использовать файлы или нет - решение принимать по месту прописки

со скроллом - если разобраться с ListView, то достаточно несложно делать любые раскладки. одно, что приходится кодить, вместо привычного накидывания компонентов

Насчет DisposeOf. Уничтожение производится автоматически, поэтому вызывайте FreeAndNIL и не парьтесь. Только перед этим для компонентов например надо сделать Parent := NIL

Уничтожение не должно производиться вами. Деструктор будет вызыван без вас, когда вы затрете все ссылки на ваш объект.

Ссылка на комментарий
  • 0
9 часов назад, Ivan B. сказал:

это в отдельном потоке:

TThread.Synchronize(TThread.CurrentThread,
    PROCEDURE ()
      begin
        thVBox:=TVertScrollBox.Create(FMain.ATabs.Tabs[thTabNo]);
        thVBox.Parent:=FMain.ATabs.Tabs[thTabNo];
        thVBox.StyleLookup:='_scrollboxstyleWhite';
        thVBox.Align:=TAlignLayOut.Client;
      end);
.......

 

1 час назад, krapotkin сказал:

По приведенному примеру - компоненты создавать в потоке - не только бесполезно но и вредно. 

Полностью согласен с Krapotkin. Выделять отдельный поток только для создания визуальных компонентов не имеет смысла, так как синхронизацией вы все равно создаете их в главном потоке. Поток нужен для работы с данными или невизуальными компонентами, например THTTPClient, UDP, TCP и т.д.

К примеру, вот вариант загрузки картинок по http:

procedure TInitThread.Execute;
var HTTP: THTTPClient;
    Stream: TStringStream;
    i: shortint;
    success: boolean;
begin
        try
            try
                HTTP:=THTTPClient.Create;
                Stream:= TStringStream.Create('',TEncoding.ANSI);
                HTTP.Get('адрес www', stream);
                Stream.Position:=0;
                names.LoadFromStream(Stream);
                i:=names.Count;
                while i>0 do begin
                    try
                        setlength(images,length(images)+1);
                        images[length(images)-1]:=TBitMap.Create;
                        Stream.Clear;
                        HTTP.Get('адрес www'+names[i-1]+'.png',Stream);
                        Stream.Position:=0;
                        Synchronize(procedure begin images[length(images)-1].LoadFromStream(Stream); end);
                    except
                        images[length(images)-1]:=noname;
                    end;
                    names.Delete(i-1);
                    i:=i-2;
                end;
                success:=true;
            except
                names.Clear;
                success:=false;
            end;
        finally
            HTTP.Free;
            Stream.Free;
        end;
end;

Пример может немного корявый, но из него видно, что синхронизация используется только для загрузки данных в Bitmap, (и то потому что это код под 10.1 Berlin. Начиная с версии 10.2 битмапы тоже можно загружать в потоке), все остальное в синхронизации не нуждается.

 

1 час назад, krapotkin сказал:

я наоборот, за фреймы. логику гораздо проще строить. Да и переключение форм свайпом вправо влево не сделать, например. Форм пара тройка достаточно.

Прошу прощения за небольшой оффтоп (хотя это можно отнести к вопросу № 3), но как вы делаете переключение фреймов свайпом? Очень интересно

Ссылка на комментарий
  • 0

так PageControl же )) грубый вариант - это просто отлавливать жест и по окончанию жеста делать ActionNextTab

если повозиться - с помощью мгновенно изготовленного скриншота можно добиться эффекта свайпа для любого фрейма.

Ссылка на комментарий
  • 0
В 21.07.2018 в 06:31, krapotkin сказал:

так PageControl же )) грубый вариант - это просто отлавливать жест и по окончанию жеста делать ActionNextTab

если повозиться - с помощью мгновенно изготовленного скриншота можно добиться эффекта свайпа для любого фрейма.

Я не совсем понял идею со скриншотами.
Можно подробнее?

Ссылка на комментарий
  • 0

идея в том, что если сложная (+-) формочка, то она не очень предсказуемо скроллится. тогда мы можем сделать скриншот любого компонента, или всей формы в mouseDown

далее например так

выводим TImage c полученным скриншотом поверх всего

на заднем плане меняем фрейм или что там еще на новый

тем временем по mouseMove сдвигаем TImage. Получается эффект листания страницы как в читалке, но без применения TabControl

Изменено пользователем krapotkin
Ссылка на комментарий
  • 0
Только что, krapotkin сказал:

идея в том, что если сложная (+-) формочка, то она не очень предсказуемо скроллится. тогда мы можем сделать скриншот любого компонента, или всей формы в mouseDown

далее например так

выводим TImage поверх всего

на заднем плане меняем фрейм или что там еще на новый

тем временем по mouseMove сдвигаем TImage. Получается эффект листания страницы как в читалке, но без применения TabControl

Да это же гениально!!!

StateOfArt.jpg

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...