wxwidgets custom control size cannot be set.What am i missing out - custom-controls

I have a Custom control derived from wxControl,inside a dialog with a vertical sizer
wxBoxSizer *topSizer = new wxBoxSizer( wxVERTICAL );
Knob* newKnob = new Knob(panel,wxID_ANY,wxDefaultPosition,wxSize(40,40));
topSizer->Add(newKnob,0,wxALL|wxALIGN_CENTER);
panel->SetSizer(topSizer);
topSizer->Fit(panel);
//panel is a wxPanel inside the dialog
But for some reason ,the custom controls' size is set at (80,100).If i resize the dialog beyond that size its aligned to center as i specified.
EDIT:
Am using wx 2.8.9 on windows Vista with visual studio 2005.
What could be missing?

You didn't provide any information about the wxWidgets version or your platform / compiler, so I will answer for wxWidgets 2.8 and MSW.
The size you specify is not necessarily used for the control, since the best size for different platforms may well be different. Even on Windows the size will usually depend on the default GUI font. So there are various methods in wxWidgets that let windows specify their minimum, best or maximum size. If you have special requirements you may need to override some of them.
For your problem it looks like you want to have the control have a smaller size than the default best size of wxControl:
wxSize wxControl::DoGetBestSize() const
{
return wxSize(DEFAULT_ITEM_WIDTH, DEFAULT_ITEM_HEIGHT);
}
(taken from src/msw/control.cpp) with the values
#define DEFAULT_ITEM_WIDTH 100
#define DEFAULT_ITEM_HEIGHT 80
(taken from include/wx/msw/private.h).
If you override DoGetBestSize() to return your intended size it should work.
Edit:
You comment that you cannot override DoGetBestSize() since it is not virtual in wxControl. It is though, because it is introduced in wxWindow:
// get the size which best suits the window: for a control, it would be
// the minimal size which doesn't truncate the control, for a panel - the
// same size as it would have after a call to Fit()
virtual wxSize DoGetBestSize() const;
(taken from include/wx/window.h). wxWindow is a parent class of wxControl, so the method is indeed virtual and you can of course override it. Many controls do in fact, as a grep in the sources will show you.

Related

AccessibleObjectFromPoint and per-monitor DPI

