stefanr
asked on
Programatically repositioning Common Dialog
I have tried to create a Common Dialog (for testing, a CFileDialog). The problem is that it is always created centered in its owners window (which not necessarily is the window that created it). I have tried to use an overlaid OnInitDialog and also OnInitDone to call SetWindowPos to change its starting position. OnInitDialog made no difference, and OnInitDone strangely enough positioned it in the owner windows upper left corner, but not where I wanted it to be. When I checked the result from a GetWindowRect in OnInitDialog it claimed that the window were 0 in height and 0 in width. In OnInitDone it said that the dialog had a height, but not a width (or if it was the other way around). I even tried to create a timer to call SetWindowPos (I tried MoveWindow too) delayed to a later time, but it gave no result.
The question is simple: how can I programatically position a Common Dialog centered around a point on the screen that I decide ? Preferrably with a global function, say ::AfxSetCommonDialogPos(x, y), that would affect any Common Dialogs created and shown after that (even underived CFileDialog, CPrintDialog, etc.).
I am using Windows NT 4.0 and Microsoft Visual C++ 5.0. The system has two displays, where our program wants to be able to move the Common Dialog away from the middle of the desktop, where it is cut in half between the displays. The program can also be configured to use the displays either horizontally or vertically.
I hope you can help us.
The question is simple: how can I programatically position a Common Dialog centered around a point on the screen that I decide ? Preferrably with a global function, say ::AfxSetCommonDialogPos(x,
I am using Windows NT 4.0 and Microsoft Visual C++ 5.0. The system has two displays, where our program wants to be able to move the Common Dialog away from the middle of the desktop, where it is cut in half between the displays. The program can also be configured to use the displays either horizontally or vertically.
I hope you can help us.
Try add BOOL flFirstPaint in your dialog class and init it with TRUE in constructor. Handle WM_PAINT message and add code like this:
if( flFirstPaint )
{
// calculate coordinaties
MoveWindow( ... );
flFirstPaint = FALSE;
}
if( flFirstPaint )
{
// calculate coordinaties
MoveWindow( ... );
flFirstPaint = FALSE;
}
ASKER
Well, I didn't get that approach to work. However, when I had read the Comment from The Master, I began to think...
As I mentioned earlier, I had tried to use an overlaid OninitDone, using GetWindowRect resulting in a rect with zero width but a positive value on the height. In OnInitDone I had zero in both the width and height. Obviously it seemed that the dialog wasn't fully constructed in OnInitDialog.
Checking out Spy, as proposed by The Master, and checking the values of the different HWND:s from the CFileDialog, its owner and parent (GetOwner(), GetParent()) I came to the following conclusion:
The CFileDialogs real window pointer is returned by GetOwner(), and should be used for SetWindowPos. Furthermore, the parent to the dialog is returned by calling GetOwner()->GetParent().
To conclude the result of my experiment (with CFileDialog so far, I haven't tested the other Common Dialogs yet) the code I have come up with is this:
class CTestFileDialog : public CFileDialog
{
...
void SetCenterPoint(BOOL bUseCenterPoint, int x, int y)
{
if (bUseCenterPoint)
{
m_ptCenter.x = x; m_ptCenter.y = y;
}
m_bUseCenterPoint = bUseCenterPoint;
}
...
protected:
//{{AFX_MSG(CTestFileDialo g)
//}}AFX_MSG
virtual void OnInitDone();
DECLARE_MESSAGE_MAP()
CPoint m_ptCenter;
BOOL m_bUseCenterPoint;
};
void CTestFileDialog::OnInitDon e()
{
CFileDialog::OnInitDone();
if (m_bUseCenterPoint)
{
CWnd* pThisWnd = GetOwner(); // Special for a Common Dialog.
//CWnd* pParentWnd = pThisWnd->GetParent(); // Special for a Common Dialog.
CRect rect(0, 0, 0, 0);
pThisWnd->GetWindowRect(re ct); // This is the rect of the Common Dialog itself.
CPoint ptUL(m_ptCenter.x-rect.Wid th()/2, m_ptCenter.y-rect.Height() /2); // m_ptCenter is defined as window coordinates (as returned from GetWindowRect).
pThisWnd->SetWindowPos(NUL L, ptUL.x, ptUL.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
}
This seems to do exactly what we wants to.
The code doesn't work if put in OnInitDialog, only in OnInitDone.
If using Pre-VC++ 5.0, the OnInitDone doesn't exist. In that case a hook function must be chained to the default pointed to by m_ofn.lpfnHook.
Thank you anyway.
As I mentioned earlier, I had tried to use an overlaid OninitDone, using GetWindowRect resulting in a rect with zero width but a positive value on the height. In OnInitDone I had zero in both the width and height. Obviously it seemed that the dialog wasn't fully constructed in OnInitDialog.
Checking out Spy, as proposed by The Master, and checking the values of the different HWND:s from the CFileDialog, its owner and parent (GetOwner(), GetParent()) I came to the following conclusion:
The CFileDialogs real window pointer is returned by GetOwner(), and should be used for SetWindowPos. Furthermore, the parent to the dialog is returned by calling GetOwner()->GetParent().
To conclude the result of my experiment (with CFileDialog so far, I haven't tested the other Common Dialogs yet) the code I have come up with is this:
class CTestFileDialog : public CFileDialog
{
...
void SetCenterPoint(BOOL bUseCenterPoint, int x, int y)
{
if (bUseCenterPoint)
{
m_ptCenter.x = x; m_ptCenter.y = y;
}
m_bUseCenterPoint = bUseCenterPoint;
}
...
protected:
//{{AFX_MSG(CTestFileDialo
//}}AFX_MSG
virtual void OnInitDone();
DECLARE_MESSAGE_MAP()
CPoint m_ptCenter;
BOOL m_bUseCenterPoint;
};
void CTestFileDialog::OnInitDon
{
CFileDialog::OnInitDone();
if (m_bUseCenterPoint)
{
CWnd* pThisWnd = GetOwner(); // Special for a Common Dialog.
//CWnd* pParentWnd = pThisWnd->GetParent(); // Special for a Common Dialog.
CRect rect(0, 0, 0, 0);
pThisWnd->GetWindowRect(re
CPoint ptUL(m_ptCenter.x-rect.Wid
pThisWnd->SetWindowPos(NUL
}
}
This seems to do exactly what we wants to.
The code doesn't work if put in OnInitDialog, only in OnInitDone.
If using Pre-VC++ 5.0, the OnInitDone doesn't exist. In that case a hook function must be chained to the default pointed to by m_ofn.lpfnHook.
Thank you anyway.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Edited text of question
ASKER
Your proposal is a very good one, indeed ! It reminds somewhat of my own solution above, but with some additional functionality, as a customized dialog box etc.
What I meant by a AfxSetCommonDialogPos global function was that I could call it once somewhere in the application, and that any Common Dialogs created and shown after that would center around that point, even if the dialog was not derived further from CFileDialog etc.
Like this:
BOOL CTestApp::InitInstance()
{
...
if (m_nSysConfig == DUAL_SCREEN_HORIZONTAL)
{
...
::AfxSetCommonDialogPos(m_ x, m_y);
...
}
}
...
CTestView::OnOpenDatabase( )
{
CFileDialog dlg(TRUE);
if (dlg.DoModal() == IDOK)
{
...
}
}
Good work !
What I meant by a AfxSetCommonDialogPos global function was that I could call it once somewhere in the application, and that any Common Dialogs created and shown after that would center around that point, even if the dialog was not derived further from CFileDialog etc.
Like this:
BOOL CTestApp::InitInstance()
{
...
if (m_nSysConfig == DUAL_SCREEN_HORIZONTAL)
{
...
::AfxSetCommonDialogPos(m_
...
}
}
...
CTestView::OnOpenDatabase(
{
CFileDialog dlg(TRUE);
if (dlg.DoModal() == IDOK)
{
...
}
}
Good work !
Good luck!