Bạn quên vẽ các mục cho các trạng thái khác nhau. Bạn cần xác định trạng thái hiện tại của mục và theo đó vẽ nó.
Những gì bạn có trên ảnh của mình, bạn có thể nhận được theo cách này. Tuy nhiên điều này không có vẻ tốt nếu bạn đã kích hoạt multiselect và chọn nhiều hơn một mục:
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;
Và kết quả với ItemHeight
thiết lập để 16:
Bonus - lựa chọn liên tục :
Đây là một giải pháp phức tạp thực hiện lựa chọn liên tục. Nguyên tắc là để vẽ các mục như trước nhưng sau đó overdraw của đường biên giới hàng đầu và dòng dưới cùng với các dòng của một màu sắc tùy thuộc vào trạng thái lựa chọn của các mục trước đó và tiếp theo. Ngoại trừ điều đó, phải được trả lại bên ngoài mục hiện tại, vì việc chọn mục không tự nhiên gọi các vật phẩm lân cận được sơn lại. Vì vậy, các đường ngang được vẽ một pixel ở trên và một pixel bên dưới giới hạn mục hiện tại (màu của các dòng này cũng phụ thuộc vào trạng thái lựa chọn tương đối).
Khá lạ ở đây là việc sử dụng các đối tượng mục để lưu trữ trạng thái đã chọn của từng mục. Tôi đã làm điều đó, bởi vì khi sử dụng kéo lựa chọn mục thả &, thuộc tính Selected
không trả về trạng thái thực cho đến khi bạn nhả nút chuột. May mắn thay, sự kiện OnDrawItem
tất nhiên sẽ xảy ra với trạng thái thực, do đó, như một giải pháp thay thế, tôi đã sử dụng lưu trữ các trạng thái này từ sự kiện OnDrawItem
.
Chú ý:
Thông báo, mà tôi đang sử dụng các đối tượng mục để lưu trữ trạng thái lựa chọn thực tế, vì vậy hãy cẩn thận, và khi bạn đang sử dụng đối tượng mục cho cái gì khác, lưu trữ thực tế này tiểu bang ví dụ vào một mảng 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;
Và kết quả:
Tôi không nghĩ rằng có loại đó của một hộp danh sách theo chủ đề lựa chọn. Có các phần ['LBCP_ITEM'] (http://msdn.microsoft.com/en-us/library/windows/desktop/bb(v = vs.85) .aspx) cho hộp danh sách, nhưng chúng trông giống hệt như hộp danh sách không được chủ sở hữu rút ra - nhàm chán. Vì vậy, có thể bạn có thể mượn các phần lựa chọn theo chủ đề, ví dụ: từ chế độ xem dạng cây như Andrew được mô tả trong ['bài đăng này'] (http://stackoverflow.com/a/10936108/960757). Bạn sẽ chỉ cần sửa đổi mã đó cho các trạng thái hộp danh sách. – TLama
Đây là những gì tôi đã lo lắng về, không giống như Treeview và Listview mà sơn theo chủ đề lựa chọn các Listbox không. –
Khi màu mã hóa cứng, đừng quên rằng người dùng có thể có một bảng phối màu hoàn toàn khác. –