|
|
Comments and Discussions
|
|
 |

|
Is it possible to let the resize class support change its properties dynamically? For example, for one case I need set DLSZ_SIZE_X peroperty to IDOK, while for another case I need set DLSZ_SIZE_Y perproperty to IDOK.
Tang
|
|
|
|

|
I have used WTL for 10 years and thanks to Mike's explanations many of WTL's obscurities were revealed in this exceptional tutorial. Thank you Mike!
|
|
|
|

|
I built this under VS2005 and WTL80 and the dialog would not resize until I added the WS_THICKFRAME style to the dialog template as specified in ATLFRAME.H:
///////////////////////////////////////////////////////////////////////////////
// CDialogResize - provides support for resizing dialog controls
// (works for any window that has child controls)
// Put CDialogResize in the list of base classes for a dialog (or even plain window),
// then implement DLGRESIZE map by specifying controls and groups of control
// and using DLSZ_* values to specify how are they supposed to be resized.
//
// Notes:
// - Resizeable border (WS_THICKFRAME style) should be set in the dialog template
|
|
|
|

|
There was a breaking change in WTL 7.5. In 7.0, DlgResize_Init() had this prototype:void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true,
DWORD dwForceStyle = WS_THICKFRAME | WS_CLIPCHILDREN);But in 7.5, it'svoid DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true,
DWORD dwForceStyle = WS_CLIPCHILDREN);Notice WS_THICKFRAME was removed from dwForceStyle's default value.
|
|
|
|

|
hmmm, I see
thanks
BTW:WS_SIZEBOX also works good~
|
|
|
|

|
Hi Michael,
Thanks for a most series of articles on WTL. Only just started with WTL, but I'm loving it already!
I have a question about the problem you highlighted with the AppWizard generated code that is exposed when you add CDialogResize as a base class of your dialog.
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/,
LPTSTR lpstrCmdLine, int nCmdShow)
{
// ...
CMainDlg dlgMain;
int nRet = dlgMain.DoModal();
_Module.Term();
::CoUninitialize();
return nRet;
}
int nRet;
{
CMainDlg dlgMain;
nRet = dlgMain.DoModal();
}
I'm using WTL 8.0 (same as WTL 7.5 except AppWizard and docs has been updated for VS 2005). I've created a modeless dialog based app using the AppWizard which has generated the following code. Am I right in thinking that because CMainDialog is instantiated (correct terminology ?) in the Run() function, the destructor for CMainDialog is called when Run() exits (and so before _Module.Term() is called). Hence, this code is now safe ?
CAppModule _Module;
int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
CMessageLoop theLoop;
_Module.AddMessageLoop(&theLoop);
CMainDlg dlgMain;
if(dlgMain.Create(NULL) == NULL)
{
ATLTRACE(_T("Main dialog creation failed!\n"));
return 0;
}
dlgMain.ShowWindow(nCmdShow);
int nRet = theLoop.Run();
_Module.RemoveMessageLoop();
return nRet;
}
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
HRESULT hRes = ::CoInitialize(NULL);
// If you are running on NT 4.0 or higher you can use the following call instead to
// make the EXE free threaded. This means that calls come in on a random RPC thread.
// HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
ATLASSERT(SUCCEEDED(hRes));
// this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used
::DefWindowProc(NULL, 0, 0, 0L);
AtlInitCommonControls(ICC_BAR_CLASSES); // add flags to support other controls
hRes = _Module.Init(NULL, hInstance);
ATLASSERT(SUCCEEDED(hRes));
int nRet = Run(lpstrCmdLine, nCmdShow);
_Module.Term();
::CoUninitialize();
return nRet;
}
|
|
|
|

|
Defenestration wrote: Am I right in thinking that because CMainDialog is instantiated (correct terminology ?) in the Run() function, the destructor for CMainDialog is called when Run() exits (and so before _Module.Term() is called). Hence, this code is now safe ?
Yes.
--Mike--
Visual C++ MVP
LINKS~! Ericahist | PimpFish | CP SearchBar v3.0 | C++ Forum FAQ
|
|
|
|

|
Thanks Mike. Just thought I'd double-check.
|
|
|
|
|
|

