Перейти к содержанию
  • Регистрация
  • 0
rustam_d

Загрузка иконок в TimageList из файла

Вопрос

DelphiXE8, Android.

Задача: загрузить в ImageList иконки 32х32 из базы данных.

Проблема: Не получается Transparent никак.

Как обычно перелопатил кучу форумов и ссылок и человеко-часов (эх vcl отнял бы 1 минуту...),

и удалось написать тестовое приложение.

Однако прозрачность никак не работает...иконка, что в тесте в поставке делфи идет,

цвет розовый. В дизайне все ок, а вот самому...

Закомментировал то что не помогает всеравно, но хотел показать что пробовал ).

Проверяю результат по иконке что на кнопке через action.

Иконка норм отображается, но с ней и розовый цвет...

procedure TForm1.Button4Click(Sender: TObject);
var
  Layer: TLayer;
  c: TCustomSourceItem;
  b: TCustomBitmapItem;
  d: TCustomDestinationItem;
begin
  d := ImageList1.Destination.Add;
  Layer := ImageList1.Destination[d.Index].Layers.Add;
  Layer.SourceRect.Rect := TRectF.Create(0, 0, 32, 32);
  c := ImageList1.Source.Add;
  Layer.Name := c.Name;
  //c.MultiResBitmap.TransparentColor := TAlphaColorRec.Fuchsia;
  b := c.MultiResBitmap.Add;
  b.Bitmap.SetSize(32,32);
  b.Bitmap.LoadFromFile('C:\Delphi\Images\GlyFX\glyFX\Icons\Aero\BMP\32x32\eject_blue_32_h.bmp');
  //b.Bitmap.Clear(TAlphaColorRec.Fuchsia);
  Action2.ImageIndex := 3;
end;
 
 

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


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

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

  • 0

А что Вам мешает сделать сразу PNG-иконку с нужной прозрачностью, и подгружать ее, а не мучать TransparentColor и т.п.?

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


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

Прозрачность почему-то применяется только если загружать картинку через редактор MultiResBitmap.

Причем прозрачный цвет должен быть выбран до загрузки.

Похоже на очередной косяк разработчиков.

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


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

Друзья спасибо вам за оперативные ответы.

Начал юзать png вместо bmp и кажется все ок.

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

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


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

Причем прозрачный цвет должен быть выбран до загрузки.

Похоже на очередной косяк разработчиков.

 

Не похоже нет. См. демонстрационное видео https://www.youtube.com/watch?v=3voFs62PYl0&feature=youtu.be&t=260

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

Хотя параметры изображения действительно применяются только в момент загрузки. Потому, что это все-таки не фотошоп и исходник картинки не хранится в FMX. То, что попадает в FMX это часто результат обработки с потерей данных. Т.е. если исходное изображение 128x128 сначала сделать 16х16, а потом 32х32, то качество количество деталей будет как у 16х16. Поэтому цвет и размеры применяются только один раз в момент загрузки, что позволяет минимизировать потери.

В FMX-файле данные хранятся только в png-формате (во всяком случае на текущий момент).

Редактор в IDE использует функцию TCustomBitmapItem.CreateBitmap.

MultiresBitmap имеет свойства Width, Height, TransparentColorSizeKind. Каждый элемент этой коллекции MultiresBitmap имеет свойство FileName, Scale.

 

Функция CreateBitmap на основе этих данных создает TBitmap. Если она вернула не nil, то вы можете присвоить эту картинку элементу коллекции TMultiresBitmap.

 

Кактотак мы перегружаем все изображения.

        MultiresBitmap.BeginUpdate;
        try
          for I := 0 to TMultiresBitmap.Count - 1 do
          begin
            FmxBitmapSource := MultiresBitmap[I].CreateBitmap;
            try
              if Assigned(FmxBitmapSource) then
              begin
                MultiresBitmap[I].Bitmap.Assign(FmxBitmapSource);
              end
              else
              begin
                MultiresBitmap[I].Bitmap.SetSize(0, 0);
                MultiresBitmap[I].FileName := '';
              end;
            finally
              FreeAndNil(FmxBitmapSource);
            end;
          end;
        finally
          MultiresBitmap.EndUpdate;

