Malowanie pozycji Listboxa na przemian dwoma kolorami

0

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

3

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

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:

box.png

Kolory w macierzach ze stałych sobie dostosuj.

0

@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

0
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.

0

@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'

2

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:

playlist.png

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).

1

@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;
0

@grzegorz_so: dzięki za fix - faktycznie taką okoliczność przeoczyłem... :]

1 użytkowników online, w tym zalogowanych: 0, gości: 1