|
There is not necessary to use derived class from static or edit control.
Set brush to ::GetStockObject (HOLLOW_BRUSH).
HBRUSH SomeDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hBrush = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
switch (nCtlColor) {
case CTLCOLOR_STATIC:
case CTLCOLOR_EDIT:
hBrush = (HBRUSH)::GetStockObject (HOLLOW_BRUSH);
pDC->SetBkMode (TRANSPARENT);
break;
....
return (hBrush);
}
|
|
|
|
|
That will work just fine as long as you're not going to change the text of the static control, and what's displayed behind the control is not changing either.
If you notice CTransparentStatic2::CtlColor is doing exactly what you are saying (I would argue that doing this in CStatic is much cleaner than catching WM_CTLCOLOR in the Dialog, you will only have to do it once in CStatic vers. many times if you have more than one dialog that will need to display transparent static controls).
The rest of the code in OnEraseBkgnd and OnSetText is to allow the user to call SetWindowText and change the Text of the static.
Using your approach try changing the static controls text by calling SetWindowText. You will see that old text is there along with the new text, unless you redraw force a redraw of the background window (that will cause flickering)
Ali
|
|
|
|
|
Thanks Ali for this summary!
I never understood this behaviour of WinAPI (background is not refreshed if you change text of an owner-draw static control), even WS_EX_TRANSPARENT style does not help. You seam to have two alternatives: take care of that yourself and paint the background in OnPaint() handler (bad if you're painting inside a property sheet with XP theme) or send an invalidate to the parent to force it to repaint the client's area.
/M
|
|
|
|
|
Hi,
Thanks for your Transparent Static.
But i have a problem with my application.
I build a CDialog dynamicaly with all the control not showed until all the control are created.
And when i show the dialog with all the control the background of the static is the image of my VC++ because the bmp background is calculate when my dialog is not showed.
Have you any idea how to get the right background or force to paint when the dialog is visible.
Thanks.
|
|
|
|
|
The problem her is that when the Static control is created it will receive a WM_ERASEBKGND message where it is getting the background it needs in order to draw itself..
There are three ways you can get around this problem.
1. Is to user CTransparentStatic instead of CTransparentStatic2 (I should have named these classes better). This class assumes that the background of the Parent is dynamically changing. So right after you show your controls, call the Static controls SetWindowText, and things will show up fine.
Example
CString Text;
m_TransStatic.GetWindowText(Text);
m_TransStatic.SetWindowText(Text);
2. You can add a method to the CTransparnetStatic2 class to clear it's cached background so that it is in an uninitialized state. Call that method right before you display your dialog box.
3. Instead of not showing the dialog, you can move it off screen, once everything is setup move it back to it's orginal place.
Ali
|
|
|
|
|
thanks for your help but the 3 ways don't work.
Arh !
When you say : "
2. You can add a method to the CTransparnetStatic2 class to clear it's cached background so that it is in an uninitialized state. Call that method right before you display your dialog box.
"
It is correct to do a m_bmp.deleteObject() ?
Any other idea ?
Thanks
|
|
|
|
|
Yes m_Bmp.DeleteObject() will do the trick.
Ali
|
|
|
|
|
Arh ! it doesn't work ! any other idea ?
|
|
|
|
|
The dialog doesn't have to be "visible" for this to work. In fact, if it is visible it won't work because all controls will have been drawn and you won't get a clean blank background to take a picture of. So I'm inclined to believe that the issue is with "layering" or ZOrder of the bitmap or something...
Here's my guess... the bitmap itself should be a static control, so that it can be "layered" at the bottom of the ZOrder. If your other controls are receiving the OnEraseBkgrnd() message BEFORE the bitmap control has been initialized then you will get a system color background. Make sure your bitmap is contained in a static control, that it's at the bottom of the ZOrder, and that it is created before all other controls.
In business, if two people always agree, one of them is unnecessary.
|
|
|
|
|
I have the same problem.
We should do the background copy right after the show of parent window and before the show our control.
But where is it?
|
|
|
|
|
I have the same problem.
We should do the background copy right after the show of parent window and before the show our control.
But where is it?
Hawk
|
|
|
|
|
Hi !
Has anybody managed to realize a Transparent Radio Button (based on CButton or special class)?.
All solutions I found, tested etc. always do not seem to care about what is written in OnEraseBkgnd... and always display an annoying block underneath the control. Very nasty when trying to put the control upon a picture.
I would appreciate any help !
On the other hand: Very good work this TransparentStatic !!!!
Best regards, Norbert
|
|
|
|
|
|
thanks your good example first,
but I could not figure out why
bitmp static or mystatic/mystatic2 can show up?
since the bitmp static and mystatic/mystatic2 overlaped each other.
so i could not understand why in OnSetText() procedure, the parent can show the bitmap .
would you give some details on this?
thanks much.
nothing nothing nothing
|
|
|
|
|
If I understand correctly, you are asking how does the system know to draw the two static text control on top of the static bitmap control.
That has to do with the ZOrder of the controls. The controls with higher ZOrder will show up on top of controls with a lower ZOrder.
This can be set in the dialog editor by setting the tab order of the controls. And you can also set this programatically using SetWindowPos, the first parameter is used to change the ZOrder of a window.
Ali
|
|
|
|
|
AliRafiee wrote:
That has to do with the ZOrder of the controls. The controls with higher ZOrder will show up on top of controls with a lower ZOrder.
after a few try, I think so, but I have not gotten the inferior from the tries.
1)
I new a project with two statics, one Labled "aaaa",
another one labled "bbbbbbbbbbbbbbbbb",
and the "aaaa" is bigger than "bbbbbbbbbbbbbbbbbbbbb" in size.
2)
in the resource file,
i changed the occurence of the two static to change their Zorders.
also I have test the WS_EX_TRANSPARENT.
the test cases and the corresponding results are:
a)
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20,0,
LTEXT "aaaa",IDC_STATIC,31,15,123,67,0
result:only "aaaa" is visible.
i think this is normal because aaaa is larger than bbbbbbbbbbbb, and aaaa is on top of bbbbbbbbbbb.
b)
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20,0,
WS_EX_TRANSPARENT
LTEXT "aaaa",IDC_STATIC,31,15,123,67
result: both are visible;
why??? MSDN states if a window with WS_EX_TRANSPARENT set,windows below it at the position where the original window was initially placed are not obscured and show through.
c)
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20,0,
WS_EX_TRANSPARENT
LTEXT "aaaa",IDC_STATIC,31,15,123,67,0,WS_EX_TRANSPARENT
result: same as a) case, only "aaaa" is visible
why????
d)
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20
LTEXT "aaaa",IDC_STATIC,31,15,123,67,0,WS_EX_TRANSPARENT
result: same as a) case, only "aaaa" visible
why???
e)
LTEXT "aaaa",IDC_STATIC,31,15,123,67,0,WS_EX_TRANSPARENT
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20
result: only "aaaa" is visible
why????
f)
LTEXT "aaaa",IDC_STATIC,31,15,123,67
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20
result:both "aaaa" and "bbbbbbbbbbbbbbbbbbbb" is visible.
this case i see why, because bbb is smaller than aaaa, and the Zorder is bbbb above aaaa.
g)
LTEXT "aaaa",IDC_STATIC,31,15,123,67,0,WS_EX_TRANSPARENT
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20,0,WS_EX_TRANSPARENT
result: both visible.
h)
LTEXT "aaaa",IDC_STATIC,31,15,123,67
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20,0,WS_EX_TRANSPARENT
result: both visible
in e,f,g,h I will think both static should be visible because bbbbb is above "aaaa" no matter whether WS_EX_TRANSPARENT is set with or not. but case e) defeated me.
would you be kind to give me more details? thanks
|
|
|
|
|
Try this. And get rid of those WS_EX_TRANSPARENTS
LTEXT "aaaa",IDC_STATIC,31,15,123,67,0
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20,0,
Like I said in the last message. The control with the higher ZOrder will show up on top of the other controls.
In the above code "aaaa" has a lower zorder than "bbbbbbb" so bbbb will show up on top of aaaaaa
in your example
LTEXT "bbbbbbbbbbbbbbbbbbbbbbb",IDC_STATIC,42,41,98,20,0,
LTEXT "aaaa",IDC_STATIC,31,15,123,67,0
aaaa has a higher zorder
Keep in mind that if you want to change the text for the larger static control ("aaaaaaaa"), then you will need to reset the text for the smaller ("bbbbbbbbbbb") one also
Ali
|
|
|
|
|
Hi,
You mentioned a possible forthcoming Transparent ListBox. Just wondering if it exists?
Thanks,
-Vin
|
|
|
|
|
Hi Vin,
I have the Transparent List box, but I have been so busy at work that I haven't been able to finilize it (and clean up) so that I can post it. If you like I can email you what I have. It might be a good starting point.
AliR
|
|
|
|
|
I emailed you the code to the email you have me and it bounced back, I improvised a couple of time, but then all bounced back. If you don't get the code, then send me another email.
I should have the code posted here at codeproject by next week.
|
|
|
|
|
The problem with the static method though, is that when the window becomes visible, if there is an always on top window in front of it, then you copy part of that window instead and that becomes your background when you do subsequent erasures.
|
|
|
|
|
Thanks for point that out. I am assuming that you are talking about method 1.
Using method 2 should eliminate that problem for you.
And if method 2 is not what you want, then you can simple make your window top most for an instant while the window get's drawn for the first time and then restore the zorder back to not top most.
For example: (If you are using it in a dialog box)
BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//set the window to topmost
SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
//set a timer to be called immediately after the window is drawn
SetTimer(100,0,NULL);
return TRUE;
}
void CMyDlg::OnTimer(UINT nIDEvent)
{
if (nIDEvent == 100)
{
KillTimer(nIDEvent);
SetWindowPos(&wndNoTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
}
CDialog::OnTimer(nIDEvent);
}
It might seem a bit awkward, but there is always a price to pay to get the cool things in windows.
AliR
|
|
|
|
|
Your method will still not work if it is being obscured by a topmost window, because setting windows position to wndTopMost will only set is above all non-topmost windows. Any topmost windows that previously existed will still obscure your window.
Here's a better solution (this is how I've implemented it in my button class). I have two methods in OnEraseBkgnd() based on a BOOL flag -- default is to use CDC::GetPixel() to identify solid color backgrounds. To use the control over an image background they must call a button method SetImageBg(TRUE, IMAGE_RESOURCE_ID) , which sets the boolean erasure flag (BOOL bImageBg ) to true and stores the image resource ID in a member variable (UINT m_background ). From there this is how I've implemented the solution in OnEraseBkgnd() :
if(bImageBg && m_background != 0)
{
if (m_Bmp.GetSafeHandle() == NULL)
{
m_Bmp.LoadBitmap(m_background);
CRect Rect;
GetClientRect(Rect);
this->ScreenToClient(&Rect);
CPoint pt = Rect.TopLeft();
CDC MemDC;
MemDC.CreateCompatibleDC(pDC);
CBitmap *pOldBmp = MemDC.SelectObject(&m_Bmp);
pDC->BitBlt(pt.x,pt.y,Rect.Width(),Rect.Height(),&MemDC,0,0,SRCCOPY);
MemDC.SelectObject(pOldBmp);
m_Bmp.DeleteObject();
}
}
This method is a little more "memory efficient" because it doesn't store a bitmap in memory for each control instance, it only stores a resource identifier (UINT). The bitmap is loaded and painted and then immediately deleted. It's probably not an issue anyway... but feel free to modify this to your own liking. At least it's a method that works and will get you pointed in the right direction.
In business, if two people always agree, one of them is unnecessary.
-- modified at 2:13 Tuesday 7th March, 2006
|
|
|
|
|
Hi,
first thanks for your smart control.
I'm using VC6 and I have the following problem:
My CStatic controls are created by directly calling the CStatic::Create() method. So I guess the ON_WM_CTLCOLOR_REFLECT() message isn't initialized correctly, because the CtlColor() method is never called. If I create the control via the MFC framework (resource editor) everything works fine.
Do you have any idea how to fix this problem?
Thanks a lot.
Ralph
|
|
|
|
|
I wasn't able to recreate your problem.
I am emailing you an example of both controls begin created dynamically. If you don't get the email, feel free to contact me again.
Ali Rafiee
|
|
|
|
|