Если у вас TransparentColor не clNone, то просто попиксельно заменяется указанный цвет на полностью прозрачный. Если TransparentColor = clDefault, то используется цвет нижней левой точки. Исходники CreateBitmap доступны, так что можете взять за основу, и сделать что-то подобное, если данные грузятся не из файла.

А что касается добавления картинок в TImageList, то можно посмотреть статью http://community.embarcadero.com/blogs/entry/timagelistxe8ru и демку, которая поставляется в составе Delphi, или взять её отсюда http://sourceforge.net/p/radstudiodemos/code/HEAD/tree/trunk/Object%20Pascal/FireMonkey%20Desktop/ImageList

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


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

 

Причем прозрачный цвет должен быть выбран до загрузки.

Похоже на очередной косяк разработчиков.

 

Не похоже нет. 

 

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

Убрать все лишнее, дестинейшн может быть и т.п., и оставить только нужное и правильное?

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


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

 

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

 

Убрать все лишнее, дестинейшн может быть и т.п., и оставить только нужное и правильное?

 

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

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


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

 

 

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

 

Убрать все лишнее, дестинейшн может быть и т.п., и оставить только нужное и правильное?

 

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

 

так это и есть тема сообщения...

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


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

Загрузка картинки будет выглядеть примерно так.

procedure TForm11.Button2Click(Sender: TObject);
const
  SourceName = 'Картинка';
  procedure LoadPicture(const Source: TCustomSourceItem; const Scale: Single; const FileName: string);
  var
    BitmapItem: TCustomBitmapItem;
    TmpBitmap: TBitmap;
  begin
    BitmapItem := Source.MultiResBitmap.ItemByScale(Scale, True, True);
    if BitmapItem = nil then
    begin
      BitmapItem := Source.MultiResBitmap.Add;
      BitmapItem.Scale := Scale;
    end;
    BitmapItem.FileName := FileName;
    TmpBitmap := BitmapItem.CreateBitmap;
    try
      if TmpBitmap <> nil then
        BitmapItem.Bitmap.Assign(TmpBitmap);
    finally
      TmpBitmap.Free;
    end;
  end;
var
  NewSource: TCustomSourceItem;
  NewDestination: TCustomDestinationItem;
  NewLayer: TLayer;
begin
  if ImageList1.Source.IndexOf(SourceName) = -1 then
  begin
    NewSource := ImageList1.Source.Add;
    NewSource.Name := SourceName;
    NewSource.MultiResBitmap.TransparentColor := TColorRec.Fuchsia;
    NewSource.MultiResBitmap.SizeKind := TSizeKind.Custom;
    NewSource.MultiResBitmap.Width := 16;
    NewSource.MultiResBitmap.Height := 16;
    LoadPicture(NewSource, 1, 'D:\Мои веселые картинки\Icons\16x16\alarm16.bmp');
    LoadPicture(NewSource, 1.5, 'D:\Мои веселые картинки\Icons\24x24\alarm24.bmp');
    NewDestination := ImageList1.Destination.Add;
    NewLayer := NewDestination.Layers.Add;
    NewLayer.SourceRect.Rect := TRectF.Create(TPoint.Zero, NewSource.MultiResBitmap.Width,
      NewSource.MultiResBitmap.Height);
    NewLayer.Name := SourceName;
    ControlAction1.ImageIndex := NewDestination.Index;
  end;
end;

Здесь как видно грузится деве картинки 16х16 и 24х24, при этом используются масштабы 1 и 1,5. После загрузки меняется свойство ImageIndex у действия ControlAction1. Загруженная картинка должна автоматом появится на всех кнопках, которые используют ControlAction1.
 

 

post-64-0-43178800-1441382242.png

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


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

Одно выглядит странным: метод CreateBitmap объекта BitmapItem создает битмап в никуда лишь для того, чтобы программист потом вручную запихивал этот битмап обратно в BitmapItem)

 