I'm using accessibility with the AccessibleObjectFromPoint function, and I'd like it to work correctly on a per-monitor DPI environment. Unfortunately, I can't get it to work. I tried many things, and the situation for now is:
My app is marked as per-monitor-DPI-aware in the manifest. (True/PM)
I use GetCursorPos and then AccessibleObjectFromPoint.
How can the problem be reproduced:
Have two monitors, one with 100% DPI, the other with 125%.
Run Chrome on the 125% monitor.
Use AccessibleObjectFromPoint on one of the tab names, it won't work.
It works with some apps (DPI-aware, it seems, like explorer), but doesn't work with others. I tried several relevant functions, such as GetPhysicalCursorPos and PhysicalToLogicalPointForPerMonitorDPI, but nothing works.
It's worth noting that Microsoft's inspect.exe works as expected.
I’ve been struggling with this exact same problem for several weeks and can now tell you my findings. Unfortunately I can’t give you more than a hint of code, because the project I am working on, is proprietary.
The issue started at Windows 8.1. The problem did not exist on Windows 7 or Vista, because AccessibleObjectFromPoint always used raw physical coordinates, as documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317984(v=vs.85).aspx .
“Microsoft Active Accessibility does not use logical coordinates. The following methods and functions either return physical coordinates or take them as parameters.” This has not been true since Windows 8.1.
AccessibleObjectFromPoint now uses a flawed calculation that cannot always find the correct window for reasons similar to my question here: High DPI scaling, mouse hooks and WindowFromPoint .
My findings lead me to one conclusion: The API is broken. This does not mean it is not possible though.
Possible solutions I have partially tested that seem to work follow.
Prerequisites are that you
1/. Make your process per monitor DPI aware, NOT USING THE MANIFEST (more on that later).
2/. Determine the hWnd of the window you want to query (WindowFromPoint() variants)
3/. Determine the monitor DPI of the queried hWnd
4/. Determine the DPI of your process
5/. Determine the DPI of the queried hWnd
6/. Determine the monitor origin and offset for the queried hWnd (MonitorFromWindow() and GetMonitorInfo() )
Next, depends on your platform
Windows 10.0.14393+
Write a function that finds the IAccessible (AccessibleObjectFromWindow() ) from the top level window, and then recursively call IAccessible::accHitTest until you reach the bottom-most IAccessible and perhaps ChildID data. Return that as if you would call AccessibleObjectFromPoint.
To call it successfully, you will need to scale the (x,y) co-ordinates into the scale system of the queried hWnd, using the DPIs and co-ordinates fetched in the list above. Watch out for systems where monitors are not the same size or if monitors are partially offset, or above and below.
And now for the important part for 10.0.14393 – Set your thread to the same DPI_AWARENESS_CONTEXT of the hWnd you are querying. Now call your new function. Now revert your thread to monitor DPI aware, and voila, it works, even if the window is not maximised. This is why you must not use the manifest.
If you are on Windows 8.1 to 10.0.10586 you have a tougher task.
Instead of calling accHitTest, as above, you have to recursively call AccessibleChildren and iterate the call IAccessible::accLocation to determine if your test point is within each child. This is tricky and starts to get really messy when you get to e.g. combo boxes in products like Office, which is only system DPI aware.
That’s all I can give you for now.
To do it successfully on multi-platform (mine has to work from Vista to Windows-Current) the only really safe bet is to write a wrapper DLL in C++ that can determine at runtime which OS it is on and change code path accordingly. The reason you want to do it in C++ is to avoid passing IAccessible objects across the .Net/unmanaged marshalling boundary. You can call IUnknown::Release on objects you don’t need to return n the unmanaged side. You can do it all in .Net, but it will be slow.
P.S. also watch out for Chrome returning infinite trees where parents are children of their parents, some snity checks are required. Also, Chrome does not return accRole correctly, and will give you HTML tags instead of VT_I4.
Good luck
A fairly workable solution is as follows, in your IAccessible recursive function:
Use getwindowrect to capture the physical right on main window
Use accChild.accLocation in loop to capture left and Width on each Object
Add this simple test
If l > rct2r.Right And l > arrIACC.x2 Then
arrIACC.x2 = l + w
End If
if dpi = 100 then no Object is furter out than physical right
if dpi > 100 then closebutton is...x pix offset
Use the difference to rescale all values you are in use of Width
arrIACC.w1 = CInt(((-rct2r.Left + arrIACC.w1) / arrIACC.x2) * rct2r.Right)
This solution is from an Excel plugin I have developed, I was testing the Width of the quick access toolbar qat and my result was +- 5 pixels regardless of any DPI.

Scaling UI with DPI change of non MFC application

My application is a plug-in developed in VC++ (win32). The solutions I could find didn't work for me.
I have two options :
To disable DPI changes for my DLL plugin. That means my plug-in will not be affected with DPI changes.
To scale all the controls according to the DPI change.
Please help.
Thanks.
1. Disable DPI affect on my application UI when some one re-configures the DPI. Help required : If possible, how to do that pro-grammatically.
This is not possible. Adrian already told you that. DPI is a user setting, not an application setting. If the user wants to change their DPI, they can do so. They can also apply backwards-compatibility hacks that turn off high DPI for a particular application, but that functionality is not available to applications. As the developer, you're expected to make sure that you support high DPI environments, not disable it.
The only thing you can do as an app developer is to fail to indicate that your application is DPI-aware. This is roughly equivalent to walking around with an "IDIOT" sign taped to your forehead. You might find that people are slightly more accommodating of your shortcomings, but they won't have much respect for you and probably won't care to hang out with you very often. Windows will do much the same thing: it will hide the truth from you about the user's actual DPI settings (you can't handle the truth) and instead it will scale up your interface automatically to match. The effect is an ugly one.
Of course, you also say that you're creating a plug-in DLL, which changes things. DLLs can't alter the DPI-awareness of the entire process because that is determined by the host application. If the host application indicates that it is high DPI aware, then your DLL must also be high DPI aware. This is an all or nothing setting, just like the "IDIOT" sign.
2. Scale the UI of my application according to the DPI change. Help required : How to determine the current DPI and how to scale the UI accordingly? Is it necessary to scale every component or any other way to scale them automatically.
In order to correctly determine the current DPI settings, you need to indicate to Windows that you're not an idiot your application is high DPI aware. As discussed above, if you do not do this, Windows will assume that you cannot handle the truth and lie to you. But as we also established above, this probably does not apply to you because you're creating a DLL that runs in the context of another process that is already establishing itself as high DPI aware.
So, what you need to do is determine the DPI scale factor. You need that to scale your user interface elements accordingly when running in high DPI environments. The baseline DPI setting is taken to be 96. The following code scales a SIZE structure (that defines a width and height) relative to that baseline:
void ScaleDpi(SIZE& size)
{
// Determine the current screen DPI.
const HDC hDC = GetDC(NULL);
const int dpiX = GetDeviceCaps(hDC, LOGPIXELSX);
const int dpiY = GetDeviceCaps(hDC, LOGPIXELSY);
ReleaseDC(NULL, hDC);
// Perform the scaling.
size.cx = MulDiv(size.cx, dpiX, 96);
size.cy = MulDiv(size.cy, dpiY, 96);
}
However, if you follow good design practices, you may not need to scale every control manually. When defining windows and dialogs in a resource file (e.g., using the Visual Studio Dialog Editor), you specify the layout in logical units (known as DLUs, or dialog units). These units are independent of any particular DPI setting and are therefore preferable to using something like pixels. A simple dialog with a few controls therefore requires no special scaling effort. You'll only need to perform manual scaling if you're creating and/or laying out controls at run-time.
You'll find more tips and techniques on how to write high DPI aware applications on MSDN, in the Writing High-DPI Win32 Applications article. And I don't link this just to say RTFM—it's actually extremely helpful, and I highly recommend reading it all.
The folks who make the RealWorld Icon and Cursor editors also maintain a helpful article on their site: DPI-aware applications in Windows Vista and Windows 7.

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.

