I'm trying to resize dynamically a CMFCPropertySheet to add a custom control at the bottom of each page.
As all Property Pages are not of the same height, I have a mechanism to increase the size if necessary.
For this, I have overridden the OnActivatePage method and by using SetWindowPos, I can resize the sheet, first, then the tab control, then the page and finally I can move the OK/Cancel/Help buttons.
It works fine with PropSheetLook_OutlookBar and PropSheetLook_Tabs styles but not with PropSheetLook_OneNoteTabs style. The page (or the tab) is not correctly resized (the lighter grey color of the page does not fill the sheet.
OneNote style OneNote http://www.freeimagehosting.net/uploads/th.ec91600664.jpg
Outlook style Outlook http://www.freeimagehosting.net/uploads/th.319b6938ab.jpg
Any idea? A MFC Feature Pack bug?
I found the problem. One needs to get a reference to the different tab control the OneNote version uses via GetTab() and resize it accordingly.
Just follow the instructions as seen in here.
Although the instructions are for CPropertySheet they work for the CMFCPropertySheet as well.
Some parts of the code is deprecated so you will need to make the following amendments.
Skip the XmnPropSheetCallback and DoModal implementations completely
In OnInitDialog just make a call to CPropertySheet::OnInitDialog(); and then call OnSize instead of doing everything presented in that code.
Related
My app is Win32; I'm using VS 2015. I have a dialog box that contains a listbox. I set the listbox to be dynamically resized, but it does not change when the dialog is resized.
Here are the listbox' attributes:
The listbox is owner-drawn:
This is the default size of the dialog:
This is what the dialog looks like when I stretch in Test mode in the Resource Workshop Dialog Editor. Notice the inside listbox expands too, exactly as hoped:
However, when it's actually running, stretching the dialog does not increase the size of the listbox:
Why is this not working? Is there some additional voodoo I have to invoke to get it to actually work? Does this only work in MFC? What is the Win32 equivalent of CWnd::ExecuteDlgInit?
Note: I have already looked at https://msdn.microsoft.com/en-us/library/mt270148.aspx and http://mariusbancila.ro/blog/2015/07/27/dynamic-dialog-layout-for-mfc-in-visual-c-2015/, wherein I did not find an answer.
Does this only work in MFC?
Indeed, this only works when using MFC1.
What is the Win32 equivalent of CWnd::ExecuteDlgInit?
MFC is a library built on top of the Windows API. The windowing system in the Windows API does not provide any sort of layout management. If you want to see the Windows API equivalent, it's literally what is implemented in MFC.
So, why is this supported in the graphical resource editor then? Because that is where the layout information is generated. It's ultimately placed into a custom resource of type AFX_DIALOG_LAYOUT, where MFC picks it up to do its magic. If you aren't using MFC, that resource is simply ignored.
That's not to say that - in theory - you wouldn't be able to implement your own solution that reads the generated resource. As long as you can find documentation for the custom resource used by MFC. I didn't, but a look into the MFC source revealed, that it's pretty simple (a version WORD, followed by pairs of WORDs for horizontal and vertical move and size settings).
1 Or a library that understands the implementation details, such as the WTL.
This functionality is also supported in Windows Template Library!
https://sourceforge.net/p/wtl/git/ci/master/tree/Include/atlframe.h
If you have a look at the CDynamicDialogLayout class you can see how it works, and if you are using WTL you can even use the functionality yourself.
For the record, I was looking for the solution to this as well, when I resized a control on my dialog all of the dynamic resizing stopped working, although it worked fine in the Test Mode.
To fix it, in the the second link you posted there's a section on adding a function:
void CMFCDynLayoutDemoDlg::SetupDynamicLayout()
Where you re-setup the Dynamic Layout manager
Once I did this, it started working in the live version for me.
Very similar answer is in this post too:
Recalculate dynamic layout properties
I have a CListCtrl that creates a child CStatusBar (for displaying statistics etc).
All works fine (except for when using CMFCTabCtrl, but that's another story).
When I use this CListCtrl in a resizable dialog, it appears the framework signals the CStatusBar to automatically add a SBARS_SIZEGRIP, which I do not want.
Any ideas on how to disable this behavior for my CStatusBar?
If you use a CStatusBar SBARS_SIZEGRIP style is added when the parent frame has the style WS_THICKFRAME (see source code VC\atlmfc\src\mfc\barstat.cpp CStatusBar::CreateEx).
It should be easy to prevent this when you overwrite PreCreateWindow and remove this style.
Note that the behaviour of CMFCStatusBar is different.
I need to extend an existing MFC app with a UI that will end up very cluttered unless I use a tab control. However, the nature of the UI is that there are some controls that are global, and only some that can be localised to a particular tab.
The standard use of tab controls (CPropertySheet + CPropertyPage) more or less expects there only to be CPropertyPage instances (tabs) visible on the CPropertySheet object, and nothing else. There is a Microsoft Example Project that shows a single additional window painted outside the area occupied by the tab control... but it's not immediately clear how it is created/drawn/handled, and it is only one single additional window that generates few events (I guess it is painted, so there must be a WM_PAINT event handler lurking somewhere).
Is it possible to lay out a bunch of controls with the MS Dialog Editor, including a tab control, and create the CPropertySheet using that template, hook up event handlers in a nice way, etc... or some equivalent way of getting the MFC framework to do as much of the creating, drawing and event handling as possible when it comes to a situation like this?
Yes it is possible to create dialog templates and use them in a CPropertyPage.
Each CPropertyPage behaves nearly like a dialog and handles all events for the controls on it.
Also there are features like OnApply that help you to manage the data exchange between the controls and your internal storage.
The central CPropertySheet only creates the dialog that get active. So OnInintDialog for a page is called the first time when the page gets active.
In the MFC since 2010 are more possibilities than a CPropertySheet. You can create tabbed views, that again may be CFormViews. I don't like CDialog based applications so I would prefer a tabbed view in a standard frame with toolbar and menus if appropriate for the application. So another method to unclutter your UI is to choose the MDI interface with tabbed documents... but multiple documents maybe isn't what you want.
Here is a sample of an SDI application with multiple tabbed views.
Also Coeproject shows some more samples here and with splitters and tabs here.
There are at least three solutions paths:
Try to squeeze the situation into the CPropertySheet + CPropertyPage framework which does not naturally allow for additional dialog controls on the CPropertySheet object, and so you will get no framework support this
Place a tab control on an ordinary dialog, and then use the TCN_SELCHANGE messages to fire code that manually hides & shows individual dialog controls subject to the tab control (again no framework support, but this time "within" the tab control instead of outside it)
Follow Mark Ransom's observation that if you can embed one kind of CWnd-based control on a CPropertySheet then you can probably embed any such object, including a CDialog-based object that has been developed in the MFC Dialog Editor
All of these approaches are going to encounter challenges, and it will depend on the specifics of the situation as to which is better. But first you should really consider whether there is a cleaner UI design which would lend itself to a simpler solution.
In my specific case, I saw no cleaner design alternatives, and found it easiest to take the second approach. It left me with some reasonably simple calls to ShowWindow() to show/hide the controls inside the tab control.
I am trying to create a tab-control that have the tab-buttons aligned from right-to-left, in Win32/c++. The WS_EX_LAYOUTRTL flag doesn't help me, as it mirrors the drawing completely both for the tab items and the tab page contents. The application itself handles the mirroring automatically (it's a cross platform UI solution), which is also a reason for us not to use WS_EX_LAYOUTRTL flag (we have mirroring implemented in a generic way for all UI frameworks/platforms).
One solution would be to override TCM_GETITEMRECT and TCM_HITTEST in the subclassed TabCtrls window procedure. This enables me to move the buttons allright, but the mouse events still acts on the positions that the control "knows" the buttons really are at (ie. mouseover on the first button invalidates the leftmost button - the coordinates are not mirrored).
So that seems to be a dead end for me.
Another possibility would be to insert padding before the first tab button, to push them all to the right edge. I haven't been able to figure out how to do that, though. Visual Studio sports this little dialog:
How did they put the buttons in front of the first tab page? Knowing this would enable me to solve this problem.
Update, solution:
The solution to my problem is to use the built-in RTL support. For this to work, the tab control must have both the WS_EX_LAYOUTRTL and WS_EX_NOINHERITLAYOUT flags. That will preserve the function of all existing drawing code while only the TabCtrl buttons are mirrored. I didn't realize that the ES_EX_NOINHERITLAYOUT flag goes on the parent (the TabCtrl), which is why I was looking for the workaround originally described.
For reference, I am still curious to have an answer to the original question, though.
If you take a look with a spy application you will see that it is not actually a normal windows tab-control but custom thing and the drawing is done by the parent window AFAIK:
Both Visual Studio and Office use a lot of custom controls, some of the features make their way into the common controls after a few years, some features stay private...
How do I have a CEdit control display placeholder text when it's empty, similar to the behavior of NSTextFields in Cocoa?
Ages ago, I wrote a custom paint routine to do it, seemed to work fine.
Sometime after, they introduced SetCueBanner to CEdit, but I can remember it:
a) not working correctly
or -
b) not behaving the way I wanted
Perhaps it will work fine for you. If not, I can see if I can find my old code and post what I did in the custom paint routine.
EDIT
I just checked the Win32 docs, I think this is why I abandoned it:
You cannot set a cue banner on a multiline edit control
you could create a small window over the top of it that contains the placeholder text. Then when the user sets the keyboard focus to it hide the window and if the focus is removed and nothing is in the box then show it.
The SetCueBanner banner function is now working.