9

フォーカスされた/選択されたリストボックス項目を Office XP スタイルで表示する最もシンプルでクリーンな方法は何ですか?

アイデアをより明確に示すために、このサンプル画像を参照してください。

ここに画像の説明を入力

lbOwnerDrawFixedListbox Style を に設定するか、またはlbOwnerDrawVariableOnDrawItem イベントを変更する必要があると思いますか?

これは私が立ち往生している場所です。そこにどのコードを書くべきかよくわかりません。これまでのところ、私は試しました:

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
  with (Control as TListBox).Canvas do
  begin
    if odSelected in State then
    begin
      Brush.Color := $00FCDDC0;
      Pen.Color   := $00FF9933;
      FillRect(Rect);
    end;

    TextOut(Rect.Left, Rect.Top, TListBox(Control).Items[Index]);
  end;
end;

私はそれがうまくいかないことを知っているべきです、私はあらゆる種類のファンキーなことが起こっています:

ここに画像の説明を入力

私は何を間違っていますか、さらに重要なことに、それを機能させるために何を変更する必要がありますか?

ありがとう。

4

2 に答える 2

13

さまざまな状態のアイテムをペイントするのを忘れました。アイテムが現在どのような状態にあるかを判断し、それに従って描画する必要があります。

あなたがあなたの写真に持っているものは、この方法で得ることができます. ただし、複数選択を有効にして複数のアイテムを選択している場合、これはうまくいきません。

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;

そして、ItemHeight16に設定した結果:

ここに画像の説明を入力

ボーナス - 連続選択:

これは、連続選択を実装するトリッキーなソリューションです。原則として、以前と同じようにアイテムを描画しますが、アイテムの境界の上下の線を、前後のアイテムの選択状態に応じた色の線で上書きします。それ以外は、現在のアイテムの外でもレンダリングする必要があります。これは、アイテムの選択によって隣接するアイテムが自然に再描画されるわけではないためです。したがって、水平線は、現在のアイテム境界の 1 ピクセル上と 1 ピクセル下に描画されます (これらの線の色は、相対的な選択状態にも依存します)。

ここで非常に奇妙なのは、アイテム オブジェクトを使用して各アイテムの選択状態を保存していることです。ドラッグ アンド ドロップ項目の選択を使用する場合Selected、マウス ボタンを離すまで、プロパティは実際の状態を返さないためです。幸いなことに、OnDrawItemイベントはもちろん実際の状態で発生するため、回避策として、OnDrawItemイベントからこれらの状態を保存することを使用しました。

重要:

項目オブジェクトを使用して実際の選択状態を保存していることに注意してください。項目オブジェクトを別の目的で使用している場合は、この実際の状態をブール値の配列などに保存してください。

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;

そして結果:

ここに画像の説明を入力

于 2012-08-12T13:39:57.073 に答える
2

関数に渡される State 変数の値を確認する必要があります。これにより、アイテムが選択されているかどうかがわかるので、ブラシとペンを適切に設定できます。

于 2012-08-12T12:24:35.063 に答える