AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Kann mir das einer mit ListBoxDrawItem und odFocused erklären
Thema durchsuchen
Ansicht
Themen-Optionen

Kann mir das einer mit ListBoxDrawItem und odFocused erklären

Ein Thema von Popov · begonnen am 14. Feb 2012 · letzter Beitrag vom 15. Okt 2012
Antwort Antwort
Popov
(Gast)

n/a Beiträge
 
#1

Kann mir das einer mit ListBoxDrawItem und odFocused erklären

  Alt 14. Feb 2012, 16:06
Wieder mal etwas wo ich 'ne viertel Stunde meines Lebens damit vergeudet habe, weil ich etwas schon zig mal gemacht habe und wo es dieses mal plötzlich nicht klappt.

Und zwar geht es drum den Fokus aus der ListBox zu entfernen, was ich übrigens schon einige Male gemacht habe. Anscheinend nur zufällig richtig.

Überschreibe ich den Fokus mit DrawFocusRect vor Canvas.TextRect, bleibt er sichtbar, mache ich es danach, ist er weg. Anscheinend zeichnet TextRect den Fokus. Nur steht in der OH nichts von einem Flag der das bewirkt. Weiß einer mehr?
Delphi-Quellcode:
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
  with (Control as TListbox) do
  begin
    //if odFocused in State then Canvas.DrawFocusRect(Rect); //klappt nicht

    Canvas.TextRect(Rect, Rect.Left, Rect.Top, Items[Index]);
    
    if odFocused in State then Canvas.DrawFocusRect(Rect); //klappt
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin //Beispielfüllung
  ListBox1.Style := lbOwnerDrawFixed;
  for i := 0 to 10 do
    ListBox1.Items.Add(DateTimeToStr(Now));
end;
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#2

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

  Alt 17. Feb 2012, 01:23
Ich habe mir die StrCtrls angeguckt, genauer das:

Delphi-Quellcode:
procedure TCustomComboBox.CNDrawItem(var Message: TWMDrawItem);
var
  State: TOwnerDrawState;
begin
  with Message.DrawItemStruct^ do
  begin
    State := TOwnerDrawState(LongRec(itemState).Lo);
    ...
    if odFocused in State then DrawFocusRect(hDC, rcItem);
    FCanvas.Handle := 0;
  end;
end;
Was mich wundert ist, dass ich odFocused in State zum Beginn von ListBox OnDrawItem lösche. Trotz dem wird FocusRect gezeichnet.
  Mit Zitat antworten Zitat
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
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

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

  Alt 15. Okt 2012, 19:10
Tstststs ... anstatt stundenlang die Haare zu raufen und irgendwas auszuprobieren, hätten ein paar gezielte Strg-Clicks auf DrawFocusRect zunächst hierhin gebracht:
Delphi-Quellcode:
unit Vcl.Graphics;
...
procedure TCanvas.DrawFocusRect(const Rect: TRect);
begin
  Changing;
  RequiredState([csHandleValid, csBrushValid]);
  Winapi.Windows.DrawFocusRect(FHandle, Rect);
  Changed;
end;
Dann hierhin:
Delphi-Quellcode:
unit Winapi.Windows;
...
function DrawFocusRect; external user32 name 'DrawFocusRect';
Und schließlich hierhin: MSDN: DrawFocusRect function
Und was finden wir da?
Zitat von MSDN: DrawFocusRect function:
Because DrawFocusRect is an XOR function, calling it a second time with the same rectangle removes the rectangle from the screen.
Aha, damit ist also auch geklärt, warum das explizite Löschen des Canvas eher kontraproduktiv als hilfreich ist
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Popov
(Gast)

n/a Beiträge
 
#5

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

  Alt 15. Okt 2012, 19:35
Nun, ich gebe zu, dass ich mir alles angeguckt habe, nur nicht die DrawFocusRect Funktion. Hielt ich nicht für nötig.

Trotzdem sehe ich hier nicht die Antwort auf meine Verwirrung. Vielleicht sehe ich es einfach nur nicht. Das DrawFocusRect Xor zeichnet ist mir klar und auch, dass ein erneutes Zeichnen es wieder löscht. Das habe ich ja auch gemacht. In einem der Beispiel habe ich es vor FillRect gemacht, dann mal danach und zuletzt ganz am Ende.

Wie auch, nach meinem Verständnis sollte von dem Rahmen schon in den ersten Beispielen nichts mehr übrig sein.

Oder habe ich dich missverstanden?
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

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

  Alt 15. Okt 2012, 19:41
Das sich 2x XOR aufhebt, funktioniert nur dann, wenn ich das, was das erste XOR verändert hat, vor dem 2. XOR nicht verändere.

Das hast du aber immer gemacht (mit FillRect, TextRect, etc.)

Darum ist es am sichersten alles auf den Canvas zu klatschen, ganz am Ende DrawFocusRect (ja, den Rahmen malen lassen) und das Control macht auch nochmal DrawFocusRect und schwupps ist der Rahmen weg
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:03 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz