TCheckListBox - problem z usuwaniem itemów o zmiennej wysokości

0

Piszę program, w którym wykorzystuję komponent z klasy TCheckListBox z ustawionym stylem na lnOwnerDrawVariable; Wszystko wszło gładko (ustawianie wysokości poszczególnych itemów, malowanie itd), ale problem pojawił się podczas usuwania zaznaczonych itemów;

Otóż lista wygląda podczas działania programu mniej więcej tak:

ListBeforeDelete.png

Ale jeśli usunę kilka item'ów zostaje zmieniona wysokość niektórych (nie określę dokładniej których) zmienia się, gdzie rysowany tekst znacznie wykracza poza rect'a itema, np. tak:

ListAfterDelete.png

Czy ktoś wie dlaczego tak się dzieje i jak można temu zaradzić? Usuwanie realizuję przez prostą pętlę:

var
  I: Integer;
begin
  { po sprawdzeniu warunków }
  for I := List.Items.Count - 1 downto 0 do
    if List.Checked[I] then
      List.Items.Delete[I];

  {...}

Z niczym nie mam problemu, tylko z usuwaniem zaznaczonych itemów;

1

A w jaki sposób ustawiasz wysokość poszczególnych itemów ? Pewnie po usunięciu musisz to "refreshnąć" dla wszystkich, które pozostały (i są na pozycji n i większej, gdzie n to usuwany element)

0
[losowa nazwa] napisał(a)

A w jaki sposób ustawiasz wysokość poszczególnych itemów ?

Najpierw wczytuję odpowiednie dane do macierzy rekordowej z pliku; Później obliczam ilość linii samej notatki (pod datą i godziną) i jeśli jest większa niż 10 to ustawiam tylko 10 linii + ostatnia stanowiąca wartość ..., żeby nie przekroczyć wysokości komponentu; To samo tyczy się szerokości - jeśli dana linia notatki jest zbyt długa - obcinam ją i dodaję ...; Wielkość jest przydzielana dynamicznie tylko i wyłącznie na podstawie ilości linii notatki i offset'ów przed i po niej; Wysokość jest zawsze taka jaką chcę dla każdych item'ów, tylko po usuwaniu jest problem;

A tak na marginesie, korzystałem z metody AddObject(), ale najpierw przydzielana jest wielkość dla item'ów, a później alokowana jest pamięć dla dodawanego obiektu; Jak sprzężyłem tą metodę z MesaureItem dostawałem zawsze AccessViolation, bo obiekt nie został jeszcze utworzony;

Sama metoda Refresh() (czy Repaint()) nic nie dają; Spróbuje dostać się do odświeżania pojedynczego itemu i spróbować tak jak piszesz; Tyle, że nie mogę tego zrobić dla wybranych, bo usuwanie oparte jest o checkbox'y obok itemów; Tak więc mogę usunąć wiele (multiselect), w tym pierwszy i ostatni; Ale nic nie stoi na przeszkodzie odświeżyć każdy item z osobna po kolei już po usunięciu zaznaczonych;


Nie mam zielonego pojęcia jak odświeżyć pojedynczy item...


Napisałem sobie tak na szybko mały programik wykorzystujący ten styl (w załączniku pliki projektu oraz gotowy exe'k dla tych co nie mają kompilatora) i muszę powiedzieć, że podczas usuwania nie dzieją się takie rzeczy... Błąd gdzieś musi być w moim programie, choć nie sądzę, żebym coś przeskrobał;

Ustalanie wysokości item'a realizowane jest takim algorytmem:

type
  TNoteLinesArr = array of String;
type
  TNoteInfoRec = record
    DateTime: TDateTime;
    Note: ShortString;
  end;
type
  TNoteInfoArr = array of TNoteInfoRec;

{...}

type
  TNotesListForm = class(TForm)
  {...}
  private
    aNoteInfo: TNoteInfoArr;
  {...}
  end;

procedure TNotesListForm.ExtractNoteLines(Note: ShortString; var LinesArr: TNoteLinesArr);
var
  iLastSepIndex, I: Word;
begin
  case Length(Note) of
    0: Exit;
  else
    Note := Note + #10;
    iLastSepIndex := 1;

    for I := 1 to Length(Note) do
      if Note[I] = #10 then
        begin
          SetLength(LinesArr, Length(LinesArr) + 1);
          LinesArr[High(LinesArr)] := Copy(Note, iLastSepIndex, I - iLastSepIndex);
          iLastSepIndex := I + 1;
        end;
  end;
end;

{...}

procedure TNotesListForm.lbNotesListMeasureItem(Control: TWinControl; Index: Integer; var Height: Integer);
var
  aNoteLines: TNoteLinesArr;
begin
  SetLength(aNoteLines, 0);
  ExtractNoteLines(aNoteInfo[Index].Note, aNoteLines);

  if Length(aNoteLines) > 10 then
    begin
      SetLength(aNoteLines, 11);
      aNoteLines[10] := '...';
    end;

  Height := 48 + Length(aNoteLines) * 15; 
end;

I za pierwszym razem podczas tworzenia itemów rysowanie przebiega bez problemów, ale po usunięciu kilku rysowanie sypie się;

1

Muszę przeprosić, ale rozwiązanie znalazło się...

Wszystko działa bardzo dobrze (poprawnie), ale zapomniałem podczas usuwania item'a z listy także usunąć pole z macierzy aNoteInfo, przez co po usunięciu pierwszego z listy i tak jest jego tekst wyświetlany, który oczywiście nie będzie pasował do przydzielonej powierzchni;

Temat uważam za zamknięty, dziękuję za zainteresowanie;

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