|
That one isn't WTL compatible, which would rather defeat the object; it also looks like you're indulging in a bit of self promotion.
FWIW In the 6 years since I posted that message I've found the built-in WTL resizer more than capable of virtually everything I've needed to do. For the special cases, there are certainly more capable WTL resizers around - but yours isn't one of them as it is built for MFC.
Anna
Tech Blog | Visual Lint
"Why would anyone prefer to wield a weapon that takes both hands at once, when they could use a lighter (and obviously superior) weapon that allows you to wield multiple ones at a time, and thus supports multi-paradigm carnage?"
|
|
|
|

|
I can't figure out how to center controls (horizontally or vertically) on a dialog. It looks like this (quite obvious) functionality is not supported by CDialogResize. I was trying to join controls in a group, to add invisible anchor windows with no result.
Dos anybody know about possible workarounds for this?
Thanks!
|
|
|
|

|
If it helps, I derived a virtual function in a child class. It's a bit whacky, it exploits the group rectangle but needs to know which item in the group to position it correctly.
You then write a group into the class definition in the form:
BEGIN_DLGRESIZE_MAP(CChildDlg)
DLGRESIZE_CONTROL(IDC_LIST,DLSZ_SIZE_X | DLSZ_SIZE_Y)
BEGIN_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDOK,DLSZ_CENTER_X | DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDCANCEL,DLSZ_CENTER_X | DLSZ_MOVE_Y)
END_DLGRESIZE_GROUP()
END_DLGRESIZE_MAP()
And now the virtual function in the child class:
bool CChildDlg::DlgResize_PositionControl
(
int in_nWidth,
int in_nHeight,
RECT & in_sGroupRect,
_AtlDlgResizeData& in_sData,
bool in_bGroup,
_AtlDlgResizeData* in_pDataPrev
)
{
bool l_bSuccess = true;
{
DWORD l_nOldFlags = in_sData.m_dwResizeFlags;
in_sData.m_dwResizeFlags &= ~(DLSZ_CENTER_X | DLSZ_CENTER_Y);
l_bSuccess = CPlayerDlg_Resize::DlgResize_PositionControl
(
in_nWidth,
in_nHeight,
in_sGroupRect,
in_sData,
false, in_pDataPrev
);
in_sData.m_dwResizeFlags = l_nOldFlags;
}
if (in_bGroup && (in_sData.m_dwResizeFlags & (DLSZ_CENTER_X | DLSZ_CENTER_Y)))
{
int l_nGroupStart = -1;
for (int l_nPos = m_arrData.Find(in_sData); l_nPos > 0; l_nPos--)
{
if (0 != (m_arrData[l_nPos].m_dwResizeFlags & _DLSZ_BEGIN_GROUP))
{
l_nGroupStart = l_nPos;
break;
}
}
ATLASSERT(-1 != l_nGroupStart);
int l_nItem = m_arrData.Find(in_sData) - l_nGroupStart;
int l_nItems = m_arrData[l_nGroupStart].GetGroupCount();
CRect l_cArea;
CWindow l_cCtrl;
l_cCtrl.Attach(GetDlgItem(in_sData.m_nCtlID));
l_cCtrl.GetWindowRect(l_cArea);
ScreenToClient(l_cArea);
if (in_sData.m_dwResizeFlags & DLSZ_CENTER_X)
{
int l_nGroupWidth = in_sGroupRect.right - in_sGroupRect.left;
int l_nGroupStart = (in_nWidth / 2) - (l_nGroupWidth / 2);
int l_nSegment = l_nGroupWidth / l_nItems;
l_cArea.MoveToX(l_nGroupStart + (l_nSegment * l_nItem));
}
if (in_sData.m_dwResizeFlags & DLSZ_CENTER_Y)
{
int l_nGroupHeight = in_sGroupRect.bottom - in_sGroupRect.top;
int l_nGroupStart = (in_nHeight / 2) - (l_nGroupHeight / 2);
int l_nSegment = l_nGroupHeight / l_nItems;
l_cArea.MoveToY(l_nGroupStart + (l_nSegment * l_nItem));
}
if ((in_sData.m_dwResizeFlags & DLSZ_REPAINT) != 0)
l_cCtrl.Invalidate();
l_cCtrl.SetWindowPos(NULL, &l_cArea, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE);
l_cCtrl.Detach();
}
return l_bSuccess;
}
|
|
|
|