Да и св-во TransparentColor, которое учитывается лишь в одном методе, а в остальных случаях его изменение ничего не дает и лишь сбивает с толку...

Может просто в CreateBitmap еще один параметр добавить? 

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

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


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

Может просто в CreateBitmap еще один параметр добавить? 

Фил я кстати тоже так подумал ))))

 

Исправил в своем коде ТОЛЬКО ОДНУ строку и тогда транспарент заработал (чудеса FMX):

 

  b.Bitmap.Assign(b.CreateBitmap('C:\Delphi\Images\GlyFX\glyFX\Icons\Aero\BMP\32x32\eject_blue_32_h.bmp'));
 
и даже удалил b.Bitmap.SetSize(32,32);
 
Сергей, в любом случае вы помогли спасибо!
Но мой код по мне куда проще и короче...
 
Вообщем вот готовый простейший код
 
procedure TForm1.Button1Click(Sender: TObject);
var
  Layer: TLayer;
  c: TCustomSourceItem;
  b: TCustomBitmapItem;
  d: TCustomDestinationItem;
begin
  d := ImageList1.Destination.Add;
  Layer := ImageList1.Destination[d.Index].Layers.Add;
  Layer.SourceRect.Rect := TRectF.Create(TPoint.Zero, 32, 32);
  c := ImageList1.Source.Add;
  Layer.Name := c.Name;
  c.MultiResBitmap.TransparentColor := TAlphaColorRec.Fuchsia;
  b := c.MultiResBitmap.Add;
  b.Bitmap.Assign(b.CreateBitmap('C:\Delphi\Images\GlyFX\glyFX\Icons\Aero\BMP\32x32\arrow_left_32_h.bmp'));
  Button2.ImageIndex := 0;
end;
 

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


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

и еще может кому сгодиться, если в БД картинки не меняли, то логично, что их не зачем загружать.

Для этого я просто сохраняю компонент ImageList в файл. Если есть лучше решения, то критика приветствуется!


    //сохраняем компонент ImageList в файл
    vStream := TFileStream.Create(TPath.GetDocumentsPath + '/imagelist',fmCreate);
    try
      vStream.WriteComponent(imgMain);
    finally
      vStream.Free;
    end;


    //загружаем файл в компонент ImageList
    vStream := TFileStream.Create(TPath.GetDocumentsPath + '/imagelist',fmOpenRead);
    try
      vStream.ReadComponent(imgMain);
    finally
      vStream.Free;
    end;

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


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

 

Может просто в CreateBitmap еще один параметр добавить? 

 

...
  b.Bitmap.Assign(b.CreateBitmap('C:\Delphi\Images\GlyFX\glyFX\Icons\Aero\BMP\32x32\arrow_left_32_h.bmp'));
...
 
      vStream.WriteComponent(imgMain);
 

1. TransparentColor еще и хранится в fmx файле, и используется редактором IDE. На что недвусмысленно намекает документация по TransparentColorCreateBitmap используется в редакторе изображений, она создает картинку по указанным параметрам, её можно и по своему усмотрению использовать, допустим вывести окошко и спросить "а действительно ли вы хотите добавить именно такую картинку". Почему используются свойства а не параметры функции? Ну потому, что заточена она для массовой загрузки нескольких однотипных изображений, скорее всего у них будут одинаковые параметры. P.S. Хотя в общем и целом принял к сведению возникшее затруднение, постараюсь как-нибудь упростить.

2. CreateBitmap создало картинку. Assign скопировало данные из этой картинки. А исходная картинка созданная CreateBitmap осталась в памяти и ссылки на неё нету.

3. В вашем примере сохраняется и загружается вся коллекция + разная служебная информация, что не добавляет скорости. Лучше бы сохранять и загружать сами битмапы из Source.MultiResBitmap с использованием LoadFromFile, SaveToFile (как в первом примере). Это будут файлы родные png и они будут грузится системными API функциями с максимальной скоростью. А CreateBitmap использовать только при первой загрузке чтобы cмасштабировать и сконвертировать в png. Хотя и так тоже можно, но я бы не стал.  B)

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


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

 

 

