What is the correct way to autosize a Static control? - winapi

I want to adjust a Static control's size to its content size, so I need to calculate the size of its text content first. I found a way to use GetTextExtentPoint32 to calculate the size, but I need to set the DC's font to the same as the control's font first. Is there a better way to do this? I've set the Static control's font once, I think maybe I don't need to set the DC's font the second time.
What is the best way to calculate the size of a Static control's text content? And is there a better way to autosize the Static control?

It sounds to me like you've already figured out the correct way to do it. Call GetTextExtentPoint32 to figure out the ideal size of the control given the text that it contains, and then resizing the control to the calculated size.
It's a lot of work, but that's what happens when you're working with the raw Win32 API. You don't have a handy wrapper library that abstracts all this for you in a Control.AutoSize() function. You could easily write your own function and re-use it, but the Win32 standard controls do not expose an "auto-size" API.
As far as the font, you will definitely need to make sure that the device context is using the same font as the control, otherwise you'll calculate the wrong size. But you don't have to create a new device context, request a handle the static control's font, and select that into your new DC. Instead, you can just use the static control's DC using the GetDC function and passing in the handle to your static control window. Make sure that if you call GetDC, you always follow up with a call to ReleaseDC when you're finished!
However, do note some caveats of the GetTextExtentPoint32 function that may interfere with the accuracy of the size you calculate:
It ignores clipping.
It does not take into account new lines (\n) or carriage returns (\r\n) when computing the height.
It does not take into account prefix characters (those preceded in the string with ampersand) and used to denote keyboard mnemonics if your static control does not have the SS_NOPREFIX style.
It may not return an accurate result in light of the kerning that may be implemented automatically by some devices.
(This is all mentioned in the linked documentation, but does anyone actually read that?)
Perhaps an easier alternative is to draw the text the same way that the static control is already doing. Unless you have the SS_SIMPLE style set (which uses TextOut or ExtTextOut to draw text as an optimization), static controls draw their text by calling the DrawText function with the appropriate parameters, given the other control styles that are set (reference).
You can do exactly the same thing, and add the DT_CALCRECT flag in your call to the DrawText function, which causes it to determine the width and height of the rectangle required to draw the specified text without actually drawing the text.

Most windows using static text controls are dialogs, where the static control's size is expressed in dialog units (DLU), which account roughly for the size of the font. In this way, dialog controls tend to have sensible sizes.
If you are not using dialogs, you can attempt to fake dialog behavior using MapDialogRect.
Otherwise yes you must use GetTextExtentPoint32.

There is no autosize for static control as far as I know. You are doing it correct.
Use GetWinDowText to get the text of static window
Use GetDC to get the dc for the window
Use WM_GETFONT to get the font for the window and select the font into the dc
Use one of the text size calculation function to calculate the text size
Restore the the original dc font
Release dc
You will always have to select the proper font into the dc to get accurate result. Also I personally prefer DrawText with DT_CALCRECT to calculate the size of a text. Refer http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498%28v=vs.85%29.aspx
With DrawText, you dont have to supply the character count if the text is NULL terminated. Plus you can combine various formatting option to adjust the calculation. For example, an Ampersand(&) character in a static control text underlines the next character. With Drawtext you will be able to calculate the size properly but in GetTextExtentPoint32 there is no provision to specify this.

Related

Can I select a font into a DC from GetDC(NULL)?

What is the difference between GetDC(hwnd) and GetDC(NULL)? I understand that the latter gets a DC for the entire (virtual) screen, but I'm not sure what that means practically.
I want to set the size of an initial window based on the font in use. I use CreateFontIndirect to create the font handle but, in my opinion, only when you SelectObject that font into a DC can you use GetTextMetrics to figure out the actual height used rather than one specified. I'm going on the assumption that they may not be the same.
I would normally use GetDC(hwnd) to get a DC and select the font into it. But, given I don't have a hwnd yet, can I select a font into a DC returned from GetDC(NULL)?
Edit: Related. I guess it may make no difference! GetDC(NULL) gets primary monitor or virtual screen?
You don't own the screen DC and should not select objects into it. What you can do is use CreateCompatibleDC, passing the screen DC, to get a DC into which you can perform text metrics calculations.

Getting the rect/height of the text inside a static control

Is there a way to achieve something similar to SysLink's LM_GETIDEALHEIGHT for static controls, i.e. getting the size (or at least the height) of the actual text?
I have a multilingual program, and I want to position the controls accordingly, otherwise there's blank space left for some of the languages, which is not great.
You can use DrawTextEx() with the DT_CALCRECT flag (thanks to Jonathan Potter for that addition). Then find the difference between top and bottom of the output RECT object.

Calculate actual size needed for a MATLAB uicontrol

