Reputation: 347
There is a call back function in my main code which included by Switch case statements. After each case I defined a SetWindowText
function to print a text in a static Control which created on a dialog (or parent window),something like this:
::SetWindowText(GetDlgItem(IDC_STATIC)->m_hWnd, "loading");
I am going to set background of static control as the background of dialog. Everything goes well except the text of all the cases which place on each other and I receive a static control with overlapped texts, somthing like this:
I don't know why in each step it does not close the static window to avoid such kind of problems.
I added OnEraseBkgnd
, OnDestroy
, OnCtlColor
messages as follow:
BOOL CmainDlg::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
CDC dcMemory;
dcMemory.CreateCompatibleDC(pDC);
CBitmap* pOldbitmap = dcMemory.SelectObject(&CBmp);
CRect rcClient;
GetClientRect(&rcClient);
const CSize& sbitmap = bitmapSize;
pDC->BitBlt(0, 0, sbitmap.cx, sbitmap.cy, &dcMemory, 0, 0, SRCCOPY);
dcMemory.SelectObject(pOldbitmap);
return TRUE;
}
HBRUSH CmainDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if (pWnd->GetDlgCtrlID() == IDC_STATIC)
//Example of changing Text colour specific to a certain
//Static Text Contol in this case IDC_STATIC.
{
pWnd->GetExStyle() & (WS_EX_TRANSPARENT);
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(RGB(255, 255, 255));
}
if (pWnd->GetDlgCtrlID() == IDC_OPERATION)
{
pWnd->GetExStyle() & (WS_EX_TRANSPARENT);
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(RGB(255, 255, 0));
// Return handle to our CBrush object
}
return reinterpret_cast<HBRUSH>(GetStockObject(NULL_BRUSH));
}
void CmainDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
Background.DeleteObject(); // Delete Background bitmap
BrushHol.DeleteObject();
}
//subclass the static control, just to make sure the code is the only one handling WM_ERASEBKGND and WM_PAINT messages.
void CmainDlg::PreSubclassWindow()
{
CWnd::PreSubclassWindow();
const LONG_PTR exStyle = GetWindowLongPtr(m_hWnd, GWL_EXSTYLE);
SetWindowLongPtr(m_hWnd, GWL_EXSTYLE, exStyle | WS_EX_TRANSPARENT);
}
Update:
I commented OnEraseBkgnd
, OnDestroy
, OnCtlColor
functions. So I received the same overlapped texts and now with a bit more certainty I can say the problem comes from setWindowText
because after finishing each Case the text remains on static control window which I defined in each of switch case statments.
I tried to use the following commands but nothing happened:
EnableWindow( GetDlgItem(m_hWnd, IDC_STATIC), FALSE);
m_static.EnableWindow(FALSE);
or
::SetDlgItemText(m_hWnd, IDC_STATIC, "");
I'll appreciate any help.
Upvotes: 2
Views: 3057
Reputation: 31599
Drawing opaque:
Initialize m_Brush
with CreateSolidBrush
and use SetBkMode(OPAQUE)
instead of TRANSPARENT
Drawing transparent:
Follow Adrian McCarthy's answer and return (HBRUSH)GetStockObject(NULL_BRUSH)
for static controls instead of returning m_Brush
.
Make sure dialog doesn't have WS_CLIPCHILDREN
flag, otherwise you run in to the same overlap problem when you re-write the text in static control.
That should do it.
Another option, this code will blend other controls with background image (edit controls, radio buttons and check boxes) Dialog can have WS_CLIPCHILDREN
flag, but static control will need a positive id if it is to be redrawn (IDC_STATIC
is usually set to -1). Dialog items will need WS_EX_TRANSPARENT
flag as well. I didn't test this much.
Don't forget to add ON_WM_DESTROY
to message map.
class TDlg : public CDialogEx
{
public:
std::map<int, HBRUSH> BrushMap;
CBitmap Bitmap;
TDlg(int id, CWnd *wnd) : CDialogEx(id, wnd){};
void MakeBrush(CDC *pdc, CDC &memdc, int id);
BOOL OnEraseBkgnd(CDC* pDC);
void OnDestroy();
BOOL OnInitDialog();
HBRUSH OnCtlColor(CDC* pDC, CWnd* wnd, UINT nCtlColor);
DECLARE_MESSAGE_MAP()
};
BOOL TDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
Bitmap.LoadBitmap(IDB_BITMAP1);
return 1;
}
void TDlg::OnDestroy()
{
CDialogEx::OnDestroy();
Bitmap.DeleteObject();
for (std::map<int, HBRUSH>::iterator it = BrushMap.begin(); it != BrushMap.end(); ++it)
if (it->second)
DeleteObject(it->second);
}
void TDlg::MakeBrush(CDC *pdc, CDC &memdc, int id)
{
CWnd *item = GetDlgItem(id);
CRect rc;
item->GetClientRect(&rc);
item->MapWindowPoints(this, &rc);
CBitmap bmp;
bmp.CreateCompatibleBitmap(&memdc, rc.Width(), rc.Height());
memdc.SelectObject(bmp);
memdc.BitBlt(0, 0, rc.Width(), rc.Height(), pdc, rc.left, rc.top, SRCCOPY);
BrushMap[id] = CreatePatternBrush(bmp);
}
BOOL TDlg::OnEraseBkgnd(CDC* pDC)
{
BITMAP bm;
Bitmap.GetBitmap(&bm);
CDC memdc;
memdc.CreateCompatibleDC(pDC);
CBitmap* pOldbitmap = memdc.SelectObject(&Bitmap);
pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memdc, 0, 0, SRCCOPY);
//BrushMap should be intialized once
if (!BrushMap.size())
for (CWnd *p = GetWindow(GW_CHILD); p; p = p->GetNextWindow(GW_HWNDNEXT))
if (p->GetDlgCtrlID() > 0)
MakeBrush(pDC, memdc, p->GetDlgCtrlID());
memdc.SelectObject(pOldbitmap);
return TRUE;
}
HBRUSH TDlg::OnCtlColor(CDC* pDC, CWnd* wnd, UINT nCtlColor)
{
HBRUSH br = CDialogEx::OnCtlColor(pDC, wnd, nCtlColor);
pDC->SetTextColor(RGB(255, 0, 0));
pDC->SetBkMode(TRANSPARENT);
int id = wnd->GetDlgCtrlID();
if (id > 0 && BrushMap[id])
return BrushMap[id];
if (nCtlColor == CTLCOLOR_STATIC)
return (HBRUSH)GetStockObject(NULL_BRUSH);
return br;
}
Upvotes: 4
Reputation: 47954
The simplest solution is:
The only trick is getting the color of the dialog as a COLORREF. If you're using standard stuff, you can probably just call GetSysColor with one of the stock color constants.
If the dialog background is not a solid color (e.g., a gradient fill), you'll have to do something more sophisticated:
The WS_EX_TRANSPARENT style should cause the part of the dialog beneath the static control to be painted before the static control. That should "erase" the previous text, and then the static control will paint the new text.
Note that WS_EX_TRANSPARENT also makes the control transparent to hit testing (e.g., for mouse clicks). Since it's a static control, that shouldn't matter. But that's why this is not a general solution for other types of controls.
Upvotes: 3