Может просто в CreateBitmap еще один параметр добавить? 

 

...
  b.Bitmap.Assign(b.CreateBitmap('C:\Delphi\Images\GlyFX\glyFX\Icons\Aero\BMP\32x32\arrow_left_32_h.bmp'));
...
 
      vStream.WriteComponent(imgMain);
 

3. В вашем примере сохраняется и загружается вся коллекция + разная служебная информация, что не добавляет скорости. Лучше бы сохранять и загружать сами битмапы из Source.MultiResBitmap с использованием LoadFromFile, SaveToFile (как в первом примере). Это будут файлы родные png и они будут грузится системными API функциями с максимальной скоростью. А CreateBitmap использовать только при первой загрузке чтобы cмасштабировать и сконвертировать в png. Хотя и так тоже можно, но я бы не стал.  B)

 

что то не догнал...вот так просто взял и SaveToFile??? а для чего я тогна танцы с бубнами делаю с Destination ? Он что как то стороной проходит?

Т.е. я беру и без всяких танцев с дестинанэйшн сразу Source.MultiResBitmap.LoadFromFile ?

вы уверены? хм...

А если вы про загрузку каждой картинки отдельно, то не вариант, мне же индексировать где то надо...

да и если собьется индекс то уже и не те картинки на кнопках...причем на многих...неее, мне 300% уверенность нужна.

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 9/17/2015 в 18:08, rustam_d сказал:

А если вы про загрузку каждой картинки отдельно, то не вариант, мне же индексировать где то надо...да и если собьется индекс то уже и не те картинки на кнопках...причем на многих...неее, мне 300% уверенность нужна.

 

Да, я про загрузку каждой картинки в отдельности в Source.

В 9/17/2015 в 05:02, RoschinSpb сказал:

 постараюсь как-нибудь упростить.

В RAD Studio 10.1 Berlin (Version 24.0) появились методы TSourceCollection.AddOrSet и TCustomImageList.AddOrSet
Как мне кажется смысл параметров довольно очевиден и не требует дополнительных пояснений.

    function AddOrSet(const SourceName: string; const Scales: array of Single; const FileNames: array of string;
      const TransparentColor: TColor = TColors.SysNone; const Width: Integer = 0;
      const Height: Integer = 0): TCustomSourceItem;

 

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 04.09.2015 в 19:00, RoschinSpb сказал:

Загрузка картинки будет выглядеть примерно так.

А вот вариант загрузки из этихвашихинтернетов из сети по заданному URL

procedure TForm2.Button2Click(Sender: TObject);
const
  SourceName = 'Картинка';
  function LoadPicture(const SourceName: string; const Scale: Single; const URL: string): TCustomSourceItem;
  var
    HTTPClient: TNetHTTPClient;
    Stream: TMemoryStream;
    TmpBitmap: TBitmap;
    BitmapItem: TCustomBitmapItem;
  begin
    Result := nil;
    Stream := nil;
    TmpBitmap := nil;
    HTTPClient := TNetHTTPClient.Create(nil);
    try
      Stream := TMemoryStream.Create;
      HTTPClient.Get(URL, Stream);
      Stream.Position := 0;
      TmpBitmap := TBitmap.Create;
      TmpBitmap.LoadFromStream(Stream);
      if (TmpBitmap.Width > 0) and (TmpBitmap.Height > 0) then
      begin
        Result := ImageList1.Source.Add;
        Result.Name := SourceName;
        Result.MultiResBitmap.TransparentColor := TColorRec.Fuchsia;
        Result.MultiResBitmap.SizeKind := TSizeKind.Source;
        Result.MultiResBitmap.Width := Round(TmpBitmap.Width / Scale);
        Result.MultiResBitmap.Height := Round(TmpBitmap.Height / Scale);
        BitmapItem := Result.MultiResBitmap.ItemByScale(Scale, True, True);
        if BitmapItem = nil then
        begin
          BitmapItem := Result.MultiResBitmap.Add;
          BitmapItem.Scale := Scale;
        end;
        BitmapItem.Bitmap.Assign(TmpBitmap);
      end;
    finally
      HTTPClient.Free;
      TmpBitmap.Free;
      Stream.Free;
    end;
  end;
