Zapomniałeś pomalować elementy dla różnych stanów. Musisz określić, w jakim stanie jest aktualnie przedmiot i zgodnie z nim go narysować.
To, co masz na swoim zdjęciu, możesz zdobyć w ten sposób. Jednak to nie wygląda dobrze, jeśli masz włączone wielokrotny i wybrać więcej niż jeden przedmiot:
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
var
Offset: Integer;
begin
with (Control as TListBox) do
begin
Canvas.Font.Color := Font.Color;
if (odSelected in State) then
begin
Canvas.Pen.Color := $00FF9932;
Canvas.Brush.Color := $00FDDDC0;
end
else
begin
Canvas.Pen.Color := Color;
Canvas.Brush.Color := Color;
end;
Canvas.Rectangle(Rect);
Canvas.Brush.Style := bsClear;
Offset := (Rect.Bottom - Rect.Top - Canvas.TextHeight(Items[Index])) div 2;
Canvas.TextOut(Rect.Left + Offset + 2, Rect.Top + Offset, Items[Index]);
end;
end;
a wynik z ItemHeight
zestaw do 16:
Bonus - ciągłą selekcję :
Oto podstępne rozwiązanie wdrażające ciągły wybór. Zasada polega na tym, aby narysować element jak poprzednio, a następnie przeciągnąć górną i dolną linię przedmiotu liniami koloru w zależności od stanu wyboru poprzedniego i następnego elementu. Poza tym, musi być wyrenderowany również poza bieżącym elementem, ponieważ wybór elementu nie wywołuje w sposób naturalny przedmiotów sąsiednich, które mają zostać przemalowane. W związku z tym linie poziome są malowane o jeden piksel powyżej i jeden piksel poniżej bieżących granic elementu (kolory tych linii zależą również od względnych stanów wyboru).
Dość dziwne jest tutaj użycie obiektów przedmiotów do przechowywania wybranego stanu każdego elementu. Zrobiłem to, ponieważ podczas korzystania z opcji rozwijanej przeciągnij &, właściwość Selected
nie zwraca stanu rzeczywistego, dopóki nie zwolnisz przycisku myszy. Na szczęście zdarzenie OnDrawItem
wywołuje oczywiście stan rzeczywisty, więc jako obejście używam przechowywania tych stanów ze zdarzenia OnDrawItem
.
Ważne:
Zauważ, że używam obiektów element do przechowywania stanu faktycznego wyboru, więc należy być ostrożnym, a gdy używasz przedmiotów pozycja dla czegoś innego, przechowywać ten rzeczywisty stwierdza np do tablicy Boolean.
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
const
SelBackColor = $00FDDDC0;
SelBorderColor = $00FF9932;
var
Offset: Integer;
ItemSelected: Boolean;
begin
with (Control as TListBox) do
begin
Items.Objects[Index] := TObject((odSelected in State));
if (odSelected in State) then
begin
Canvas.Pen.Color := SelBorderColor;
Canvas.Brush.Color := SelBackColor;
Canvas.Rectangle(Rect);
end
else
begin
Canvas.Pen.Color := Color;
Canvas.Brush.Color := Color;
Canvas.Rectangle(Rect);
end;
if MultiSelect then
begin
if (Index > 0) then
begin
ItemSelected := Boolean(ListBox1.Items.Objects[Index - 1]);
if ItemSelected then
begin
if (odSelected in State) then
begin
Canvas.Pen.Color := SelBackColor;
Canvas.MoveTo(Rect.Left + 1, Rect.Top);
Canvas.LineTo(Rect.Right - 1, Rect.Top);
end
else
Canvas.Pen.Color := SelBorderColor;
end
else
Canvas.Pen.Color := Color;
Canvas.MoveTo(Rect.Left + 1, Rect.Top - 1);
Canvas.LineTo(Rect.Right - 1, Rect.Top - 1);
end;
if (Index < Items.Count - 1) then
begin
ItemSelected := Boolean(ListBox1.Items.Objects[Index + 1]);
if ItemSelected then
begin
if (odSelected in State) then
begin
Canvas.Pen.Color := SelBackColor;
Canvas.MoveTo(Rect.Left + 1, Rect.Bottom - 1);
Canvas.LineTo(Rect.Right - 1, Rect.Bottom - 1);
end
else
Canvas.Pen.Color := SelBorderColor;
end
else
Canvas.Pen.Color := Color;
Canvas.MoveTo(Rect.Left + 1, Rect.Bottom);
Canvas.LineTo(Rect.Right - 1, Rect.Bottom);
end;
end;
Offset := (Rect.Bottom - Rect.Top - Canvas.TextHeight(Items[Index])) div 2;
Canvas.Brush.Style := bsClear;
Canvas.Font.Color := Font.Color;
Canvas.TextOut(Rect.Left + Offset + 2, Rect.Top + Offset, Items[Index]);
end;
end;
A wynik:
Nie sądzę, istnieje taki rodzaj skrzynki lista motywem wyboru. W polu listy znajdują się części '' LBCP_ITEM'] (http://msdn.microsoft.com/en-us/library/windows/desktop/bb(v = vs.85) .aspx), ale wyglądają dokładnie tak samo, jak pole listy wykreślone przez właściciela - nudne. Może więc możesz pożyczyć części tematyczne do wyboru, np. z widoku drzewa opisanego przez Andrew w ['this post'] (http://stackoverflow.com/a/10936108/960757). Będziesz tylko musiał zmodyfikować ten kod dla stanów pola listy. – TLama
Właśnie o to się martwiłem, w przeciwieństwie do widoku drzewa i listview, które malują sekcje tematyczne, których nie robi Listbox. –
W przypadku intensywnego kodowania kolorów nie należy zapominać, że użytkownik może mieć zupełnie inny schemat kolorów. –