Einzelnen Beitrag anzeigen

Popov
(Gast)

n/a Beiträge
 
#3

AW: Kann mir das einer mit ListBoxDrawItem und odFocused erklären

  Alt 15. Okt 2012, 18:22
Auf ein Neues. Ich hab mich den Problem noch Mal gewidmet, aber bin wieder gescheiter mit der Erklärung. Es geht um den Fokus in der ListBox. Das ist gepunktete Rahmen um den selektierten Item. Nicht die Hintergrundfarbe, sondern der Rahmen.

Meine Frage ist: wann und wie wird in einer Listbox der Fokus-Rand gezeichnet? Die Annahme, dass er zuerst in den OnDrawItem Prozedur gezeichnet wird, stimmt nicht mit den Beobachtungen. Würde er bereits gezeichnet in die OnDrawItem Prozedur kommen, würde FillRect ihn hier löschen:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  s: String;
  i, k: Integer;
begin
  ListBox1.Style := lbOwnerDrawFixed;
  {Inhalt generieren}
  for i := 0 to 10 do
    ListBox1.Items.Add(StringOfChar('a', 30));
end;

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  ListBox: TListBox;
begin
  ListBox := (Control as TListBox);

  if odSelected in State then
  begin
    ListBox.Canvas.Font.Color := clWindowText;
    ListBox.Canvas.Brush.Color := clSilver;
  end;

  //Löscht den Item-Canvas
  ListBox.Canvas.FillRect(Rect);

  //Textausgabe
  ListBox.Canvas.TextOut(Rect.Left + 2, Rect.Top, ListBox.Items[Index]);
end;
FillRect löscht den ganzen Canvas in Rect Bereich. Da müßte er theoretisch den Fokus mit löschen. Tut er aber nicht.

Hier noch mal das gleiche in grün, nur dieses Mal mit der Fokus-Lösch-Funktion (auch wenn es vor FillRect anzuordnen unsinnig ist, aber eben für den Test).

Delphi-Quellcode:
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  ListBox: TListBox;
begin
  ListBox := (Control as TListBox);

  if odSelected in State then
  begin
    ListBox.Canvas.Font.Color := clWindowText;
    ListBox.Canvas.Brush.Color := clSilver;
  end;

  //Überzeichnet den alten Fokus weg
  if odFocused in State then
    ListBox.Canvas.DrawFocusRect(Rect);

  //Löscht den Item-Canvas
  ListBox.Canvas.FillRect(Rect);

  //Textausgabe
  ListBox.Canvas.TextOut(Rect.Left + 2, Rect.Top, ListBox.Items[Index]);
end;
Fokus ist komplett da obwohl er zuerst gelöscht wurde und dann noch Canvas gelöscht wurde.

Hier ist DrawFocusRect nach FillRect und und vor der Textausgabe.

Delphi-Quellcode:
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  ListBox: TListBox;
begin
  ListBox := (Control as TListBox);

  if odSelected in State then
  begin
    ListBox.Canvas.Font.Color := clWindowText;
    ListBox.Canvas.Brush.Color := clSilver;
  end;

  //Löscht den Item-Canvas
  ListBox.Canvas.FillRect(Rect);

  //Überzeichnet den alten Fokus weg
  if odFocused in State then
    ListBox.Canvas.DrawFocusRect(Rect);

  //Textausgabe
  ListBox.Canvas.TextOut(Rect.Left + 2, Rect.Top, ListBox.Items[Index]);
end;
Der gepunktete Rand ist jetzt zwar um den selektierten Bereich weg, aber über und unter dem Text immer noch da.

Nun der letzte Versuch. Dieses mal ist DrawFocusRect die letzte Funktion und hinter der Textausgabe:

Delphi-Quellcode:
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  ListBox: TListBox;
begin
  ListBox := (Control as TListBox);

  if odSelected in State then
  begin
    ListBox.Canvas.Font.Color := clWindowText;
    ListBox.Canvas.Brush.Color := clSilver;
  end;

  //Löscht den Item-Canvas
  ListBox.Canvas.FillRect(Rect);

  //Textausgabe
  ListBox.Canvas.TextOut(Rect.Left + 2, Rect.Top, ListBox.Items[Index]);

  //Überzeichnet den alten Fokus weg
  if odFocused in State then
    ListBox.Canvas.DrawFocusRect(Rect);
end;
Hier ist der gepunktete Fokus-Rand komplett weg. Und ich stelle mit seit Monaten (nicht permanent, aber gelegentlich wieder) die Frage wieso. Die Lösung ist wahrscheinlich wieder mal ganz einfach, aber ich verstehe es nicht. Die Funktion die den Rand in der ListBox zeichnet ist wohl CNDrawItem. Und so wie ich die lese liefert sie die Anfangs-Einstellungen für OnDrawItem. Es sieht fast so aus als ob er nach den Ende noch mal gezeichnet wird. Wie gesagt, ist wahrscheinlich ganz einfache Erklärung, nur erkenne ich sie nicht.

Geändert von Popov (15. Okt 2012 um 18:25 Uhr)
  Mit Zitat antworten Zitat