|
Hello,
I'm dynamically creating my buttons, so once I add the button to
DLGRESIZE_CONTROL(IDD_BUTTON_OK, DLSZ_MOVE_X | DLSZ_MOVE_Y)
The coordinate system seems to completely change (0,0) is not the top of the window but somewhere in the middle.
Can you guys suggest me how to do it? I want to place the button in right bottom corner of my screen (its not a dialog but a View CDialogImpl).
Thanks.
|
|
|
|
|
|

|
I have a dialog that I am showing Modal (In a seperate thread) with a single static image. I would just like to allow resizing and show scroll bars when the dialog gets too small. It would also be great if I could limit the max and min size of the dlg.
Please Help
-- Rick
|
|
|
|

|
Nice example, but with one problem. In my app COM is initialized through CoInitializeEx(NULL, COINIT_MULTITHREADED) in place of CoInitialize(NULL), because my app use COM object, that return events from different thread and without COINIT_MULTITHREADED it crash all app on shutdown. An in that case, when dialog opens, WebBrowser control is drawed out of dialog on left top side of desktop (at dialog remain empty rectangle, that is not be updated anymore. Without COINIT_MULTITHREADED dialog works as expected. Where is problem, i don't know
|
|
|
|

|
I found source of this problem - WebBrowser ActiveX control needs STA to run, that means, app must be intialized through CoInitialize(NULL) or CoInitializeEx(NULL, COINIT_APARTAMENTTHREADED). Then i redesigned our dialog for work in different thread:
void CReportManager::StartReport()
{
Lock();
.....
// Create report window thread.
DWORD dwThreadId;
HANDLE hThread = ::CreateThread(NULL, 0, CReportManager::ReportFunction, this, 0, &dwThreadId);
if (hThread == NULL)
{
ATLTRACE(_T("* Unable to create report window thread."));
Cancel();
Unlock();
return;
}
::CloseHandle(hThread);
.....
Unlock();
}
// Report manager client window thread function.
DWORD WINAPI CReportManager::ReportFunction(LPVOID lpParam)
{
CReportManager* pThis = reinterpret_cast(lpParam);
volatile BOOL *bWorking = &pThis->m_bWorking;
if (bWorking && pThis->m_rptState == rptRunning)
{
// Reinitialize COM to STA for this thread.
::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
CReportViewDlg dlg(pThis->m_strTitle);
dlg.DoModal(g_pwndMain->m_hWnd);
pThis->m_hWndRpt = NULL;
::CoUninitialize();
}
return 0;
}
Now all works as i expected
|
|
|
|
|

|
Check your tab order - the list controls need to be after the tab control in the tab order. The tab order is also the Z-order, so if the tab control comes first, it will be above the lists in the Z-order. In that case, the lists won't repaint because the system sees that they're completly covered by the tab control.
--Mike--
Ericahist | CP SearchBar v2.0.2 | Homepage | RightClick-Encrypt | 1ClickPicGrabber
#include "witty-quote.h"
|
|
|
|

|
Hi,
I have a TabCtrl on my dialog and it resizes well.
I wonder how to resize the dialogs attached to the tab automatically since I cannot add my dialogs shown on the tabs using
DLGRESIZE_CONTROL(IDD_DIALOG2, DLSZ_SIZE_X|DLSZ_SIZE_Y)
to the resize-method, because the dialog does naturally not exist by the time that code (macro) ist executed. The dialogs for the tabs are (only) created in the OnInitDialog-handler of the dialog tha contains the TabCtrl.
Do I in any case have to track the resize of the tab, or is there a way to track the resize with the CDialogResize-class and attach the dialogs to that class?
Best,
Bernhard
|
|
|
|

|
Anyone found a solution to this one, I have exactly the same problem, my tab container resizes fine but the child windows within it stay the same.
Cheers,
Rob.
|
|
|
|

|
When using a CTabCtrl, for the child windows I create a CDialogImpl-derived class to handle the dialog items, etc (I guess you've done the same thing). In this class I placed the code just as Michael described, but in the WM_INITDIALOG handler I changed the style to my dialog's. Damn, I'm bad at describing things, so here's my code:
class CProductInventoryView :
public CDialogImpl<CProductInventoryView>,
public CDialogResize<CProductInventoryView>
{
public:
enum { IDD = IDD_PRODUCT_VIEW_INVENTORY };
BEGIN_MSG_MAP(CProductInventoryView)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
CHAIN_MSG_MAP(CDialogResize<CProductInventoryView> )
END_MSG_MAP()
BEGIN_DLGRESIZE_MAP(CProductInventoryView)
...etc...
END_DLGRESIZE_MAP()
protected:
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
};
LRESULT CProductInventoryView::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DlgResize_Init(false, true, DS_SETFONT | DS_FIXEDSYS | WS_CHILD);
return S_OK;
}
and it's working for me. Hope this helps (although this post is two years from the OP).
Stupidity is an International Association - Enrique Jardiel Poncela
|
|
|
|

|
Any tips on setting the initial dialog size without the controls being placed incorrectly? I want to have persistent dialog sizes (size saved to the registry) but when I call SetWindowPos in OnInitDialog, it ends up a real mess. I have tried various hacks but haven't found an effective solution...
When I am king, you will be first against the wall.
|
|
|
|

|
This may/may not help, but there is a bug in WTL 7.0 whereas a resize of a hidden dialog can cause all kinds of resize issues. In my case, it was cutting off certain HTML items from the page that should have appeared on the right. On the yahoo WTL group, there is a post on a WTL 7.0 CDialogResize issue that aids in fixing this outright (by modifying atlframe.h). My fix was to first do a ShowWindow(SW_SHOW), then provide a SetWindowPos call.
|
|
|
|

|
With WinXP and VC.NET 2003
I'm using DialogResize in a dialog box created as a child window. When the dialog resizes all combo boxes with the droplist style have their text magically selected. The text wasn't selected before the move. This is most annoying.
Any one have any idea's what is going on?
|
|
|
|

|
Is exactly what i needed !
Adrian Bacaianu
|
|
|
|
|

|
Well done Michael. I just added a resizeable dialog to my WTL app in minutes.
When I am king, you will be first against the wall.
|
|
|
|

|
Just solved a really dumb problem I was having. I'm creating a dialog with dynamic controls, i.e. a blank template. The default template doesn't have a system/min/max menu. Without those the window won't resize. So remember to set the properties on your dialog template properly or no resizing for you! Thanks for the very useful article.
|
|
|
|

|
Hi, I'm new to WTL and trying to develop dynamic dialog controls, wondering how did you use the resizing in dynamically allocated controls. If you can give me a start, will be grateful.
Thanks,
Pathman
|
|
|
|

|
Sure, it was actually really easy in my case. Although the controls are dynamically created I know the IDs of the controls at compile time. So I built a static DLG_RESIZE_MAP with the IDs of all the controls that will be on the dialog and then when I create the controls they are resized.
|
|
|
|

|
Additional issue what I've really had. A dialog won't resize if its border doesn't have Resizing type.
|
|
|
|

|
C:\garbage\wtldlgresize_demo\WtlBrowser\WtlBrowser.rc(10) : fatal error RC1015: cannot open include file 'atlres.h'
|
|
|
|
|

|
First, a control can appear more than once in the resize map. This allows you to control movement in one direction as part of a group, while using ungrouped movement in the other direction. For instance:
BEGIN_DLGRESIZE_MAP(CNotesDlg)
BEGIN_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDC_BTN_FIRSTNOTE, DLSZ_MOVE_X)
DLGRESIZE_CONTROL(IDC_BTN_PREVNOTE, DLSZ_MOVE_X)
DLGRESIZE_CONTROL(IDC_BTN_NEXTNOTE, DLSZ_MOVE_X)
DLGRESIZE_CONTROL(IDC_BTN_LASTNOTE, DLSZ_MOVE_X)
END_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDC_BTN_FIRSTNOTE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PREVNOTE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_NEXTNOTE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_LASTNOTE, DLSZ_MOVE_Y)
END_DLGRESIZE_MAP()
Second, when using a group, the controls are anchored by the leftmost control in the group. This can look strange if that control is not at the left margin of the dialog, for example, and the dialog is stretched significantly in the x direction. To avoid this, an invisible control can be used as an anchor point.
John
|
|
|
|

