title: Highlight controls in themed Delphi App with Delphi Tokyo
body: <p>Using Delphi Tokyo 10.2, with Stylized Themes. I am trying to highlight components on the form, e.g., <code>ComboBoxes</code>, <code>EditTexts</code>, etc. For example, if a user entered invalid data, I would like to highlight the component. </p>
  
  <p>In the past, we just colored components <code>Red</code>, and the color persisted through resizes/movement/repaints in general. Now with theming, we need to do a bit more to get the color to show and persist. </p>
  
  <p>I have tried disabling each component's <code>StyleElements [seFont, seClient, seBorder]</code> properties to force show the color. This works but seems kludgy, particularly when there are many components being validated. Also, simply coloring a component red might not look right with some of the themes. </p>
  
  <p>I have also tried simply drawing a red rectangle around the components using <code>WinAPI SetRop2(..)</code>. E.g., <a href="http://delphi.xcjc.net/viewthread.php?tid=48253" rel="nofollow noreferrer">here</a> is some clever code, I tweaked to take a <code>TWinControl</code> and <code>Draw</code> a <code>redbox</code> around it; I can also remove the <code>redbox</code> using a similar call. This works: </p>
  
  <p><a href="https://i.stack.imgur.com/t1HsW.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/t1HsW.png" alt="enter image description here"></a></p>
  
  <p>…but doesn't persist through repaints, obviously. It seems like adding custom paint methods might be an overkill here. Unless, there is some better way?</p>
  
  <p><strong>Other things I have considered:</strong></p>
  
  <p>All of the components sit on panels, and I have considered using a protected hack to draw red <code>rect</code>s on the panel's canvas around the components, but again, more custom paint routines… </p>
  
  <p>I am also considering drawing <code>TShapes</code> dynamically as needed, but this strikes me as silly.</p>
  
  <p>There must be others in the same situation, e.g., data entry validation that worked neatly in older versions of Delphi, but doesn't look so good when themed. What is the best approach when using themes? The <code>SetRop2(..)</code> approach seems to be the cleanest, but can someone suggest a simple way to make the color persist? I would welcome other ideas, too. Thank you. </p>
  
  <p><strong>EDIT</strong>
  So maybe, just dynamically drawing <code>TShapes</code> around the invalid responses isn't so bad. They persist through repaints and don't descend from <code>TWinControl</code>, meaning they automatically show up behind the control they are highlighting. </p>
  
  <p>This works quite well for me and I hope it's helpful to others.</p>
  
  <pre><code>// assuming owning control will be free'd properly and 
  // will in turn free HI_LITE Box.
  // 
  // tantamount to adding an instance variable, TShape, to existing Control,
  // since class helpers don't allow. And I don't want to descend 
  // new controls just to have a hiLiteBox Instance Variable.
  
  procedure HiLiteMe(aControl : TWinControl; HILITE_FLAG : Boolean = TRUE; aColor : TColor = clRed);
  const OFFSET = 4;                         // specify the offset of the border size of the box.
  const BOX_NAME_PREFIX = 'HI_LITE_BOX_';
  
  var
     hiLiteBox : TShape;      // reference created on stack, but object created on the heap,
     uniqueBoxName : String;    // so use the persistent aControl's owned component list to maintain the reference.
  begin
    uniqueBoxName := BOX_NAME_PREFIX + aControl.Name;              // uniquename for each associated HiLiteBox.
    HiLiteBox := aControl.FindComponent(uniqueBoxName) as TShape;  // phishing for the HiLiteBox if it was previously created.
  
    if NOT Assigned(hiLiteBox) then         // create HiLiteBox and make persist outside this proc.
    begin
      if NOT HILITE_FLAG then exit;         // don't create a box if we're just going to hide it anyway.
      hiLiteBox := TShape.Create(aControl); // Create HiLiteBox, setting aControl as owner, quicker retrieval using aControl.findComponent
      hiLiteBox.Parent := aControl.Parent;  // Render the box on the control's parent, e.g., panel, form, etc.
      hiLiteBox.Name :=  uniqueBoxName;
      hiLiteBox.Pen.Color := aColor;        // Color the Pen
      hiLiteBox.Pen.Width := offset-1;      // Make the Pen just slightly smaller than the offset.
      hiLiteBox.Brush.Color := clWindow;    // Choose a brush color, to fill the space between the pen and the Control
      hiLiteBox.Left := aControl.Left - offset;
      hiLiteBox.Width := aControl.Width + offset*2;
      hiLiteBox.Top := aControl.Top - offset;
      hiLiteBox.Height := aControl.Height + offset*2;
    end;
  
    hiLiteBox.Visible := HILITE_FLAG; // Show/Hide HiLite as appropriate.
  end;
  </code></pre>
  
  <p>Called like this to HiLite with a red and blue box...</p>
  
  <pre><code>begin
    HiLiteMe(checkListBox1, TRUE, clRed);   // Draw a RedBox around the CheckListBox, e.g., Invalid.
    HiLiteMe(bitBtn3, TRUE, clBlue);        // Draw a Blue Box around the Button, e.g., Required.
  end;
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/ciirw.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ciirw.png" alt="blue box indicates required, red box indicates invalid"></a></p>
  
  <p>Called like this to remove <code>HiLites</code>…</p>
  
  <pre><code>begin
    HiLiteMe(checkListBox1, FALSE);   // Draw a RedBox around the CheckListBox, e.g., Invalid.
    HiLiteMe(bitBtn3, FALSE);        // Draw a Blue Box around the Button, e.g., Required.
  end;
  </code></pre>