var
  NewSource: TCustomSourceItem;
  NewDestination: TCustomDestinationItem;
  NewLayer: TLayer;
begin
  if ImageList1.Source.IndexOf(SourceName) = -1 then
  begin
    NewSource := LoadPicture(SourceName, 1,
     'http://voy.dk/wp-content/uploads/2010/06/Avril-lavigne-13thebestdamnthingmarkliddellshootnhy5_122_131lo-779x1024.jpg');
    NewDestination := ImageList1.Destination.Add;
    NewLayer := NewDestination.Layers.Add;
    NewLayer.SourceRect.Rect := TRectF.Create(TPoint.Zero, NewSource.MultiResBitmap.Width,
      NewSource.MultiResBitmap.Height);
    NewLayer.Name := SourceName;
    Button1.ImageIndex := NewDestination.Index;
  end;
end;

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

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


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

Не нашел я к сожалению в этой и других ветках простой код для добавления TBitmap в ImageList без лишних элементов. Все приходиться делать самому: 

Helper для ImageList

type
  TImageListHelper = class helper for TImageList
    function Add(aBitmap: TBitmap): integer;
  end;

function TImageListHelper.Add(aBitmap: TBitmap): integer;
const
  SCALE = 1;
var
  vSource: TCustomSourceItem;
  vBitmapItem: TCustomBitmapItem;
  vDest: TCustomDestinationItem;
  vLayer: TLayer;
begin
  Result := -1;
  if (aBitmap.Width = 0) or (aBitmap.Height = 0) then exit;

  // add source bitmap
  vSource := Source.Add;
  vSource.MultiResBitmap.TransparentColor := TColorRec.Fuchsia;
  vSource.MultiResBitmap.SizeKind := TSizeKind.Source;
  vSource.MultiResBitmap.Width := Round(aBitmap.Width / SCALE);
  vSource.MultiResBitmap.Height := Round(aBitmap.Height / SCALE);
  vBitmapItem := vSource.MultiResBitmap.ItemByScale(SCALE, True, True);
  if vBitmapItem = nil then
  begin
    vBitmapItem := vSource.MultiResBitmap.Add;
    vBitmapItem.Scale := Scale;
  end;
  vBitmapItem.Bitmap.Assign(aBitmap);

  vDest := Destination.Add;
  vLayer := vDest.Layers.Add;
  vLayer.SourceRect.Rect := TRectF.Create(TPoint.Zero, vSource.MultiResBitmap.Width,
      vSource.MultiResBitmap.Height);
  vLayer.Name := vSource.Name;
  Result := vDest.Index;
end;

 

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

После этого можно обращаться к любому ImageList 

ImageList1.Add(MyBitmap);

 

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

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


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

Использование Tag, как бы намекает ;) Не стоит скрывать свойство TCustomSourceItem.Name от пользователя, пусть сам заботится об уникальности (не такая уж это большая проблема). Это свойство может быть использовано для предотвращения случайной повторной загрузки, допустим если есть картинка с указанным названием поднимать исключение. На случай, если нужно заменить имеющуюся картинку, можно добавить метод AddOrReplace.


Успехов :)

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


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

@RoschinSpb

Цитата

Использование Tag, как бы намекает ;) Не стоит скрывать свойство TCustomSourceItem.Name от пользователя, пусть сам заботится об уникальности (не такая уж это большая проблема).

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

 

Цитата

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

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

 

У Delphi есть широкий выбор разнообразных списков, очередей, cтэков, массивов, деревьев и никогда в них не использовались имена. Для идентификации и унификации всегда использовалось число-индекс. У этого подхода гораздо больше плюсов, чем у строковых идентификаторов, почему решили отойти от этого стандарта, не понимаю...

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

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


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

по идее нужно было молча заменить картинку.

Это смотря какая идея. В некоторых случаях уместно заменить, в некоторых это неуместно, или недопустимо. Например у Вас процедура инициализации (которая загружает сотню картинок) в процессе долгой разработки она перемещалась из OnShow в OnCreate потом в OnActivate где-то забыли удалить вызов и теперь эта процедура вызывается два раза. Допустим в приложении появилась вторая, третья, N+1 форма. Я не знаю отнаследовалась она, или просто скопипастилась, или Вы что-то добавили в Design-Time, так или иначе есть ненулевая вероятность получить неоднократное добавление одного и того же. Ситуация ошибочная и хорошо бы как-то об этом узнать, такая вот идея у меня была. В Вашем случае и не заменит и не предупредит об ошибке, т.е. потенциально имеем утечку ресурсов.

Вы бы смогли догадаться, что изображено на этих картинках без доп. описания? Картинки конечно неважные, но в коде-то Вы их вообще не видите.

SmallImages.png.b9cdf747f3ea7fb0188bdc0e519da4dd.png

В итоговой коллекции обращение идет всё равно по номеру, потому, что соображения совместимости важнее удобства, но во всяком случае есть возможность найти картинку по человекопонятному описанию например:

ImageList1.Source.IndexOf('я');

ImageList1.Destination[0].Layers[0].Name;

Надеюсь, я внес некоторое понимание.

Кстати, при добавлении новой картинки по умолчанию у неё и так имеется уникальное имя вида "Item 0", "Item 1" и т. д.

procedure TForm2.Button1Click(Sender: TObject);
begin
  Button1.Text := ImageList1.Source.Add.Name;
end;

 

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

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


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

Вы бы смогли догадаться, что изображено на этих картинках без доп. описания? Картинки конечно неважные, но в коде-то Вы их вообще не видите.

Имена можно было ввести, но опционально (description) - нужно юзеру, - добавил.  Не нужно ну и не надо.

В большинстве случаев описание не нужно. А те кому это нужно, обычно хранят это в своих структурах, в отдельном списке, где можно кроме описания, сохранить и др. параметры (путь к файлу, адрес итд).

А сейчас это обязательный идентификатор, который, имхо, усложняет работу со списком..

 

Цитата

Допустим в приложении появилась вторая, третья, N+1 форма. Я не знаю отнаследовалась она, или просто скопипастилась, или Вы что-то добавили в Design-Time, так или иначе есть ненулевая вероятность получить неоднократное добавление одного и того же

Ну и что, это задача уже ложиться на программиста, причем здесь ImageList.

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

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


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

А сейчас это обязательный идентификатор, который, имхо, усложняет работу со списком..

Еще раз обращаю внимание: обязательный идентификатор инициализируется значением по умолчанию. Если не видите в нем смысла (это вовсе не значит что его нет), ни кто Вас не заставляет его использовать, по сути он и является опциональным.

function TImageListHelper.Add(aBitmap: TBitmap; const AName: string = ''): integer;
...
begin
...
  vSource := Self.Source.Add;
  if AName <> '' then
    vSource.Name := AName;

Использование Tag мало того, что просто дурной тон, оно еще и лишнее и снижает базовую функциональность.

 

Цитата

это задача уже ложиться на программиста, причем здесь ImageList.

С тем же успехом спрошу, а при чем здесь StringList, здесь больше уместна аналогия с TComponent.Name. Я Вам привел конкретные примеры зачем оно может использоваться (а может и не использоваться). Вы приводите гипотетические версии, что можно было бы сделать, конечно можно всё, можно даже заполнять список рандомными данными, но какой в этом практический смысл.

И вообще мне странно, что Вы сначала жалуетесь, на излишнюю сложность и уже на следующей строке перекладываете на программиста куда более сложную задачу (формировать отдельные списки/структуры). В подавляющем большинстве случаев пользователь формирует коллекцию в DesignTime и не углубляется в дебри. Если же речь идет о динамической загрузке, это почти всегда что-то нестандартное, тут уже возможны всякие варианты (заменять, поднимать исключение, делать еще что-нибудь, не делать ни чего), но почти всегда важно застраховаться от повторной загрузки, или случайного перетирания одного изображения другим. И здесь могут помочь "человеческие" названия. В сложном приложении порядок загрузки может легко и непринужденно поменяться.

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


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

