How do I set a minimum window size in wxWidgets? - user-interface

This is the hierarchy of widgets I've got:
Frame > wxBoxSizer > wxPanel > wxBoxSizer > wxFlexGridSizer (2 columns, 9 rows), with assorted form fields and buttons inside.
The first BoxSizer is to place the panel in, and the second is to make a border around the FlexGrid.
Everything looks nice, and the frame can expand properly if the window is enlarged, but it also can be resized to almost nothing, hiding all form elements.
How do I force the minimum size for the window to the one suggested by the FlexGridSizer by default (all form elements visible and having their minimal possible sizes)?

Probably much too late but the answers given here are needlessly complicated, you just need to call SetSizerAndFit(sizer) to both associate the sizer with the frame, set its initial size and also set this size as minimal acceptable size.

Using the SetMinSize() method on your Frame to set a minimum size will set a limit on the smallest area of the frame (just tested it). Once set, wxWidgets will not allow the frame to be sized smaller than the value specified.
I'd set the value like this. In the constructor, set up all the elements of the frame. At the end, after you call the Layout() method to setup all the sizers and such, call the GetSize(int *w, int *h) method to get the x and y size of your frame at the default layout. Use those values to call the SetMinSize() method to set that default size as the minimum for your Frame. This will take into account all the various padding and borders and such set up by the frame and the contained elements.

In wxPerl, dagorym's answer can be written concisely as
$self->SetMinSize($self->GetSize()); after a call to Layout().

I would try calling wxFrame->SetMinSize(wxSize) with whatever wxFlexGridSizer->GetMinSize() returns, should work, but not tested. You will need to note what GetMinSize says about coverting to window size before passing it I expect.

Related

ID2D1RenderTarget::GetSize returing physical pixels instead of DIP

I'm currently getting started with Win32 and Direct2D and reached the chapter on DPI and DIP. At the very bottom it says ID2D1RenderTarget::GetSize returns size as DIP and ID2D1RenderTarget::GetPixelSize as physical pixels. Their individual documentation confirms that.
However I cannot observe that ID2D1RenderTarget::GetSize actually returns DIP.
I tested it by
setting the scale of one of my two otherwise identical displays to 175%,
adding <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness> to my application manifest,
obtaining
D2D1_SIZE_U sizeP = pRenderTarget->GetPixelSize();
D2D1_SIZE_F size = pRenderTarget->GetSize();
in method MainWindow::CalculateLayout from this example (and printing the values),
and moving the window from one screen to the other, and arbitrarily resizing it.
I can see the window-border changing size when moving from one display to another. However, the values in both sizeP and size (besides being int and float) are always identical and correspond to the physical size of the ID2D1HwndRenderTarget.
Since I do not expect the documentation to be flawed, I wonder what I am missing to actually get the DIP of the window of the ID2D1HwndRenderTarget pRenderTarget.
The size is only relative to the DPI of the render target, set using ID2D1RenderTarget::SetDpi. This value is not automatically connected to the value provided by the display system, which can be queried using ID2D1Factory::GetDesktopDpi or GetDpiForMonitor.

DPI awareness: could I be told when I need to recalculate my text height so I don't have to do it all the time? And SM_CYSMICON/checkbox heights too?

A frequent operation in my Windows Table control, which I am reworking and moving into a DLL, is to get the height of a row. This is the maximum of
the height of text in the current font, in pixels
the current small icon height, in pixels (GetSystemMetrics(SM_CYSMICON))
the height of checkboxes, in pixels (determined on a WM_THEMECHANGED, when checkbox information is recalculated)
Calculating the text height, as far as I know, requires getting a DC, selecting the font in (and getting the SYSTEM_FONT if that's NULL), getting the text metrics, selecting the font out, and releasing the DC, all of which can error out/fail/etc. This means that virtually every function in my control can fail.
I can avoid this by storing the text height somewhere else, only calculating it when it changes. I know that text height is a property related to the DPI of the DC that GetDC(hwnd) returns. I would like my control to be DPI-agnostic because DPI awareness is per-process, not per-DLL/per-window.
At the same time, knowing when GetSystemMetrics(SM_CYSMICON) changes would also be useful.
So my questions are simple:
Is there a message that I can look for that will tell me that my DPI has changed and that I need to recalculate my text height?
Is there a message that will tell me that SM_CYSMICON has changed and that I need to recalculate everything? Is it the same one? (I know there is no reliable way to detect a GetSystemMetrics() failure (since 0 is a valid return and it does not set the last error code), so I am assuming it cannot fail with a valid parameter and am simply calling it each time I need to calculate the row height; this is just so I can queue a redraw when the value does change.) Would it also work for SM_CXSMICON?
In addition, looking back at my code, GetThemePartSize() takes a DC as well; do theme items like checkbox images scale with DPI? And if so, what messages do I look for in that case? The same one?
Alternative: is there a non-failing way to get the text height that I don't know about, given only a HWND and HFONT?
I will be happy to take a solution that was introduced in either Windows XP or Windows Vista; if there's a solution that was introduced in a newer version of Windows, then knowing about it could also be beneficial.
Thanks.

Restoring modified size of wxFrame in wxWidgets

I am using wxWidgets to design GUI in windows. The requirements is, if the user has modified the frame size then I have to store the modified size and use the modified size for next session. I am able to store the size, but still I am getting older size not the modified size in next session. My window has several children(check, text, label). These controls are put in panel using sizers. Every time the best size is queried and recalculated and SetClientSize(size) is called. Is this the reason why the modified size is not reflected?
First, don't save and restore the frame size yourself, use wxPersistentTLW which does it for you instead, see the overview for more information and the "widgets" sample for an example of using it to preserve the frame geometry.
Second, the layout mechanism in wxWidgets is totally deterministic, so restoring the same frame size as during the last run should definitely result in the same positions and sizes being used for the children. If this isn't the case (I'm not really sure about it, you don't actually say what the problem is), most likely explanation is that your size saving/restoring code doesn't work correctly -- and that simply getting rid of it and using the built-in support for this should fix the problem (whatever it is).

What is the correct way to autosize a Static control?

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.

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.

Resources