I want to make a transparent dialog. I capture the OnCtlColor message in a CDialog derived class...this is the code:
HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if(bSetBkTransparent_)
{
pDC->SetBkMode(TRANSPARENT);
hbr = (HBRUSH)GetStockObject(NULL_BRUSH);
}
return hbr;
}
It works fine for all the controls but the group-box (CStatic). All the labels (CStatic) are been painted with a transparent text background but the text of the group box it is not transparent.
I already googled for this but I didn't find a solutions. Does anybody know how to make a real transparent group-box?
By the way, I am working in Windows XP. And I don't want to fully draw the control to avoid having to change the code if the application is migrated to another OS.
Thanks,
Javier
Note: I finally changed the dialog so that I don't need to make it transparent. Anyway, I add this information because maybe someone is still trying to do it. The groupbox isn't a CStatic but a CButton (I know this is not new). I changed the Windows XP theme to Windows classic and then the groupbox backgraund was transparent. The bad new is that in this case the frame line gets visible beneath the text...so if someone is following this approach I think maybe he/she would better follow the Adzm's advice.
You have two options.
You can not use Common Controls v6 (the XP-Styled controls), which will make your app lose the fanciness of newer windows versions. However IIRC the groupbox will respect the CTLCOLOR issue. If you are not using that anyway, and it is still not respecting your color, then you only have one option...
Which is to draw it yourself. I know you said you don't want to, but sometimes you have to. Thankfully a group box is a very simple control to draw. This page has an example for drawing a classic-style group box: http://www.codeguru.com/cpp/controls/controls/groupbox/article.php/c2273/ You can also draw it very simply using the UxTheme libraries that come with XP+.
If the application will be migrated to another OS, you will have plenty to deal with migrating over an MFC application in general. If that is your goal, then you should really look into developing with a cross-platform UI toolkit.
Simply set the WS_EX_TRANSPARENT extended window style for the group box.
I knows this is a 12 years old question, but it frustrates me that nobody answered it correctly so far.
All you have to do is handle WM_CTLCOLORSTATIC:
case WM_CTLCOLORSTATIC:
{
HDC hDC = (HDC)wParam;
SetTextColor(hDC, RGB(255, 255, 255));
SetBkMode(hDC, TRANSPARENT);
return (INT_PTR)GetStockObject(HOLLOW_BRUSH);
}
break;
Related
I have created a custom window using DWM. I painted the caption by using PaintCustomCaption() ,which is an example from MSDN. It worked properly until I added SetLayeredWindowAttributes().
Window before adding
SetLayeredWindowAttributes(hWnd,RGB(0,0,1),0,LWA_COLORKEY);
After adding
I tried changing RGB values but it was still black except RGB(0,0,0).
I wonder if BitBlt() works properly.
Edited:
The reason I added SetLayeredWindowAttributes is to solve this problem
Do you have other ways to paint the caption?
case WM_ACTIVATE: {
DwmExtendFrameIntoClientArea(hWnd,&m); // m={-1,-1,-1,-1};
break;
}
case WM_INITDIALOG: {
SetWindowPos(hWnd,NULL,0,0,500,500,SWP_NOMOVE|SWP_FRAMECHANGED);
SetWindowLongPtr(hWnd,GWL_STYLE,WS_VISIBLE|WS_OVERLAPPEDWINDOW);
SetWindowLongPtr(hWnd,GWL_EXSTYLE,WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd,RGB(0,0,1),0,LWA_COLORKEY);
RedrawWindow(hWnd,NULL,NULL,RDW_INVALIDATE|RDW_ERASE);
return true;
}
case WM_PAINT: {
hdc=BeginPaint(hWnd,&paintstruct);
PaintCustomCaption(hWnd,hdc)
EndPaint(hWnd,&paintstruct);
break;
}
If you keep the window border, you don't need to paint the caption yourself unless you want to add something to your caption.
That is, handle WM_NCCALCSIZE and WM_NCHITTEST normally.
First, use RGB(200,201,202) as the transparency key instead of RGB(0,0,1).
You may try other values but it is the best one so far I have tested.
Then, add this after HBITMAP hbmOld=(HBITMAP)SelectObject(hdcPaint,hbm); in PaintCustomCaption():
FillRect(hdcPaint,&rcClient,CreateSolidBrush(RGB(200,201,202)));
I am trying to implement a static control which refreshes(change text) in response to some event, which occurs once every second. Since I didn't want to paint the entire client area every second and so I decided to use a static control, now the problem is the parent window is skinned, meaning it has custom bitmap as its background, and the static control doesn't fit in, so am looking for ways to make the static control's background transparent.
This is what I have now:
hHandle = CreateWindowEx( WS_EX_TRANSPARENT, "STATIC", "", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 60, 212, 477, 20, hwnd, 0, hInstance, 0) ;
case WM_CTLCOLORSTATIC:
{
HDC hdC = (HDC)wParam;
SetTextColor( hdC, RGB(31,122,179) );
SetBkMode( hdC, TRANSPARENT );
return 0;//(HRESULT)GetStockObject(NULL_BRUSH);
}
break;
I tried returning NULL brush to paint the background, hoping it would make its background transparent but it didn't what more it forced the static control to not repaint properly, what I mean is that the text gets painted on top of the old text so its all messy.
Is subclassing is the only option ?
The only way I've found to do this reliably is to sub-class the static control and paint the background manually.
WS_EX_TRANSPARENT does not make a control truly transparent to underlying pixels (although it may appear like that) and WS_EX_COMPOSITED can not be used for child windows.
Instead, sub-class the static, and catch the WM_ERASEBKGND message. You can then paint the appropriate portion of the underlying bitmap.
The way to get a WC_STATIC control to show only text in the color you choose (over an image or other surface) is the return, as I understand this. This is what worked for me from this link.
case WM_CTLCOLORSTATIC:
SetTextColor((HDC)wParam, RGB(255, 0, 0));
SetBkMode((HDC)wParam, TRANSPARENT);
// the correct return needs HOLLOW_BRUSH
return (LRESULT)GetStockObject(HOLLOW_BRUSH);
break;
You don't mention the window styles on the static control, specifically the extended styles WS_EX_TRANSPARENT seems intended to solve the problem you describe with the repaint. Also as I understand it WS_EX_COMPOSITED might be useful in your context.
You also might consider whether the background window should have WS_CLIPCHILDREN set as that might affect the repaint.
I am creating a basic GUI with the Windows API and I have run into an issue. It starts with a main window that opens with a custom background color I set (RGB(230,230,230)). It then displays text in the upper left corner with the static control.
settingstext = CreateWindow("STATIC",
"SETTINGS",
SS_LEFT | WS_CHILD,
12,
20,
100,
20,
hwnd,
NULL,
proginstance,
NULL);
ShowWindow(settingstext, 1);
This works, but when the text is displayed I need a way to change the background of it to match the main window or else it just looks like it doesn't blend in.
My question is, how do I do this? I currently use the method below and it works, but I wanted to know, is there a way to permanently set the background color somehow, right after the CreateWindow function for the static control without changing system colors, and just have it apply to that one control and not anything that sends the WM_CTLCOLORSTATIC message. I have experimented around with using the GetDC function and SetBkColor function outside of the message loop but nothing works.
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkColor(hdcStatic, RGB(230,230,230));
return (INT_PTR)CreateSolidBrush(RGB(230,230,230));
}
I want to do this because...
I don't want to fill up my message loop with functions that need to be called every time the window repaints.
Have the changes apply to only this static control.
I would be very thankful for any help that could be provided, at least pointing me in the right direction, thanks.
For static text controls there's no permanent way to set the text color or their background. Even if you want to apply the changes to a single static control; you would still have to handle WM_CTLCOLORSTATIC notification message in parent dlgproc just when the control is about to be drawn.
This is due to the DefWindowProc overwriting your changes to the device context each time it handles WM_CTLCOLORSTATIC as stated in the MSDN:
By default, the DefWindowProc function selects the default system colors for the static control.
static HBRUSH hBrush = CreateSolidBrush(RGB(230,230,230));
case WM_CTLCOLORSTATIC:
{
if (settingstext == (HWND)lParam)
//OR if the handle is unavailable to you, get ctrl ID
DWORD CtrlID = GetDlgCtrlID((HWND)lParam); //Window Control ID
if (CtrlID == IDC_STATIC1) //If desired control
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkColor(hdcStatic, RGB(230,230,230));
return (INT_PTR)hBrush;
}
}
If you're looking to make the control's background transparent over a parent dialog you could use SetBkMode(hdcStatic, TRANSPARENT).
I think there is a permanent way to do it.
Just after you create the label,use GetDC() function to get the Device Context.
Then use:
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkColor(hdcStatic, RGB(230,230,230)); // Code Copied from the above answer by cpx.
And it should do .
Have you considered subclassing the static window and doing owner draw?
I have created a simple propertySheet(CPropertySheet) and a couple of CPropertyPage derived classes.
While running the application, the ProperySheet, Page and tabs are appeared in white color.
I was expecting them to be like normal widow dialog color.
Any clue to make the property sheet, pages background to be like other normal MFC dialogs appears?
I use Visual Studio 2008 MFC without .NET CLR.
What do you mean 'system color'? Grey (COLOR_BTNFACE) ? What OS are you on? If XP the property sheet should be in COLOR_BTNFACE , Vista/Win7 I don't know what the proper color is. If you don't do anything special, they will show in the system default colors.
This is a MFC bug. Use the spy++ monitor your app, you will find your app receives many WM_GETDLGCODE message, and seems enter a dead loop. Yeah, that is the problem.
Microsoft had post a PRB for the problem. please view:PRB: Child CPropertySheet Hangs If Focus Is Switched
In short, add WS_EX_CONTROLPARENT style to your PropertySheet.
BOOL CMySheet::OnInitDialog()
{
ModifyStyleEx (0, WS_EX_CONTROLPARENT);
return CPropertySheet::OnInitDialog();
}
Process the WM_CTLCOLORDLG message.
case WM_CTLCOLORDLG:
{
HDC hdc = (HDC)wParam;
COLORREF color = GetSysColor(COLOR_3DFACE);
SetBkColor(hdc, color);
static HBRUSH brush = CreateSolidBrush(color);
return (BOOL)brush;
}
I have a CEdit control that's used to display a diagnostics output.
Sometimes the data overflows the screen size, so naturally I set the Vertical Scroll property to true (MFC dialog editor).
But then, when I tried to scroll the text that was in the window before isn't cleared and the new text is written over it.
The result is a big mess of everything I have scrolled past.
I've looked for a draw background property or something similar that will erase everything in the window while scrolling (before redrawing the new data).
Any suggestions?
I think you might want to set Auto VScroll and Multiline to true, and Auto HScroll to false.
We were having a similar problem. We ended up having to invalid the region of the parent window to get it to update when we got WM_VSCROLL. I tried to do as user demorge says here:
SetBkMode(hdc, TRANSPARENT) doesn't work
But our code doesn't use handles, we actually use the class CWnd, so we ended up doing this in the WindowProc instead:
switch(message)
{
...
case WM_VSCROLL:
case WM_HSCROLL:
LRESULT answer;
PAINTSTRUCT ps;
CDC* pdc;
CWnd* MyParentHWnd;
// We want the scroll to work the same way it has always worked for our
// ancestor class. Let them handle the scrolling and save off their
// return.
answer = AncestorClass::WindowProc(message, wParam, lParam);
pdc = BeginPaint(&ps);
// DO NOT change the assignement operator in the conditional below to an
// equality operator. We are actually trying to get the parent window and
// and storing locally, and then verifying that we didn't get back null.
// This is a purposeful design decision.
if (MyParentHWnd = GetParent()){
RECT MyRect;
GetClientRect(&MyRect);
ClientToScreen(&MyRect);
MyParentHWnd->ScreenToClient(&MyRect);
MyParentHWnd->InvalidateRect(&MyRect);
}
EndPaint(&ps);
return answer;
break;
...
}
Of course, I had to genericize it a little bit. I just wanted you to know that yes, there are other people that are seeing your problem, and we found how to fix it.
I tested this with VS2005, which ships with MFC 8.0. I couldn't replicate your problem.
I added one CEdit and one CRichEditCtrl to a dialog based app. Changed properties Multiline, Auto VSCroll and Vertical Scroll to true. Used SetWindowText-method to put loooooong string of text to both of them. I started the app and text scrolled just fine.
What did you do differently?
Just to be sure. You didn't use the SetCaretPos-method, did you? There was some note about that in the MSDN page. Here's the Knowledge Base article.