|
The problem you mention with the controls shifting by one pixel on the first resize, I ran into this myself. It is actually not an off-by-one bug. It is because your dialog is designed with the "Thin" border style in the resource editor. CDialogResize forces the WS_THICKFRAME style, causing the dialog's client area to shrink slightly. If the dialog template already has a resizing border then the problem does not occur. Cheers, - Jim Jim Barry <jim@mvps.org> MVP for Windows SDK
|
|
|
|

|
Jim Barry wrote:
If the dialog template already has a resizing border then the problem does not occur.
sweet, I never thought to look at that.
Odd that the controls don't shift on XP when using the default theme, maybe the dialog and resizing borders are the same size.
--Mike--
Just released - RightClick-Encrypt v1.3 - Adds fast & easy file encryption to Explorer
My really out-of-date homepage
Sonork-100.19012 Acid_Helm
|
|
|
|

|
Michael Dunn wrote:
Odd that the controls don't shift on XP when using the default theme, maybe the dialog and resizing borders are the same size.
Interestingly, no, that's not it. With the XP theme enabled, SM_CXFIXEDFRAME is still 3 and SM_CXSIZEFRAME is still 4 (default), but the client area gets shrunk before the dialog is shown instead of when the dialog is first resized. Wacky, huh?
- Jim
|
|
|
|

