Witajcie w świąteczny dzień
Mam pytanie
Jak pomalować ListBoxa
Za pomocą SelectDirectory wczytuje do niego pliki za pomocą buutonClick raz to z jednego folderu raz za pomocą drugiego butona także z pod folderów przez wyszukiwanie określonego typu plików
Jak pomalować tło w Listboxie by pliki z każdego folderu miały osobne tło na przemiennie dwa kolory np.: zielony i żółty.
pliki z folderu A zielone tło
pliki z folderu B żółte tło
pliki z folderu C zielone tło
pliki z folderu D żółte
i tak w kółko
musisz oprogramować zdarzenie OnDrawItem listboxa.
Poniższy przykład pokazuje w jaki sposób można uzyskać naprzemienne ,dwukolorowe, malowanie listboxa
procedure TFFileListView.ListBox1DrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState);
var
Flags: Longint;
Data: String;
listbox: TListBox;
begin
listbox := TListBox(Control);
if not(odselected in State) then
if index mod 2 = 0 then
listbox.Canvas.Brush.Color := clmoneygreen
else
listbox.Canvas.Brush.Color := clskyblue;
listbox.Canvas.FillRect(Rect);
if Index < listbox.Count then
begin
Flags := DrawTextBiDiModeFlags(DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX);
if not UseRightToLeftAlignment then
Inc(Rect.Left, 2)
else
Dec(Rect.Right, 2);
Data := listbox.Items[index];
DrawText(listbox.Canvas.Handle, Data, Length(Data), Rect, Flags);
end;
end;
Inny przykład, tym razem z metodą Canvas.TextOut
:
procedure TForm1.ListBox1DrawItem(AControl: TWinControl; AIndex: Integer; ARect: TRect; AState: TOwnerDrawState);
const
BACK_COLORS: array [Boolean, Boolean] of TColor = (($FFFFFF, $CD6F36), ($EEEEEE, $CD6F36));
FONT_COLORS: array [Boolean] of TColor = ($000000, $FFFFFF);
var
LBox: TListBox absolute AControl;
begin
LBox.Canvas.Brush.Color := BACK_COLORS[Odd(AIndex), odSelected in AState];
LBox.Canvas.FillRect(ARect);
LBox.Canvas.Font.Color := FONT_COLORS[odSelected in AState];
LBox.Canvas.TextOut(ARect.Left + 4, ARect.Top + 1, LBox.Items[AIndex]);
end;
Efekt:
Kolory w macierzach ze stałych sobie dostosuj.
@furious programming:
kolejnym problemem będzie dynamiczne budowanie macierzy , ponieważ nie wiadomo jaki będzie wymiar macierzy czyli liczba różnych folderów , Samą liczbę folderów można wyliczyć i umieścić unikalne nazwy folderów w tablicy albo liście , ale i tak wtedy trzeba by też mieć tablicę(listę) kolorów o wymiarze nie mniejszym niż liczba plików i tym samym trzeba by ją budować dynamicznie , albo wyliczać '.color' (int) 'online' wg jakiegoś algorytmu, np w oparciu indeks folderu w tablicy albo liście .folderów
marya:
pliki z folderu A zielone tło
pliki z folderu B żółte tło
pliki z folderu C zielone tło
pliki z folderu D żółte
i tak w kółko
Ja tutaj widzę tylko dwa kolory - na przemian żółty i zielony, bez względu na liczbę katalogów.
@furious programming:
:))) Level God, dzięki :)) no cóż.... tak już mam :)
a na poważnie, to aby naprzemiennie pokolorować listboxa wg folderów to powiązanie koloru wiersza z indeksem (aindex) w listboxie nie wystarczy
LBox.Canvas.Brush.Color := BACK_COLORS[Odd(AIndex), odSelected in AState]
Z pewnością listbox musi być posortowany , tak aby nazwy plików z tego samego folderu sąsiadowały ze sobą i każdemu wierszowi listboxka trzeba przypisać kolor po zapełnieniu lisboxka, można by do tego celu użyć obiektu podpiętego pod każdy element listy 'items'
Widzę, że oboje zrozumieliśmy problem... Wszystkie pliki z danego katalogu mają być tego samego koloru, w taki sposób, aby w komponencie było widać, że załadowane nazwy plików są pogrupowane; W takim razie podejdźmy do problemu z innej strony;
Metoda wyszukująca pliki mp3
powinna podczas dodawania nazwy pliku do listy, dodawać również magic value
, która to posłuży metodzie malującej pozycje w komponencie; Metoda ładująca nazwy plików powinna używać metody AddObject
, a w miejsce referencji obiektu wrzucać tę dodatkową informację;
Czyli metoda ładująca może wyglądac tak:
procedure TMainForm.LoadMP3Files(const APath: String; ABox: TListBox);
procedure InternalLoadMP3Files(const APath: String; var AMagic: Integer);
var
LEntry: TSearchRec;
begin
if FindFirst(APath + '*.mp3', faAnyFile, LEntry) = 0 then
try
repeat
ABox.Items.AddObject(APath + LEntry.Name, TObject(AMagic));
until FindNext(LEntry) <> 0;
finally
FindClose(LEntry);
end;
if FindFirst(APath + '*', faDirectory, LEntry) = 0 then
try
repeat
if (LEntry.Attr and faDirectory <> 0) and (LEntry.Name[1] <> '.') then
begin
AMagic += 1;
InternalLoadMP3Files(APath + LEntry.Name + '\', AMagic);
end;
until FindNext(LEntry) <> 0;
finally
FindClose(LEntry);
end;
end;
var
LMagic: Integer = 0;
begin
InternalLoadMP3Files(APath, LMagic);
end;
Natomiast kod zdarzenia OnDrawItem
wiele by się nie zmienił:
procedure TMainForm.CPlaylistDrawItem(AControl: TWinControl; AIndex: Integer; ARect: TRect; AState: TOwnerDrawState);
const
BACK_COLORS: array [Boolean, Boolean] of TColor = (($FFFFFF, $CD6F36), ($EEEEEE, $CD6F36));
FONT_COLORS: array [Boolean] of TColor = ($000000, $FFFFFF);
var
LBox: TListBox absolute AControl;
begin
LBox.Canvas.Brush.Color := BACK_COLORS[Odd(Integer(LBox.Items.Objects[AIndex])), odSelected in AState];
LBox.Canvas.FillRect(ARect);
LBox.Canvas.Font.Color := FONT_COLORS[odSelected in AState];
LBox.Canvas.TextOut(ARect.Left + 4, ARect.Top + 1, LBox.Items[AIndex]);
end;
Ewentualnie można dorzucić dodatkowe zmienne, coby skrócić linijki:
var
LBox: TListBox absolute AControl;
LIsOdd, LIsSelected: Boolean;
begin
LIsOdd := Odd(Integer(LBox.Items.Objects[AIndex]));
LIsSelected := odSelected in AState;
LBox.Canvas.Brush.Color := BACK_COLORS[LIsOdd, LIsSelected];
LBox.Canvas.FillRect(ARect);
LBox.Canvas.Font.Color := FONT_COLORS[LIsSelected];
LBox.Canvas.TextOut(ARect.Left + 4, ARect.Top + 1, LBox.Items[AIndex]);
end;
W ten sposób, dla poniższej struktury plików i katalogów:
+ C:
+ Sound
- First.mp3
- Second.mp3
+ Bald
- First.mp3
- Second.mp3
+ Bar
- First.mp3
- Second.mp3
- Third.mp3
+ Baz
- First.mp3
- Second.mp3
- Third.mp3
+ Foo
- First.mp3
- Second.mp3
- Third.mp3
oraz poniższego wywołania:
LoadMP3Files('C:\Sound\', CPlaylist);
otrzymamy poniższy efekt:
Na powyższym zrzucie, żadna pozycja nie jest zaznaczona; Gdyby była, jej tło było by niebieskie, tak jak w poprzednim moim przykładzie (bez względu na tło pozycji niezaznaczonej, ta zaznaczona zawsze będzie niebieska).
@furious programming:
pomysł z aMagic
jest świetny :) ale Twój algorytm ma jedną małą lukę. Inkrementujesz amagic
przy każdym wywołaniu procedury InternalLoadMP3Files
.Jeśli w którymś z podfolderów nie będzie żadnego pliku pasującego do wzorca to nic nie zostanie dodane do listboxa a pliki z sąsiadujacych ze sobą w listboxsie folderów bedą miały taką samą parzystość i tym samym ten sam kolor.
amagic
należy ikrementować tylko wtedy kiedy w folderze znaleziono przynajmniej jeden plik pasujący do wzorca
procedure Listamp3(const APath: String; AFilesList: TStrings);
procedure internalListamp3(const APath: String; AFilesList: TStrings; aMagic: integer);
var
fileload: TSearchRec;
intIsAnyFile: integer;
begin
intIsAnyFile := 0;
if FindFirst(APath + '*.mp3', faAnyFile, fileload) = 0 then
try
repeat
AFilesList.Addobject(APath + fileload.Name, tobject(aMagic));
intIsAnyFile := 1;
until FindNext(fileload) <> 0;
finally
FindClose(fileload);
end;
if FindFirst(APath + '*.*', fadirectory, fileload) = 0 then
try
repeat
if (fileload.Name <> '.') and (fileload.Name <> '..') then
begin
aMagic := aMagic + intIsAnyFile;
internalListamp3(APath + fileload.Name + '\', AFilesList, aMagic);
end;
until FindNext(fileload) <> 0;
finally
FindClose(fileload);
end;
end;
begin
internalListamp3(APath, AFilesList, 0);
end;
@grzegorz_so: dzięki za fix - faktycznie taką okoliczność przeoczyłem... :]