How can I resize my vb6 program so that it automatically fits in any screen resolution?

How can I have a vb6 program which opens correctly in 1280*1024 but when switched to other resolutions say 640*480 i can only see half of the screen. how to re-size my vb6 program so that it automatically fits in any screen resolution?
You need to use the Screen object, this will always give you the current resolution in pixels:
Dim screenwidth,screenheight As Single
screenwidth = Screen.Width \ Screen.TwipsPerPixelX
screenheight = Screen.Height \ Screen.TwipsPerPixelY
Usually a Form amenable to resizing has controls that lend themselves to a "flow" layout. Often this is something like a TextBox, grid control, etc. that supports scrollbars. You shrink/grow such controls as required after allocating positions for (i.e. moving) the fixed-size elements like buttons and such.
For a busy Form with lots of fixed size controls that isn't "document oriented" there is no set answer. Sometimes creating a scrollable Form makes sense but usually it doesn't.
Some people try to resize "fixed" elements, change fonts sizes, etc. This can produce results of mixed quality though, sometimes good and sometimes not.
Considerations about the Form size are best made up front as part of the design process. For some applications it might be better to decide on a minimum supported Form size. In other cases you may have to break things up with dialog Forms or tab controls.
There's no easy way to do this in VB6, like there is in .Net. You have to manually resize everything in the form's Resized event handler based on the new form's client size. It's a pain, and a huge mess, but it's the only way to do it.
Correction: There's never only one way to do things, but I've been programming VB6 for several years, and usually just writing it into the Resize handler is straightforward enough, and I haven't found any good way to do it other than that.
Have you tried any 3rd party tools for doing this? Here's (a free) one that seems to work :-
ActiveResize Control Lite - I created a quick project to try it and it does what it says on the tin!
The lite version has some limitions such as number of forms in project, number of controls on form etc. You can also buy a Standard or Professional version if you need more functionality.
I know we've spent countless hours trying to implement our own resizing code only to remove it all and fix the location of most controls, move a few to make it look better and limit the min/max functionality of the form - none of which give a nice user experience. If we needed to do it again I probably use this control (or a similar one) just for the time savings.
I use ComponentOne SizerOne
The C1Elastic control allow from resizing and maintain the aspect ratio, resizing the inside controls on the setting you defined.
It's not free, but it payed itself with all the time I saved.
Form1.Height = Screen.Height
Form1.Width = Screen.Width
This code sets form size according to screen resolution.
"ActiveResize Control Lite" ActiveX tool is limited to 20 controls per form.
Once we know the screen resolution, there are a number of things you can do.
• The easiest solution would be do design different form to accommodate the four most popular monitor resolutions – 640 x 480, 800 x 600, 1024 x 768, and 1600 x 1200.
• Alternatively, we could write code that dynamically resizes and relocates every control on the form, based on the screen resolution – not an easy undertaking!
• Third party controls that resize the controls based on the screen resolution are quite effective. On the whole, though, it's better to just avoid this kind of problem, if you can. For example, see Creating Flexible Forms in Visual Basic (Flexi-Forms) at codeguru.com
To auto fit screen resolution you need to download an active x, drag it on your conform.
Search for "veg gold vb6.0 screen Resize".

Resources