3

A very easy way to show different string values than the Items is to set the Style property from csDropDown to csOwnerDrawFixed as Andreas Rejbrand has answered a few years ago.

The thing is: as soon as you do that, you loose Windows Theming support.
The same limitation applies to using csOwnerDrawVariable

These two Style values get translated into adding the CBS_OWNERDRAWFIXED or CBS_OWNERDRAWVARIABLE (in addition to CBS_DROPDOWNLIST) styles of the Windows COMBOBOX control.

In turn, CBS_OWNERDRAWFIXED or CBS_OWNERDRAWVARIABLE cause you to instantly loose the Windows theming support.

When you do full custom painting like a colour picker, that is all fine. But when you only want to replace the drawn text, it is not.

The Windows COMBOBOX control does not seem to have a way around this, so I'm wondering: how can you simulate the Windows theming from Delphi?

I assume it has to do with DrawThemedBackground, but it has been a while since I've done serious Delphi Control work, so any pointers on how to get started there are fine too (even if they invalidate my assumption).

Community
  • 1
  • 1
Jeroen Wiert Pluimers
  • 23,965
  • 9
  • 74
  • 154
  • 1
    Just change the text in the control and let Windows do the work. – David Heffernan Sep 09 '12 at 11:08
  • @DavidHeffernan That is a lot of work, so I wonder if simulating the theming is less work. And it would be a good exercise to learn more about how the theming support actually functions. – Jeroen Wiert Pluimers Sep 09 '12 at 11:14
  • 2
    I cannot imagine that ComboBox1.Items.Assign is harder than working out theming. Very easy to get themed painting wrong as you can see from the VCL. Windows gets it right. – David Heffernan Sep 09 '12 at 11:38
  • @DavidHeffernan The problem is not the Assign, but the mapping back to what I want. But I appreciate your point. Just waiting to see if someone comes with an answer into the theming direction and if not, work on the mapping. – Jeroen Wiert Pluimers Sep 09 '12 at 12:21
  • 1
    Can you work it out by reading the code for `TComboBoxStyleHook`. – David Heffernan Sep 09 '12 at 13:13
  • I tried, not much success yet, but when I do, I will post. First some non work though (: – Jeroen Wiert Pluimers Sep 09 '12 at 13:24
  • 1
    As david says, I really don't see the point of your question. You're doing it the hard slow way, instead of the fast easy way (Just change the item text?) – Warren P Sep 10 '12 at 03:21
  • I simplified the question a lot. Doing the reverse mapping requires me to enumerate over all items, which I'd rather not do (especially since I'd need abstract that for multiple not so similar kinds of occasions that are in different parts of the class hierarchy). – Jeroen Wiert Pluimers Sep 10 '12 at 11:03
  • @JeroenWiertPluimers But you need to do that mapping at some point. The text has to come from somewhere. – David Heffernan Sep 10 '12 at 12:09
  • @DavidHeffernan But now I need to do the reverse mapping... It's not impossible like a trapdoor, but it is impractical. But probably less impractical than doing the theming. – Jeroen Wiert Pluimers Sep 10 '12 at 14:19
  • 1
    If you can work the text out to paint it, you can work the text out to stuff into the combo box items. – David Heffernan Sep 10 '12 at 14:42
  • @DavidHeffernan stuffing the text into the items isn't the problem. The reverse (getting the right underlying item back from that text) is. That's my mapping problem, hence the reference to the trapdoor. – Jeroen Wiert Pluimers Sep 10 '12 at 15:14
  • OK, now I understand. I guess at this point you wished you had a better separation between business logic and UI! – David Heffernan Sep 10 '12 at 15:15
  • I usually want, as most code I maintain at clients has very bad separation. But in this case the separation is quite OK. The `Business Layer` gives me a `TStrings` with the `Objects` filled (it is pre-Delphi-2009, so no generics yet). That's why I can get out the `Text` sou easy (: First I need to finish about a week of .NET work though. – Jeroen Wiert Pluimers Sep 10 '12 at 16:03
  • I actually wish that I had a completely VCL-implementation of TComboBox if only due to the issues in the Standard Control ComboBox setting its item height however it wants. If I was stuck in your situation, I think I'd almost write my own `TExtComboBox` and its own VCL styles feature. – Warren P Sep 10 '12 at 20:45
  • The comments by @DavidHeffernan did give me some thought. Since the `Object` instance references are already in the `TStrings`, I wrote a small function to return a new temporary `TStrings` that has the string values with the captions I needed and keep the `Object` references. Since it has the same item ordering, and same `Object` references I don't need any mapping at all. Just need to make sure I free the new `TStrings` at the right moment. – Jeroen Wiert Pluimers Sep 10 '12 at 21:24

3 Answers3

2

I added theming support to the TurboPower Orpheus ComboBox a couple of years ago. Take a look at the code inside the {$IFDEF VERSION2010}...{$ENDIF} sections. That should give you a pretty good idea about what is needed.

Sebastian Z
  • 4,520
  • 1
  • 15
  • 30
0

I fixed it in drawitem

procedure Tfrmxxx.cbTypeDrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
    with (Control as TCombobox).Canvas do
    begin
    if odSelected in State then
      Brush.Color := StyleServices.GetSystemColor(clHighlight);// $00FFD2A6;

    FillRect(Rect);
    TextOut(Rect.Left, Rect.Top, (Control as TCombobox).Items[Index]);
    if odFocused In State then
    begin
      Brush.Color := (Control as TCombobox).Color;
      DrawFocusRect(Rect);
    end;
  end;
end;