• 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;

 

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

 

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


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

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

  • 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
1 час назад, Barbanel сказал:

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

Control.Makescreenshot

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


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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

StateOfArt.jpg

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

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

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

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

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