Re: recreate a window
On 10 Nov., 18:59, Joseph M. Newcomer <newco...@flounder.com> wrote:
See below...
On Mon, 10 Nov 2008 08:09:56 -0800 (PST), ".rhavin grobert" <cl...@yahoo.=
de> wrote:
a CComboBox and CQControl derived control shall recreate itself, if
the styles given in resource not match the style required for toe
control (here: CBS_OWNERDRAWFIXED must be set). As CComboBox is unable
to correctly modify this style with ModifyStyle(), the recreation is
called and works.
****
The error is that you did not do this at design time. Essentially, I t=
reat the failure to
have the wrong styles as an error. Not sure why you are bothering to w=
ork around a bug
that shouldn't exist. If this happens, you ASSERT and then fix the dia=
log at design time,
and omit ALL the code below.
CComboBox is not *supposed* to be able to modify this style after the con=
trol is created,
so it is not "unable to correctly modify this style" because it was never=
defined that
this is even possible.
****
thats why i recreate it.
____________________________________________
//----------------------------------------------------------------------=
-
// recreate the underlying hwnd to match required styles
bool CQControl::QRecreateWindow(DWORD dwStyle, DWORD dwStyleEx)
{
CWnd* pWnd = CWnd::FromHandlePermanent(m_hwnd);
****
This is unnecessary; 'this' is already the CWnd *. So there is no need=
for the above
line.
no it is not. 'this' is a CQControl that has no CWnd as baseclass! for
example, the
CQComboBox is a public CComboBox, public CQControl.
****> ASSERT(pWnd != NULL);
ASSERT(pWnd == CWnd::FromHandle(m_hwnd));
if (pWnd == NULL)
return false;
****
The above statements are meaningless. You already have 'this' or you w=
ouldn't be here. It
doesn't matter about what map it is in; you shouldn't care, either.
see above.
Note that I use this technique rather often to create a control in a spac=
e formerly
occupied by a CStatic, so I'm changing the entire control type. This c=
ode is FAR too
complicated for such a simple task.
****
a static in Dialog-Editor would not look like a combobox.
CRect rc;
HWND hParent = GetParent(m_hwnd); =
// [1]
****
CWnd * parent = GetParent();
****
wrong. see above.
// get position and size of current window
GetWindowRect(m_hwnd, &rc); =
// [2]
****
I'm surprised this even compiles. There is no need to use the raw HWND=
.. You could just
have written
GetWindowRect(&rc);
and get everything you need.
see above;-)
// following fn's need width and size, we recycle rc
rc.right = rc.Width(); =
=
// [3]
rc.bottom = rc.Height(); =
// [4]
***
This code is incorrect. You must not set the right and bottom in this =
fashion, because
you are working with the window rect, and the width and height are indepe=
ndent of the
coordinate system. Lose the two assignments above.
// translate into parents coordinates
ScreenToClient(hParent, &rc.TopLeft()); =
// [5]
****
Why are you not doing something as simple as
CRect rc;
GetWindowRect(&rc);
GetParent()->ScreenToClient(&rc);
this is all you need. You have a complex and convoluted solution to a =
simple problem.
Just translating the top/left coordinate makes no sense, because it will =
produce a window
that has the wrong size.
no. everything works pretty well. i you insist, one could of course
define a struct RECT_ that has let, top, width and height members, but
apart from that, my way is completely ok.
You have five overly complicated lines doing what two trivial lines will =
accomplish.
****
// let derived class modify rc
OnCreationRect(rc);
****
I have no idea what this does because there is no handler called OnCreati=
onRect and you
have not given the code for this, but there's nothing I know that needs t=
o be done to this
rectangle once you have it.
****
in this case, the derived class uses this virtual as following:
void CQComboBox::OnCreationRect(RECT& rc)
{
RECT rcDropped;
GetDroppedControlRect(&rcDropped);
rc.bottom = rcDropped.bottom - rcDropped.top;
}
// create a new window at current windows coordinates
HWND hNew = CreateWindowEx(dwStyleEx, QGetClassName(), "", dwS=
tyle,
rc.left, rc.top, rc.right, rc.bottom, hParent, 0=
,
::AfxGetInstanceHandle(), NULL);
****
Why are you using the raw CreateWindowEx call? You can do this trivial=
ly in MFC:
CWnd temp;
temp.CreateEx(dwStyleEx, QGetClassName(),=
_T(""), dwStyle, rc,
GetDlgCtrlId(), parent);
Note how simple this is. For that matter, does CQControl have a Create=
method that would
be better?
I have no idea why you have chosen to change the control ID by setting it=
to 0; this kills
off all your handlers in the parent window. For a brief moment you wil=
l have two controls
with the same ID, but this will be changed momentarily, and causes no har=
m.
oh, i thought it was hMenu.
But what you didn't do was make sure it is in the right place in the Z-or=
der
temp.SetWindowPos(this, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSI=
ZE);
DestroyWindow();
Attach(temp.Detach());
All this use of raw API and HWNDs is unneccessay.
*****
// destroy old window and attach new one
DestroyWindow(pWnd->Detach());
pWnd->Attach(hNew);
m_hwnd = hNew;
****
Get rid of all the above lines.
The convoluted nature of what you are doing is probably what leads to the=
assertion
failure. I wouldn't even try to debug this code, I would rewrite it as=
indicated. Then,
and only then, if there is still a bug, would I worry about it.
****
return true;
}
____________________________________________
however, when the dialog is closed, the line 991 (marked "/******/"
in Wincore.cpp asserts:
____________________________________________
BOOL CWnd::DestroyWindow()
{
if (m_hWnd == NULL)
return FALSE;
CHandleMap* pMap = afxMapHWND();
ASSERT(pMap != NULL);
CWnd* pWnd = (CWnd*)pMap->LookupPermanent(m_hWnd);
#ifdef _DEBUG
HWND hWndOrig = m_hWnd;
#endif
#ifdef _AFX_NO_OCC_SUPPORT
BOOL bResult = ::DestroyWindow(m_hWnd);
#else //_AFX_NO_OCC_SUPPORT
BOOL bResult;
if (m_pCtrlSite == NULL)
bResult = ::DestroyWindow(m_hWnd);
else
bResult = m_pCtrlSite->DestroyControl();
#endif //_AFX_NO_OCC_SUPPORT
// Note that 'this' may have been deleted at this point,
// (but only if pWnd != NULL)
if (pWnd != NULL)
{
// Should have been detached by OnNcDestroy
#ifdef _DEBUG
ASSERT(pMap->LookupPermanent(hWndOrig) == NU=
LL); /******/
#endif
}
else
{
#ifdef _DEBUG
ASSERT(m_hWnd == hWndOrig);
#endif
// Detach after DestroyWindow called just in cas=
e
Detach();
}
return bResult;
}
____________________________________________
As i definitively Detached() the hwnd, i'd apprechiate any
enlightenment...
~.rhavin;)
Joseph M. Newcomer [MVP]
email: newco...@flounder.com
Web:http://www.flounder.com
MVP Tips:http://www.flounder.com/mvp_tips.htm