Ну идея такова... На форму бросаем ImageList и ListView...Связываем их Дальше ищем файлы и заполняем список путей...
| Код | var TumbPath: TStringList; //глобальный лист //-------------------------- procedure GetPathsToTumbs(Dir: string; ras: string); //Dir - путь к папке, Ras - соответственно расширение формата ('*.jpg') var f : TSearchRec; i : integer; s : string; begin i := FindFirst(Dir+ras, faAnyFile, f); while (i=0) do begin s := Dir+f.Name; TumbPath.Add(s); i := FindNext(f); Application.ProcessMessages; end; FindClose(f); end;
|
Дальше я создавал пустой список в ЛистеВьюве:
| Код | var //глобальная TerminateFlag: boolean; //Если флаг поднят, занчит тормазим все что тормазиться...
//............................ procedure CreateEmptyItem(); //Создаем пустой список var ListItem: TListItem; i: integer; begin with Form1 do begin for i := 0 to TumbPath.Count -1 do begin if TerminateFlag then exit; //Т.к. процесс может быть давольно длительный, при смени фокуса прерываем опирацию....
Application.ProcessMessages;
ListItem := ListView1.Items.Add; ListItem.Caption := GetDirNameFromPath(TumbPath.Strings[i]); //Здесь просто заполняется капшен итемов именами файлов ListItem.ImageIndex := -1; //говорим что картинки пока нету end; //for end;//with end;
|
Дальше немного сложнее, т.к. я писал это все на GDI+
| Код | uses GDIPAPI, GDIPOBJ; //.......................
procedure FillImg(); var graphics : TGPGraphics; //основной санвас Image, pThumbnail: TGPImage; //полная картинка, и тумблс (минисатюра/эскиз) к ней b: TBitmap; //Это мы будем запихивать в имиджлист path: string; //путь к файлу R: TRect; //область x, y, i: integer; //x,y - для размещения по центру begin for i:= 0 to TumbPath.Count-1 do begin if TerminateFlag = true then exit; Application.ProcessMessages; b := TBitmap.Create; b.Width := 130; //размеры эскизов b.Height := 130;
graphics := TGPGraphics.Create(b.Canvas.Handle); try path := TumbPath[i]; //получаем путь из ранее заполненного списка Image:= TGPImage.Create(path);
R := GetProportional(Image.GetWidth, Image.GetHeight, 128, 128); //рассчитываем пропорциональную область pThumbnail := Image.GetThumbnailImage(R.Right, R.Bottom, nil, nil); //получаем миниатюрку
x := Trunc((130-R.Right)/2); //определяем координаты левого верхнего угла картинки, y := Trunc((130-R.Bottom)/2); //для размещения по центру
Graphics.SetSmoothingMode(SmoothingModeHighSpeed); //устанавливаем качество сжатия //Graphics.SetCompositingQuality(CompositingQualityHighSpeed);
Graphics.DrawImage(pThumbnail, x, y, pThumbnail.GetWidth, pThumbnail.GetHeight); //непосредственно рисуем миниатюрку на битмапе
//это просто рисует прямоугольник во круг картинки b.Canvas.LineTo(0,128); b.Canvas.LineTo(128,128); b.Canvas.LineTo(128,-128); b.Canvas.MoveTo(0,0); b.Canvas.LineTo(128,0);
Form1.TumbnailsList.Add(b, nil); //добавляем в наш имиджлист полученный маленький битмап Form1.ListView1.Items[i].ImageIndex := i; //(*) пробегаем по нашему ListViev-у и устанавливаем картинки для нашего пустого списка finally //не забываем почистица Image.Free; b.Free; pThumbnail.Free; graphics.Free; end; end; end;
|
В общем то за счет использования GDI+ код довольно шустро работает даже на нескольких сотнях файлов, к тому же он адекватно переваривает *.bmp, *.dib, *.jpeg/*.jpg, *.emf, *.wmf, *.gif, *.tif/tiff, *.png, *.ico (*) Вот этот код надо вынести в OnAdvancedCustomDrawItem и подгружать только те картинки которые в данный момент на экране...Откровенно говоря я просто не нашел последний вариант...
З.Ы.: Я не стал выносить код в отдельный поток, ради сохранения производительности. Хотя конечно в потоке это было бы правильней. З.З.Ы.: Если использовать код как есть, то есть минусы: - Во время формирования есть артифакты в виде подрагивания - Приходиться отслеживать смену дирректории в рантайме Но есть и плюсы: - После формирования, скроллинг проходит без артифактов - Есть возможность создавать картинки любого размера
В аттаче скрин с проекта |