When F is instantiated by its parent dialog using DoModal, it creates
the modeless dialog A:
A.Create(IDD_A,this);
I attempted to position A using code in F. Guide2 is a static control
in F at the desired initial position of A:
CRect r;
A.GetWindowRect(&r); // to get the dimensions of A,
needed for MoveWindow
int w=r.Width(),h=r.Height();
CStatic *pStatic;
pStatic=(CStatic *)GetDlgItem(IDC_Guide2); // get the desired
position for A
pStatic->GetWindowRect(&r);
A.MoveWindow(r.left,r.top,w,h,TRUE/*repaint*/);
A.ShowWindow(SW_SHOW);
This code repositions the modeless dialog A, but not at the correct
spot.
The documentation for MoveWindow says that the coordinates are client
wrt the parent, but screen if A is a "top-level window". Although A
was created with F as a parent, Spy++ and GetParent both indicate that
it has no parent.
I tried converting the guide coordinates from screen to client, in
case MoveWindow was using client coords of F; this didn't work either.
How can I reposition the modeless dialog A at a known position with
respect to modal dialog F, its creator?
>I have a model dialog, F. F has a modeless dialog, A, which is
>intended to show on top of F (user drags A to different locations of
>F).
>
>When F is instantiated by its parent dialog using DoModal, it creates
>the modeless dialog A:
>
> A.Create(IDD_A,this);
***
This line makes no sense at all. The variable A is declared somewhere, and has a type.
Both of these are critical to the understanding of what is going on. Therefore, it is
meaningless to give this statement without specifying the declaration of the variable, and
state where it is declared.
I would do this by doing
class CFDlg : public CDialog {
protected:
CADlg * A;
... etc.
};
to show where the variable is declared (it has to be at the scope of the F class; it is
meaningless to declare it as a local variable, and therefore it is impossible access it
using ".", as in "A.Create". If you do not get a syntax error, it means your declaration
is wrong, and probably, furthermore, in the wrong place. So the example as presented
cannot possibly work)
Then, you would show:
CFDlg::CDDlg(...etc...) : ...etc...
{
A = NULL;
}
to show that it is set to NULL in the constructor. Then you need show the instantiation
BOOL CFDlg::OnInitDialog()
{
...etc....
A = new CADlg;
A->Create(CADlg::IDD);
...maybe other stuff,,,
return TRUE;
}
Note that the correct form is NOT use use IDD_A, but the appropriate IDD name, which is
CADlg::IDD.
I would then create a PostNcDestroy handler:
void CADlg::PostNcDestroy()
{
delete this;
CDialog::PostNcDestroy();
}
Because A is a modeless dialog, I would add handlers to override the default OK and Cancel
events:
void CADlg::OnOK()
{
}
void CADlg::OnCancel()
{
}
I would then add on OnDestroy handler in the parent dialog
void CFDlg::OnDestroy()
{
if(A != NULL)
A->DestroyWindow();
Now you would have the essential infrastructure for doing a modeless dialog.
You have shown none of this, nor have you indicated that any of it has been done.
****
>
>I attempted to position A using code in F. Guide2 is a static control
>in F at the desired initial position of A:
>
> CRect r;
> A.GetWindowRect(&r); // to get the dimensions of A,
>needed for MoveWindow
> int w=r.Width(),h=r.Height();
****
Never declare more than one variable on a line. NEVER initialize more than one variable
on a line. ALWAYS put a space after a comma when one appears in a separator context. The
line is unreadable as written, and should have been written as
CSize sz(r.Width(), r.Height());
****
> CStatic *pStatic;
> pStatic=(CStatic *)GetDlgItem(IDC_Guide2); // get the desired
>position for A
> pStatic->GetWindowRect(&r);
****
Why would you write a GetDlgItem call for any control? If you are writing more than one a
year, you are not using MFC correctly. Therefore, we will assume that you have created a
CStatic control variable for guide2, which would be added by the Add Variable menu item
(right click on the stack control), and therefore this gibberish will disappear, and you
will write something like as shown below (where c_Guide2 is the name of the variable)
c_Guide.GetWIndowRect(&r);
****
> A.MoveWindow(r.left,r.top,w,h,TRUE/*repaint*/);
****
The problem here is that you are using the wrong coordinates. If you want to position a
window, you must give its coordinates in parent client coordinates. Since F, the class
you are in, is the parent of the window, you must express the desired position of A in
terms of the F client system. So you have to do
ScreenToClient(&r);
This converts the screen coordinates of GetWindowRect to the client coordinates of F.
Since you do not want to change the size of the control A, you do NOT need either the
width or the height at all, so getting them was a meaningless activity. What you want to
write now is:
A->SetWindowPos(NULL, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER |
SWP_SHOWWINDOW);
This presumes your modeless dialog is done as a popup, by the way, and you have said
nothing about how this window is managed. It would probably make more sense to create the
dialog as a child window. But since instead of asking how to solve a general problem,
say, of grouping controls in a moveable window, and concentrated on details of how to fix
a fundamentally incorrect approach to the problem, it is hard to determine what the
correct answer should be, since we have no hint of what is really going on here.
****
> A.ShowWindow(SW_SHOW);
>
>This code repositions the modeless dialog A, but not at the correct
>spot.
****
Nor surprising, because you gave it the wrong coordinates.
****
>
>The documentation for MoveWindow says that the coordinates are client
>wrt the parent, but screen if A is a "top-level window". Although A
>was created with F as a parent, Spy++ and GetParent both indicate that
>it has no parent.
****
Actually, it should probably be a child window. And MoveWindow should be used rarely, if
at all; SetWindowPos is almost always easier to use. For one thing, you don't have to
waste time getting useless parameters like width and height when they are not changing, or
position, if it is not changing. In over 20 years of Windows programming, I cannot
remember the last time I ever wrote "MoveWindow".
****
>
>I tried converting the guide coordinates from screen to client, in
>case MoveWindow was using client coords of F; this didn't work either.
****
I have no idea what "didn't work" means. For example, if you position the parent in the
top left corner of your screen, where does the child appear.
Note also that unless the dialog is a child (not a popup), when you move the parent
dialog, the modeless dialog window will stay where it was, unless you also implement
MoveWindow to move it. And if you resize the window to cover some of the controls, the
modeless dialog will still appear on top of the window; it will not be clipped by the
parent window.
Note that if you are creating a child window, it is not the same as a modeless dialog
(although there are tremendous similarities in how they are created). So what do you
intend here?
****
>
>How can I reposition the modeless dialog A at a known position with
>respect to modal dialog F, its creator?
****
Since you have said very little about the dialog, such as its styles, it is hard to guess.
But much of the code I see is deeply suspect.
joe
****
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
A is a type, a dialog derived from CDialog. In simplifying the code
for the question, I confounded the type A, and the instance, a. In the
"parent" dialog F, there is a declaration
A a;
and in the remainder of the code I showed, "A" should be "a".
> Because A is a modeless dialog, I would add handlers to override the default OK and Cancel
> events:
Not using either of these, although I may have to provide for user's
typing Esc.
> You have shown none of this, nor have you indicated that any of it has been done.
It's true, I didn't show all my code. It does work, though, except for
the positioning.
> Never declare more than one variable on a line. NEVER initialize more than one variable
> on a line. ALWAYS put a space after a comma when one appears in a separator context.
These are your opinions, and as I have said before, I don't agree.
> The problem here is that you are using the wrong coordinates. If you want to position a
> window, you must give its coordinates in parent client coordinates. Since F, the class
> you are in, is the parent of the window, you must express the desired position of A in
> terms of the F client system. So you have to do
>
> ScreenToClient(&r);
> This converts the screen coordinates of GetWindowRect to the client coordinates of F.
Finally, we get to the point. It is undoubtedly a question of
coordinates, but not just screen to client. As I said, I did try this,
and it positions the window incorrectly.
> This presumes your modeless dialog is done as a popup, by the way, and you have said
> nothing about how this window is managed. It would probably make more sense to create the
> dialog as a child window.
The modeless dialog has the following styles (as shown by Spy++):
WS_CAPTION, WS_VISIBLE, WS_CLIPSIBLINGS, WS_OVERLAPPED, DS_3DLOOK,
DS_FIXEDSYS, DS_SETFONT, WS_EX_ LEFT, WS_EX_LTRREADING,
WS_EX_RIGHTSCROLLBAR, WS_EX_TOOLWINDOW, WS_EX_WINDOWEDGE,
WS_EX_CONTROLPARENT, WS_EX_STATICEDGE. Spy++ shows its parent as
(none), although the dialog F was specified in the Create call.
> Actually, it should probably be a child window.
It was created using VS2005 dialog editor. I left the style choice as
"overlapped" (the default), but I can try "child".
The issue may be complicated by the fact that I'm testing this on the
primary monitor of a dual-monitor system.
> Note also that unless the dialog is a child (not a popup), when you move the parent
> dialog, the modeless dialog window will stay where it was, unless you also implement
> MoveWindow to move it. And if you resize the window to cover some of the controls, the
> modeless dialog will still appear on top of the window; it will not be clipped by the
> parent window.
These properties are OK, but I do want to get the coords correct, so I
will try the "child" approach.
> So what do you intend here?
In MS Word 97, the Find dialog's behavior is what I'm after. It
behaves as a window which remains on top of the main window, can be
moved anywhere.
> But much of the code I see is deeply suspect.
We are all deeply suspect.
I changed the style of the modeless dialog from Overlapped to Child,
re-instated the screen-to-client conversion, and now MoveWindow works
as expected. Problem solved.
>On Feb 1, 6:59�pm, Joseph M. Newcomer <newco...@flounder.com> wrote:
>>The variable A is declared somewhere, and has a type.
>
>A is a type, a dialog derived from CDialog. In simplifying the code
>for the question, I confounded the type A, and the instance, a. In the
>"parent" dialog F, there is a declaration
>
>A a;
>
>and in the remainder of the code I showed, "A" should be "a".
>
>> Because A is a modeless dialog, I would add handlers to override the default OK and Cancel
>> events:
>
>Not using either of these, although I may have to provide for user's
>typing Esc.
****
You don't have an option. You *MUST* provide them! And they must do NOTHING! If you
want 'ESC' to do something, you must handle it in the OnCancel, but you must NOT, under
any conditions, call CDialog::OnOK or CDialog::OnCancel as a consequence. These only work
correctly in modal dialogs. A modeless dialog handler MUST override these virtual methods
and no matter what it does, it must not call the superclass methods. This is because the
superclass methods call ::EndDialog, whose behavior is undefined for modeless dialogs.
****
>
>> You have shown none of this, nor have you indicated that any of it has been done.
>
>It's true, I didn't show all my code. It does work, though, except for
>the positioning.
****
But part of the answer depends on seeing the declaration. In general, you must not show
code that has "unbound variables", that is, variables for which we do not see the
declarations.
****
>
>> Never declare more than one variable on a line. �NEVER initialize more than one variable
>> on a line. �ALWAYS put a space after a comma when one appears in a separator context.
>
>These are your opinions, and as I have said before, I don't agree.
****
The code was nearly unreadable.
****
>
>> The problem here is that you are using the wrong coordinates. �If you want to position a
>> window, you must give its coordinates in parent client coordinates. �Since F, the class
>> you are in, is the parent of the window, you must express the desired position of A in
>> terms of the F client system. �So you have to do
>>
>> � � � � ScreenToClient(&r);
>> This converts the screen coordinates of GetWindowRect to the client coordinates of F.
>
>Finally, we get to the point. It is undoubtedly a question of
>coordinates, but not just screen to client. As I said, I did try this,
>and it positions the window incorrectly.
****
WHatever that means. It actually is important to know what it did. Was the box to the
left and above, or to the right and below, or what?
****
>
>> This presumes your modeless dialog is done as a popup, by the way, and you have said
>> nothing about how this window is managed. �It would probably make more sense to create the
>> dialog as a child window.
>
>The modeless dialog has the following styles (as shown by Spy++):
>WS_CAPTION, WS_VISIBLE, WS_CLIPSIBLINGS, WS_OVERLAPPED, DS_3DLOOK,
>DS_FIXEDSYS, DS_SETFONT, WS_EX_ LEFT, WS_EX_LTRREADING,
>WS_EX_RIGHTSCROLLBAR, WS_EX_TOOLWINDOW, WS_EX_WINDOWEDGE,
>WS_EX_CONTROLPARENT, WS_EX_STATICEDGE. Spy++ shows its parent as
>(none), although the dialog F was specified in the Create call.
****
There is some total weirdness dealing with parents of modeless dialogs, done within MFC. I
found that it attaches all dialogs to the main window as a parent, no matter what you
specify in the Create call.
But without knowing what you intend, it isn't easy to figure out what the correct answer
is. I wouldn't have done it with a modeless popup dialog.
****
>
>> Actually, it should probably be a child window.
>
>It was created using VS2005 dialog editor. I left the style choice as
>"overlapped" (the default), but I can try "child".
>
>The issue may be complicated by the fact that I'm testing this on the
>primary monitor of a dual-monitor system.
****
That can have problems in some cases, but I suspect the child property is the one you
want.
****
>
>> Note also that unless the dialog is a child (not a popup), when you move the parent
>> dialog, the modeless dialog window will stay where it was, unless you also implement
>> MoveWindow to move it. �And if you resize the window to cover some of the controls, the
>> modeless dialog will still appear on top of the window; it will not be clipped by the
>> parent window.
>
>These properties are OK, but I do want to get the coords correct, so I
>will try the "child" approach.�
>
>>�So what do you intend here?
>
>In MS Word 97, the Find dialog's behavior is what I'm after. It
>behaves as a window which remains on top of the main window, can be
>moved anywhere.
****
OK, so you are going to allow the parent window to move around. That does suggest that
you want a popup instead of a child. Now it gets tricky, because of how the parentage is
determined. You might try doing a AfxGetApp()->m_pMainWnd->ScreenToClient to get the
coordinates, because it is relative to whatever coordinate system Windows believes owns
the window.
Try an experiment: do a
CWnd * w = GetParent();
in the OnInitDialog and see what you get. The use Spy++ to find the m_hWnd that matches.
Go study the case in CWnd::CenterWindow. Pass in NULL. Study what it does to dtermine
the center coordinates, and what coordinate system it is using, then adapt your code to
that. I'm too sleepy to do it now (I'm still jet-lagged)
joe
****
>
>> But much of the code I see is deeply suspect.
>
>We are all deeply suspect.
That way the dialog doesn't ever really get lost.
Tom
"Woody" <ols...@sbcglobal.net> wrote in message
news:911d99c9-b52c-4e8f...@p13g2000pre.googlegroups.com...
So far, I have discovered that neither GetParent nor GetOwner in the
"parent" dialog returns a non-null value, although Spy says the parent
F has an owner. Apparently there is more than one definition of
"owner", because ::GetOwner returns the correct window handle.
It looks like the coordinates for move window are relative to the
client area of another dialog, P, which is the owner of F. Now I need
to solve the problem of how to get the window coords of the client
area of a window. The only thing I have found so far on this topic is
WM_NCCALCSIZE, which may or may not get what I want (I haven't
finished researching this yet).
1) The coordinate difficulty came about because I was doing the
calculation in OnInitDialog (of F). At that time, F has not been
positioned relative to P, and its reported window rect is actually the
client rect of P.
2) When I move the calculation to OnCtlColor of F, MoveWindow on A
uses screen coords. I get the screen coords of the guide, so I can
position A correctly. I am never using client coords.
3) To get the screen coords of the client area, use GetWindowInfo.
This handy function returns both the window and client rectangles in
screen coords.
I have a flag so it's only done once, so it's not an accident that it
works. At the time when the dialog is drawing its controls, it has
been moved to its final position by CDialog code.
You are right, though, that this is not an elegant soln. I looked for
a function that would be called once by the framework after the dialog
window had been positioned, but didn't find one; hence OnCtlColor.
Next time I'll try the message, although that's more work.
Of course you did not find a function that was called when you wanted it, because it is so
trivial to implement yourself that there is no need to create a function as part of the
API set to do it. PostMessage of a user-defined message handles this nicely.
joe