[delphi] Mysterisch rond DrawFocusRect

Pagina: 1
Acties:
  • 120 views sinds 30-01-2008
  • Reageer

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
Misschien kan iemand mij vertellen wat er toch met deze functie is. In alle Delphi-jaren van m'n leven heb ik nog nooit gesnopen wat deze functie nou ingesteld moet hebben om tot een goed resultaat (een blauwe rand met gele puntjes, in geval van standaard windows kleurtjes) te komen.

Aanleiding van deze post is een owner-drawn combobox, waarin ik een paar lijntjes teken. Een combobox die line-styles weergeeft dus. Het moest er zo uit zien als in Word, dus de selectie moet wit zijn, met een blauw randje en daaromheen weer die focus-rand.

Dat ging goed, als ik aan het einde van de OnDrawItem de TComboBox(Control).Canvas.Brush.Color op clHighlight zet. Maar als ik zo'n item selecteer, dan komt er een solide gele lijn ipv de gestippelde lijn (dus bij odComboBoxEdit in State) :?

Bleek dat als ik TComboBox(Control).Canvas.Brush.Color op clHighlight zet, vóórdat ik de linestyle teken (een combinatie van een Pen.Style instellen en een of twee calls naar PolyLine), dat gaat dat weer wel goed, maar de selectie in de dropdown weer niet...

Dus nogmaals: wat moet je instellen om DrawFocusRect een goeie focusrect te laten tekenen?

日本!🎌


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

DrawFocusRect tekent niet in kleuren, maar neemt het nagatieve van de onderstaande kleur. In het geval van blauw is dat geel. Als je ook 2x een DrawFocusRect achterelkaar doet zie je m niet meer.

Volgensmij is de enige vereiste dat Canvas.Brush.Style op bsSolid moet staan. De kleur maakt volgensmij niet uit, maar anders zou ik kiezen voor Canvas.Brush.Color op clOlive.

We adore chaos because we like to restore order - M.C. Escher


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
Toch vreemd dan dat het uitmaakt of ik Brush.Color ergens op instel. En of ik daarna nog PolyLine aanroep... Maar nou vraag ik me nog steeds af waarom DrawFocusRect een solide lijn zou tekenen, want soms gebeurt dat dus...

日本!🎌


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Dat heeft waarschijnlijk te maken met de Brush.Style, als ik mag gokken. Ik heb zelf eigenlijk nooit problemen met die functie.

We adore chaos because we like to restore order - M.C. Escher


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 27-05 15:56

Tomatoman

Fulltime prutser

DrawFocusRect is inderdaad nogal ondoorgrondelijk. De functie gebruikt een XOR-bewerking om de focus rectangle te tekenen. Het unieke aan XOR-bewerking is dat hij weer ongedaan kan worden gemaakt door precies dezelfde XOR-bewerking. Anders gezegd:

<iets> xor <iets anders> xor <iets anders> = <iets>

Als je twee focus rectangles over elkaar heen laat tekenen, gebeurt er daar door per saldo helemaal niets. Nu tekenen veel controls uit zichzelf al een focus rectangle, maar pas nadat jij je custom painting hebt gedaan. Er verschijnt daardoor bijvoorbeeld alsnog een focus rectangle, terwijl je die zelf helemaal niet hebt getekend. De oplossing is simpel. Je tekent gewoon eerst zelf een focus rectangle met DrawFocusRect en daarna doet de control het zelf nog eens dunnetjes over. Resultaat: de ene rectangle wist de andere uit, zodat er per saldo geen focus rectangle zichtbaar is.

Wil je dat de (custom-drawn) items in een TListBox nooit een focus rectangle laten zien, dan kan dat vrij eenvoudig.
Delphi:
1
2
3
4
5
6
7
8
procedure TForm1.ListBox1DrawItem(Control: TWinControl;
  Index: Integer; Rect: TRect; State: TOwnerDrawState);
begin
  { If focused, the listbox will also draw a focus rectangle. Both together
    will result in no focus rect. }
  if (odFocused in State) and (odSelected in State) then
    ListBoxAnswers.Canvas.DrawFocusRect(Rect);
end;

Als je een heel vlak een beetje blauw wilt laten lijken, zodat het helemaal geselecteerd lijkt, dan zul je zelf iets moeten klussen.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
type
  TForm1 = class(TForm1)
    ListBox1: TListBox;
    procedure ListBox1DrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
  private
    procedure EmphasizeListBoxItem(State: TOwnerDrawState;
      BlendColor: TColor);
  end;

procedure TForm1.EmphasizeListBoxItem(State: TOwnerDrawState;
  BlendColor: TColor);
{ Very simple (and slow) fade routine (alpha blending against blend color)
  for emphasis in the list box with answers. }
const
  { Blending value: alpha = AlphaNum/AlphaDen }
  AlphaNum = 1;   // numerator of alpha
  AlphaDen = 4;   // denominator of alpha
  { 1 - alpha = (AlphaDen - AlphaNum)/AlphaDen }
  OneMinusAlphaNum = AlphaDen - AlphaNum;
type
  PColorRec = ^TColorRec;
  TColorRec = packed record
    B, G, R, A: Byte;
  end;
var
  X, Y: Cardinal;
  Pixel: PColorRec;
  Highlight: TColorRec;
begin
  BlendColor := ColorToRGB(BlendColor);

  if odSelected in State then
  begin
    { alpha blend highlight color }
    Highlight.R := MulDiv(GetRValue(BlendColor), AlphaNum, AlphaDen);
    Highlight.G := MulDiv(GetGValue(BlendColor), AlphaNum, AlphaDen);
    Highlight.B := MulDiv(GetBValue(BlendColor), AlphaNum, AlphaDen);

    { highlight selection }
    for Y := 0 to FItemBmp.Height - 1 do
    begin
      Pixel := FItemBmp.ScanLine[Y];
      Inc(Pixel, IconMargin.Right);
      for X := IconMargin.Right to FItemBmp.Width - 1 do
      begin
        Pixel.R := MulDiv(Pixel.R, OneMinusAlphaNum, AlphaDen) + Highlight.R;
        Pixel.G := MulDiv(Pixel.G, OneMinusAlphaNum, AlphaDen) + Highlight.G;
        Pixel.B := MulDiv(Pixel.B, OneMinusAlphaNum, AlphaDen) + Highlight.B;
        Inc(Pixel);
      end;
    end;
  end;

  { draw focus rectangle in selected state}
  if odFocused in State then
    with FItemBmp do
    begin
      Canvas.Pen.Color := BlendColor;
      Canvas.Brush.Style := bsClear;
      Canvas.Rectangle(0, 0, Width, Height);
    end;
end;

procedure TForm1.ListBox1DrawItem(Control: TWinControl;
  Index: Integer; Rect: TRect; State: TOwnerDrawState);
begin
  { selection box drawing and background blending }
  EmphasizeListBoxItem(State, clHighlight);

  { If focused, the listbox will also draw a focus rectangle. Both together 
    will result in no focus rect. }
  if (odFocused in State) and (odSelected in State) then
    ListBoxAnswers.Canvas.DrawFocusRect(Rect);
end;

Een goede grap mag vrienden kosten.