@RoschinSpb

Цитата

Еще раз обращаю внимание: обязательный идентификатор инициализируется значением по умолчанию.   по сути он и является опциональным.

По сути он как раз является обязательным, потому что при добавлении картинки в список в runtime, нужно указывать уникальное имя, притом в двух местах. Было бы классно, если бы компонент сам создавал это имя (в Runtime), конечно было бы удобней если имя было представлено как необязательное поле Description.

Цитата

Использование Tag мало того, что просто дурной тон, оно еще и лишнее и снижает базовую функциональность.

Ну без Tag пришлось бы вводит переменную-счетчик в класс текущей формы, что имхо только усложняет. А если форм несколько?
Использовать глобальную переменную, тоже вариант, но это же костыль, такой же как и тэг. А если используются костыли, в таком простой случае, значит что-то не так..

Цитата

И вообще мне странно, что Вы сначала жалуетесь, на излишнюю сложность и уже на следующей строке перекладываете на программиста куда более сложную задачу (формировать отдельные списки/структуры).

Это имя нужно только компоненту TImageList. А юзеру чтобы отличать картинки в DesignTime в ImageList достаточно посмотреть на картинку. В остальных случаях - обращение через индексы.

Туда не запишешь какое то серьезное описание. Как вы представляете это? Одни значения для обрабатываемой картинки (размер, имя, разрешение, и многое др.) храним и читаем со специально созданного для этого класса, а описание\имя читаем с ImageList?

Это же не удобно и запутает. Плюс ImageList находится в юните GUI, где только GUI код,

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

Плюс обычно если программисту нужно хранить описание картинки или имя, то оно должны быть writeable. А в ImageList  оно readonly.

Имхо это велосипед, явно усложняющий работу.

Цитата

 а при чем здесь StringList, здесь больше уместна аналогия с TComponent.Name.

Какая разница какой тип данных содержит список - строки, картинки - это просто data куски лежащие в памяти. 

Цитата

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

Есть определенные стандарты написания похожих компонентов, втч. это и имена методов (Add, Remove, Insert etc),  имхо разработчикам следовало бы держаться стандартов Delphi для списков, к которым за годы все привыкли.

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

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


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

 Было бы классно, если бы компонент сам создавал это имя (в Runtime)

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

procedure TForm2.Button1Click(Sender: TObject);
begin
  // Добавляем новый элемент в колекцию ImageList1.Source
  // И присваиваем тексту кнопки имя свежесозданного элемента
  Button1.Text := ImageList1.Source.Add.Name;
end;

  vSource := Self.Source.Add; // Здесь безо всякого Tag имеем уникальное имя vSource.Name
  if AName <> '' then // Если задали какоето своё имя AName то, присваиваем его, если такое имя уже есть, получаем исключение
    vSource.Name := AName;
  // Если не задали своё имя оставляем как есть
  // В любом случае дальше используем vSource.Name

Но, как я понял, мои ответы отправляются в пустоту без попыток осмысления... <_<

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


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

Но, как я понял, мои ответы отправляются в пустоту без попыток осмысления

Я все внимательно читаю, просто думал вы про Design Time говорите.

Исправил на вариант без тэга.

Но имя все равно используется чтобы идентифицировать слой, но уже стало гораздо легче :)

 vDest := Self.Destination.Add;
  vLayer := vDest.Layers.Add;
  vLayer.SourceRect.Rect := TRectF.Create(TPoint.Zero, vSource.MultiResBitmap.Width,
      vSource.MultiResBitmap.Height);
  vLayer.Name := vSource.Name;
  Result := vDest.Index;

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

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


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

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

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

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

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

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

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

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

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


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

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

×
×
  • Создать...