tags:

views:

285

answers:

3

In Delphi, all the TEdit and TComboBox controls are 21 pixels high by default. In the case of TComboBox, this size is absolute and trying to stretch it to something bigger doesn't work. In the case of TComboBoxEx though, the default height is 22 pixels, which makes it stand out a little on any form where you use it. Now according to the Microsoft docs, ComboBoxEx is essentially a ComboBox with owner-drawn functionality being handled to allow images and indentation.

So is it possible to make my TComboBoxEx controls 21 pixels high? What does this depend on?

Update: I added a Quality Central report on the issue, as suggested by Roddy. Also, I found a fix. Apparently, the size depends on the size of item -1 in the combobox. So you set that size to 15 (or one pixel less than the default size) and the box shrinks to the more familiar 21 pixels.

+1  A: 

The height of a TComboBox isn't absolute; it's tied to the height of the font you use. TComboBoxEx works the same way, but it seems to have one extra pixel of "overhead", as you've noted, and there doesn't seem to be any simple way to change that. If this is a wrapper for a built-in Windows control, there may not be any way to change it at the Delphi level, period.

Mason Wheeler
Unless you want to create your own version, but I don't think that's a valid option ;-).
Gamecat
+1  A: 

Two ways to change the height of TComboBoxEx, unfortunately neither are probably what you want.

  • Set the font.size property smaller - the box will shrink. (however, your text is smaller)

  • Set the StyleEx.csExNoSizeLimit := false, then set Height := 21 as desired. Unfortunately, this just causes your box to be clipped, so the bottom bezel disappears.

I'd probably replace all TComboBoxes with TComboBoxEx - GExperts has a brilliant 'replace components' wizard for doing this.

This looks like a Delphi bug. Have you reported it via QC?

Roddy
Added the QC report. Link added to question.
Cobus Kruger
+3  A: 

I found a fix. Delphi seems to have a couple of bugs relating to this:

  1. The value of the published ItemHeight property is forced to be 16, because the TComboBoxEx class overrides the GetItemHt function to be a hard-coded 16. No regard whatsoever for the actual size of the item - strange, as this works perfectly on TComboBox. I don't know why they decided to go with this strategy. Probably to ensure the images will always fit.
  2. Delphi doesn't actually call the CB_SETITEMHEIGHT message, so even if you override this function nothing changes.

Update:

As pointed out by mghie, my initial idea of using a hard-coded value of 15 in calling the message doesn't work well at different DPI settings. So I am now using a calll to GetTextMetrics to determine the height. Added to the height of the font is the value of GetSystemMetrics(SM_CYBORDER).

This is based on the way the VCL determines the size of a TEdit. I don't think it is quite right, but since the goal is to have the ComboBoxEx the same size as TEdit it is probably as close as we'll get. And it works at DPI settings of 96, 120, 144 and 192.

The height of the ComboBoxEx is determined by the height of item -1. So items 0 to count-1 are the actual list items, but item -1 is the height used for the editor. If you set that height to 15, the height of the control is corrected to be 21 pixels (see update above for scaling issues). I think Mason may be right that the font size plays a part here (probably resizes the item), butyou can make it work just fine by adjusting the item size.

It does seem to introduce a new (in my view, smaller) problem in that at 96 DPI 16-pixel high images loose the bottom-most line when shown in the editor portion, but that's hardly noticeable.

So the fix then, is to call this code:

GetTextMetrics(Canvas.Handle, TM);
SendMessage(Handle, CB_SETITEMHEIGHT, -1, 
  GetSystemMetrics(SM_CYBORDER) * 2 + TM.tmHeight);
Cobus Kruger
A TEdit on my laptop with a DPI setting of 124 is certainly not 21 pixels high. Hard-coded heights are just wrong, whether they work for you or not, and returning 15 is not really any better than returning 16. What about different fonts or DPI settings? A real fix would involve getting the height of the font and calculating the item height based on that.
mghie
-1 for hardcoded constants like mghie explained
Jeroen Pluimers
Point taken about the DPI setting. So now I need to know how the height of an edit box is calculated.I looked at calculating the item height based on the font height, but I don't see how that got them to 16 in the first place - I actually think it was chosen so 16x16 glyphs would fit. What does seem to work on both 96 DPI and 120, is calling GetTextMetric and using the tmHeight + 2. I thought using tmHeight + tmInternalLeading would be correct, but that only works at 120 DPI. I could start at 15 and scale that from 96 to 120, but that doesn't seem right either.Any ideas?
Cobus Kruger
The TEdit.AdjustHeight method also makes glaring assumptions, I see. It uses tmHeight + I, where I is GetSystemMetrics(SM_CYBORDER) * either 6 or 8, depending on whether or not the control has Ctl3D set. It seems that 6 or 8 is supposed to be the width of the border plus the internal spacing of the edit control. So if I do the same, I'll be replacing one magic number for another. So how do I determine the internal spacing? And remember, the goal is to get the TComboBoxEx height the same as the default for a TEdit.
Cobus Kruger
+1, and thanks for following up on this and finding a better solution.
mghie