I'm trying to calculate the actual size needed for uicontrols in a GUI so the GUI can resize itself appropriately. My problem is that the Extent property of a uicontrol is only the text area, and I can't find a way to determine the size of the surrounding control (such as the down arrow in a popup or the margin of an edit control). Is there a way to get the size of the decorations on a control?
I saw this related question on MATLAB Answers, which looked like it ended with no solution as well.
Edit:
For example, I want to calculate how big this popup should be to avoid cutting off the contents:
uicontrol('style', 'popup', 'string', {'a long string'})
Extent only tells me how big "a long string" is, and I still don't know how big to make the popup. I want a way to determine how much extra space is needed on the user's display (without assuming which OS or font sizes they use).
You can use get(hObject,'extent') to find out how much space the string contained in the uicontrol takes up. You can see if this is larger than the uicontrol's position.
The uicontrol Position property gives you the height and width of the bounding rectangle for the control. This has always worked for me. Is there a control where this property does not provide enough information?
If the GUI you're building can be assembled exclusively from Java components, you can use MATLAB's Java integration to create and drive a window using Java Swing components (all from M-code). That sidesteps the problem entirely, since the Java layout managers can do UI layout properly.

How to measure static size beforehand? WINAPI

I am creating a widow with static text, and because of the all 96/120/180 DPI stuff, I need to create a layouting mini-engine.
The dialog is created in code, statics are created in code, fonts are created in code, everything, mostly because resources in .rc have their share of DPI related problems as well and I want a total control.
The problem with all this is that I don't know how to find the length of the text in statics. I need to calculate the initial size of the static control, and also, I need to calculate a padding between different statics in font unit sizes, but since I don't know the size of the previous static, I can't offset the next one.
The biggest problem is that static does the word wrapping, therefore I can't find a text measuring function that would calculate that and a correction for a custom font, italic, bold, oversize...
Anyone have any ideas?
The static control styles (ENDELLIPSIS,PATHELLIPSIS and LEFTNOWORDWRAP) seem to map to the DrawText flags, so calling DrawText with DT_WORDBREAK|DT_CALCRECT will probably be as close as you can get...
I can't think of any compelling reason to do this any differently then the way all other GUI class libraries do it. Just scale window sizes between the 'design' DPI setting and the target machine DPI setting. Using DPI-independent constants is pretty painful in MFC since everything is pixel based. So keep your workstation at the common 96 DPI setting, scale from there on the target machine. You do have to keep a bit of slack because of TrueType hinting.

Wordwrap Win32

I'm trying to wordwrap a block of text for display in a window that would otherwise be too long. The font I'm using is not a fixed width font, so GetSystemMetrics will not return accurate values for my text.
Using a static window is not an option here because a static window doesn't tell me one crucial piece of information: The height of the text drawn after wordwrapping.
Any ideas?
Billy3
Check out the Win32 API call DrawtextEx. You'll need to pass the DT_CALCRECT option, telling Windows that you wish for the rectangle to be calculated.
You could use the DrawText() API function with the DT_CALCRECT flag set. You would need to select the correct font for the HDC first.
DrawTextEx() will do everything you want and need if the entire text is to be displayed in a single font.
If you need to mix fonts, you'll have to do the work yourself. In that case, you'll want to look at APIs like GetTextMetrics() (not GetSystemMetrics()) and GetTextExtentExPoint32() to figure out positions and sizes for each run.
If you need to handle complex scripts (e.g., right-to-left languages and scripts where the letters change shape depending on context), you'll need Uniscribe. Caution: Uniscribe is powerful but very low level. It can take a lot of work to wrap it with a higher-level interface. If you need complex script handling, you might be better off using a browser control.
Both DrawText() and DrawTextEx() can accomplish that. The key is to use DT_WORDBREAK in the format parameter.
To draw text within a 100 x 100 rectangle at the top let, one could use either:
RECT textRect;
SetRect(&textRect, 0, 0, 100, 100);
DrawText(hdc,TEXT("THIS IS TEXT THAT WILL PROBABLY WRAP AROUND A 100 BY 100 RECTANGLE. BUT YOU CAN'T BE SURE UNLESS YOU TRY."),-1,&textRect, DT_LEFT | DT_NOCLIP | DT_WORDBREAK);
The DT_LEFT option aligns the sentences to the left. The DT_NOCLIP ensures that text isn't cut out at the bottom.
OR
Use DrawTextEx():
RECT textRect;
SetRect(&textRect, 0, 0, 100,100);
DrawTextEx(hdc,(LPSTR)TEXT("THIS IS TEXT THAT WILL PROBABLY WRAP AROUND A 100 BY 100 RECTANGLE. BUT YOU CAN'T BE SURE UNLESS YOU TRY."), -1, &textRect, DT_LEFT| DT_NOCLIP|DT_WORDBREAK , NULL);

Resources