|
I'm trying to use CDialogResize with a project and have a problem. At the top of the dialog is a group box. Inside the group box, left to right, are a bit of static text, a combobox, and a button. Using CDialogResize I've gotten everything sizing and moving as it should. But the space inside the group box that's not covered by some other control isn't getting erased and repainted. Help! I really don't want to have to rip this out and do all the resizing "by hand". haldevore@yahoo.com
|
|
|
|

|
Never fails, post to a public place and the stupid thing you've done becomes immediately obvious.
The group boxes were not set to transparent.
haldevore@yahoo.com
|
|
|
|
|

|
Dir Michael Dunn,
I am a beginner in ATL/WTL. I found your article and I like it very much!
But I want to ask you how to sink IE control events in your project? For example, if I navigated the first site, the button Back and Forward is disable. While I am navigating some address, the button Stop is enable, and so on.
I've try by mysefl but it's very hard. Because I'm a beginner!
Thank you very much!
Lightmas and happy new year!
Nguyen Huu Quynh
|
|
|
|

|
It appears that if a contol is on the left side of center on the dialog, it is anchored to the left side, similarly with the right side of center.
Also, if a control is set to resize, it is anchored to the top/left/top left. Is this the case, or do you set it somewhere I haven't noticed?
Thanks
|
|
|
|

|
The Resize is a cool dialog, But I am having some trouble getting the control to work on a dialog that doesnt have the WS_THICKFRAME or any other border frame set.
Is there a resolution for this ? Also is there any way to change the appearance of the resizing control ?
|
|
|
|

|
Handle the WM_NCHITTEST message, and when the cursor is near the edge of the dialog, return the proper HTxxx constant (HTLEFT, HTRIGHT, etc.). (This is how you do it for straight Win32 dialogs; I don't know if this'll work with CDialogResize. Give it a try.)
--Mike--
http://home.inreach.com/mdunn/
"Make sure that if you are using a blow torch that you don't set anything on fire."
-- Chris Maunder
|
|
|
|

|
I couldn't compile your example until I added #include <atlframe.h> to stdafx.h.
Nevertheless a useful article.
Regards,
Thomas
I am a signature virus!
Help me spread and copy me to your sig!
|
|
|
|

|
hmm, do you mean that the demo project is missing this include? I thought the WTL AppWizard created an #include for atlframe automagically.
--Mike--
http://home.inreach.com/mdunn/
We've secretly replaced the msdn.microsoft.com servers with Atari 800XLs. Let's see if anyone notices....
|
|
|
|

|
Add WS_OVERLAPPED to make the control paint nicer.
DlgResize_Init(true,true,WS_THICKFRAME|WS_CLIPCHILDREN|WS_OVERLAPPED);
Jimmy Hoffa
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
How to use WTL's built-in support for resizable dialogs
| Type | Article |
| Licence | |
| First Posted | 24 Jun 2001 |
| Views | 212,123 |
| Downloads | 1,831 |
| Bookmarked | 76 times |
|
|