Re: recreate a window
On 11 Nov., 17:42, Joseph M. Newcomer <newco...@flounder.com> wrote:
See below...
On Tue, 11 Nov 2008 05:51:17 -0800 (PST), ".rhavin grobert" <cl...@yahoo.=
de> wrote:
On 10 Nov., 20:43, Joseph M. Newcomer <newco...@flounder.com> wrote:
See below...
On Mon, 10 Nov 2008 10:26:29 -0800 (PST), ".rhavin grobert" <cl...@yah=
oo.de> wrote:
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, i=
f
the styles given in resource not match the style required for toe
control (here: CBS_OWNERDRAWFIXED must be set). As CComboBox is un=
able
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. Essentiall=
y, I treat the failure to
have the wrong styles as an error. Not sure why you are botherin=
g to work around a bug
that shouldn't exist. If this happens, you ASSERT and then fix t=
he dialog at design time,
and omit ALL the code below.
CComboBox is not *supposed* to be able to modify this style after t=
he control 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.
***
My point is, a program which has one of these which is NOT defined as =
CBS_OWNERDRAWFIXED
is an erroneous program, so you fix it in the dialog template once, an=
d never again worry
about it.
****
if there's no way to let my code correct the error, i'd assert. but i
thought to use this flags myself, e.g. recreate a control with the
appropriate windowsflags needed for the control, and use the user-
defined flags for my own implementation (in this case, calling a user-
defined drawing routine instead of my own default drawing routine.)
****
You should not go to extensive effort to correct a defect that can be cor=
rected at design
time.
****
____________________________________________
//----------------------------------------------------------------=
-------
// 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 n=
o need for the above
line.
no it is not. 'this' is a CQControl that has no CWnd as baseclass! fo=
r
example, the
CQComboBox is a public CComboBox, public CQControl.
****
That's a different question than the one you asked. You did not spe=
cify that you are
using multiple inheritance.
i did'nt say i'm not using it;-) But you're right, assuming direct(?)
inheritance is the default.
****
On the whole, MFC is not multiple-inheritance friendly. You can get in=
to all kinds of
problems using multiple-inheritance in MFC, which is why most of us avoid=
it.
ATL and COM use it, but they use it *very carefully*. And they don't u=
se it for ordinary
controls, but special ATL and COM objects
****
But in that case, FromHandle is sufficient.
****
i just wanted to be shure.
****> 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 wouldn't be here. It
doesn't matter about what map it is in; you shouldn't care, either.
see above.
****
You have to provide *all* relevant information in order to get a corre=
ct answer
****
Note that I use this technique rather often to create a control in =
a space formerly
occupied by a CStatic, so I'm changing the entire control type. =
This code 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.
****
If you use multiple inheritance, a previously unstated case, then yes.=
But you can't ask
a question without giving all relevant information and expect to get a=
relevant answer
****
// 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 ra=
w 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 =
independent 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, bu=
t
apart from that, my way is completely ok.
****
Why do you need to define a new structure? You can just do
CRect rc;
::GetWindowRect(m_hWnd, &rc);
::ScreenToClient(parent, &rc);
where, now that I know you are using multiple inheritance, is still si=
mpler than the
complex code you wrote. And by setting the right and bottom to the =
Width() and Height(),
BEFORE transforming the top and left, you still get the wrong size.
****
=E4hm, no.. both rects are in pixel.
****
Consider the following: the rect is in the more-or-less middle of the scr=
een, and
somewhere inside of the window.
Let the screen coordinates be 600,400, 700, 500, that is, it is a 100x100=
control
physically at 600,400.
You set rc.right=rc.Width() and rc.bottom=rc.Height(). So we have
rc.right = 100;
rc.bottom = 100;
Let the (0,0) of the client area of the window that contains the control =
be at 400, 200 in
screen coordinates.
Now we transform with ScreenToClient the initial coordinates, just top an=
d left, to client
coordinates. In client coordinates, 600,400 translates to 200, 200 in =
client coordinates.
So you have a rectangle that starts at 200,200 and ends at 100,100, when =
your goal is to
have one that starts at 200,200 and goes to 300,300. Since right < lef=
t and bottom < top,
what you have is actually an illegal rectangle.
in the view of "rectangle", you're right. but i have now something
different: i have struct that has x,y,width,height as needed by
CreateWindowEx(). but to dont make thinks to complicated for other i
now use the following struct:
//-------------------------------------------------------------------------=
----
struct SQDim {
UINT nLeft;
UINT nTop;
UINT nWidth;
UINT nHeight;
inline SQDim(UINT left = 0, UINT top = 0, UINT width = 0, UINT heigh=
t
= 0) :
nLeft(left), nTop(top), nWidth(width), nHeight(height) {};
inline SQDim const& operator =(SQDim const& rDim)
{memcpy(this, &rDim, sizeof(this));};
inline SQDim const& operator =(RECT const& rRect)
{
nLeft = rRect.left;
nTop = rRect.top;
nWidth = rRect.right - nLeft;
nHeight = rRect.bottom - nTop;
};
inline operator RECT() const
{RECT rc = {nLeft, nTop, nWidth + nLeft, nHeight + nTop}; return
rc;};
};
Had you just done ScreenToClient on the whole rectangle, you would have g=
otten
200,200, 300, 300
which is what you would want. right and bottom are not distances, but =
absolute positions
within the coordinate system in question, which in this case is the clien=
t coordinate
system (after translation). But you translate left and top as coordina=
tes and right and
bottom as distances. This is erroneous.
****
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 On=
CreationRect and you
have not given the code for this, but there's nothing I know that n=
eeds to 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;
}
****
Using the 'On' prefix, which is used for handlers, is confusing. Ca=
lling it something
meaningful like ComputeDroppedRect might have made it less ambiguous a=
s to what was going
on.
****
// create a new window at current windows coordinates
HWND hNew = CreateWindowEx(dwStyleEx, QGetClassName(), "=
", dwStyle,
rc.left, rc.top, rc.right, rc.bottom, hPar=
ent, 0,
::AfxGetInstanceHandle(), NULL);
****
Why are you using the raw CreateWindowEx call? You can do this t=
rivially in MFC:
CWnd temp;
temp.CreateEx(dwStyleEx, QGetClassN=
ame(), _T(""), dwStyle, rc,
ent);
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 sett=
ing it to 0; this kills
off all your handlers in the parent window. For a brief moment y=
ou will have two controls
with the same ID, but this will be changed momentarily, and causes =
no harm.
oh, i thought it was hMenu.
****
Note that it is specified as being the hMenu for a top-level window an=
d the control ID for
a child window. From the documentation:
"For a child window, hMenu specifies the child-window identifer, an in=
teger value..."
It will have to be cast to an HMENU to satisfy the compiler.
joe
****
But what you didn't do was make sure it is in the right place in th=
e Z-order
temp.SetWindowPos(this, 0, 0, 0, 0, SWP_NOMOVE | SW=
P_NOSIZE);
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.
****
Since MFC does not normally support multiple inheritance, there can be=
some confusing side
effects here that may account for it. What is the type of the objec=
t displayed by the
debugger?
it displayes the expected type (CQComboBox)
****
Then you should not be seeing the error. But, as I indicated, MFC does=
not play well with
multiple inheritance, and virtual destructors in a multiple inheritance s=
ituation can have
interesting consequences. You're off into uncharted territory here.
****
Is there a reason you chose to use multiple inheritance over direct in=
heritance? You are
working in unsupported areas here.
of course;-) i have a baseclass (CQControl) from with CQButton,
CQTree, CQComboBox and so on derive. Each derived class uses multiple
inheritance to derive from CQControl and its MFC-class. By doind this,
i can do the following:
void SomeFunction(CQControl* pCtrl)
{
pCtrl->QResetContent();
// add an red blinking element with id ELEMENT_ID to the control
pCtrl->QElmSet(ELEMENT_ID, QDS_SHOWN|QDS_BLINK, DYE_RED);
// set text of element ELEMENT_ID with detail id DETAIL_ID to "S=
ome
Text"
// and add an image
pCtrl->QDtlSet(ELEMENT_ID, DETAIL_ID, _T("Some Text"),
ELEMENT_IMAGE);
// Select element ELEMENT_ID
pCtrl->QSelectionSet(ELEMENT_ID);
}
if pCtrl is a CQListView, you set element-row ELEMENT_ID, detail-
column DETAIL_ID to image ELEMENT_IMAGE, detail DETAIL_ID. if pCtrl is
a CQButton and you have more than one element, you get a multibutton.
if you dont have "columns" (Button, ListBox,..), the details appear
tab-separated. So you have the same syntax for all controls. Use in
programm: guess you have a function that shall fill a selection-
control with user-names and some additional infos (an icon per user or
a user-state-color and so on). this function just gets a CQControl*
and fills it. if it fills a Listview, a Treeview, a ListBox, a
ComboBox or even a Button just depents on the design of the GUI. More:
CQControl uses a special worker thread and does all the syncronisation
needed, so you could call the above SomeFunction() from ANY Thread;-)
****
Yes, it is a cool idea, but as I've indicated, you are out into seriously=
uncharted
territory here, and most of the ideas are not supported by the MFC framew=
ork, which
aggressively is single-inheritance.
You can have the same syntax for all controls without requiring multiple =
inheritance, but
I agree it is painful to duplicate code. As far as I know, no one has =
succeeded in doing
this.
;-))))))))))))) What i wrote is no "i plan to do this". IT
WORKS! ;-)))
I tried it myself some years ago for the same purposes, and after a
lot of
newsgroup discussions, the verdict at that time was "You are never going =
to win at this,
don't bother", and I gave it up. Nothing has changed in the intervenin=
g decade since I
tried this, so it probably doesn't work today, either.
It's not that you have a bad idea, but that you have an idea that is prob=
ably incompatible
with how MFC is designed to work.
joe
****
Joseph M. Newcomer [MVP]
email: newco...@flounder.com
Web:http://www.flounder.com
MVP Tips:http://www.flounder.com/mvp_tips.htm