I would like to have a CEdit control, background-painted half-length or in any other portion of its length.
I have implemented the following code
HBRUSH CMyView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);
if (nCtlColor == CTLCOLOR_EDIT)
{
if (pWnd->GetDlgCtrlID() == IDC_MY_NORMAL_PERCENT_BOX)
{
// Set the text color to red
pDC->SetTextColor(RGB(255, 0, 0));
CRect rc;
// Get the client area of the edit control
m_CTV_Normal_Percent_Box_Ctrl.GetClientRect(&rc);
m_CTV_Normal_Percent_Box_Ctrl.ScreenToClient(&rc);
// Apply the device context to the client area of the edit control
pDC->Rectangle(0, 0, rc.Width()/2, rc.Height());
// Set the background mode for text to transparent
// so background will show thru.
pDC->SetBkMode(TRANSPARENT);
// Return handle to our CBrush object
hbr = m_brush;
}
}
return hbr;
}
but this could not be achieved. Could anyone possibly assist?
This is what I would like to get
and this is what I get
Thanks in advance.
Related
I want to make edit control's background transparent and change text's color to white. I can do both of them with this function, the only problem is that when you type on edit control, text keeps overlapping, follow the link for an example. I believe the problem is NULL_BRUSH, which makes background transparent, because if I change only the text color it works fine, unfortunately I need both.
How can I do this?
HBRUSH CDlg::OnCtlColor(CDC* pDc, CWnd* pWnd, UINT nCtlColor){
HBRUSH hbr = NULL;
switch (nCtlColor) {
case CTLCOLOR_EDIT:
if (pWnd->GetDlgCtrlID() == editControl){
pDc->SetBkMode(TRANSPARENT);
pDc->SetBkColor(TRANSPARENT);
pDc->SetTextColor(RGB(255, 255, 255));
hbr = (HBRUSH)GetStockObject(NULL_BRUSH);
}
break;
default:
hbr = CDialogEx::OnCtlColor(pDc, pWnd, nCtlColor);
}
return hbr;
}
My goal is to replace a background for the common-control's edit control. My current code does this:
HBITMAP hBmp = ::LoadBitmap(hInstance, MAKEINTRESOURCE(BKGND_ID));
HBRUSH hBkgndBrush = ::CreatePatternBrush(hBmp);
::DeleteObject(hBmp);
HBRUSH CDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
if(pWnd->GetDlgCtrlID() == MY_CTRL_ID && hBkgndBrush)
{
hbr = hBkgndBrush;
//Do I need to select it?
//pDC->SelectObject(hbr); //This line?
pDC->SetBkMode(TRANSPARENT);
}
// TODO: Return a different brush if the default is not desired
return hbr;
}
The question is, do I need to select hbr before returning it? (See commented out line above.) I seem to see it done both ways in different examples online.
EDIT: Also forgot to mention, I override WM_ERASEBKGND as such:
HDC hDc = ::GetDC(hWnd);
if(hDc)
{
RECT rc = {0};
::GetClientRect(hWnd, &rc);
::FillRect(hDc, &rc, hBkgndBrush);
::ReleaseDC(hWnd, hDc);
}
EDIT2: I made a small sample MFC project to illustrate the issue. Basically, when I move the app quickly off the screen and then back, it creates this visual "glitch" but only if control doesn't have ES_MULTILINE style:
When background brush is created from bitmap using CreatePatternBrush, some "repeating artifacts" may occur during dialog resizing or moving.
To remove these artifacts, force the child controls to repaint in response to ON_WM_WINDOWPOSCHANGED message:
void CMyDialog::OnWindowPosChanged(WINDOWPOS *wndpos)
{
CDialog::OnWindowPosChanged(wndpos);
CWnd *wnd = GetWindow(GW_CHILD);
while (wnd)
{
wnd->Invalidate(TRUE);
wnd = wnd->GetWindow(GW_HWNDNEXT);
}
}
or
void CMyDialog::OnWindowPosChanged(WINDOWPOS *wndpos)
{
CDialog::OnWindowPosChanged(wndpos);
edit1.Invalidate(FALSE);
edit2.Invalidate(FALSE);
...
}
OnCtlColor override will be as follows:
HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* wnd, UINT nCtlColor)
{
if (nCtlColor == CTLCOLOR_DLG)
return CDialogEx::OnCtlColor(pDC, wnd, nCtlColor);
pDC->SetBkMode(TRANSPARENT);
return hBkgndBrush;
}
You can add other conditions based on wnd or nCtlColor to change the background of edit control only.
In my application I have CPaneDialog with controls (e.g. Text control). I try to set background color for this CPanelDialog. For this purpose, I overwrited OnEraseBkgnd
BOOL CBgPaneDialog::OnEraseBkgnd(CDC* pDC)
{
CBrush backBrush(RGB(255, 128, 128));
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect); // Erase the area needed
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);
pDC->SelectObject(pOldBrush);
return TRUE;
}
Unfortunately, controls on this CPaneDialog have other background.
http://fotoo.pl//out.php?t=964580_text.png
I overwrot next method: OnCtlColor to set caontrol's backgorund.
HBRUSH CBgPaneDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
CBrush br;
br.CreateSolidBrush(RGB(255,255,255));
HBRUSH hbr = (HBRUSH)br;
CWnd *pCheckBox = GetDlgItem(IDC_STATIC); // put ID of your checkbox here.
int a;
if (*pCheckBox == *pWnd)
{
br.DeleteObject();
br.CreateSolidBrush(a=pDC->SetBkColor(RGB(255, 128, 128)));
hbr = (HBRUSH)br;
}
else
hbr = CPaneDialog::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}
The control's background have changed, but not completely. Please see in the picture:
http://fotoo.pl//out.php?i=964579_textcontrol.jpg
How can I change background completely for the text control?
Don't return temporary brush. Your code is okay for OnEraseBkgnd() because it's using the brush, not returning it, but for OnCtlColor use this instead:
class CMyDialog ...
{
COLORREF BkColor;
CBrush BkBrush;
//...
};
CMyDialog::CMyDialog...
{
BkColor = RGB(0, 255, 255);
BkBrush.CreateSolidBrush(BkColor);
}
HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
//add conditions...
pDC->SetBkColor(BkColor);
return BkBrush;
}
By the way, you can add mfc tag to your question to get faster answer in future.
How to change the background color of a edit box if user modifies its content in MFC.
How to change it in ON_EN_CHANGE MSg of a Edit control.
basically your solution is
HBRUSH CEditDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
switch (nCtlColor) {
case CTLCOLOR_EDIT:
case CTLCOLOR_MSGBOX:
// Set color to green on black and return the background
brush.
pDC->SetTextColor(RGB(0, 255, 0));
if(ChangeColor == TRUE)
{
pDC->SetBkColor(RGB(0, 0, 0));
ChangeColor = FALSE;
}
return (HBRUSH)(m_pEditBkBrush->GetSafeHandle());
default:
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
}
Now you want textbox color change on text change then,
::OnEnchange()
{
ChangeColor = TRUE; //Its global flag maintain in any global position may be in your .H file.
}
The MFC combobox is really a wierd design.
I use "drop list" type combo box.
HBRUSH CValueInputDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hBrush = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
if (nCtlColor == CTLCOLOR_STATIC || nCtlColor == CTLCOLOR_EDIT)
{
pDC->SetTextColor(RGB(255, 255, 255));
pDC->SetBkMode(TRANSPARENT);
hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
}
return hBrush;
}
what I do is having all my CStatic and CEdit color WHITE.
but i discover that I also change the combobox's edit to white.
that is what I don't want.
that is what I don't want. and I can't stop it from
pWnd->GetDlgCtrlID() == IDC_COMBO
it is so unfriendly. this combo box.
The Edit box is a child of the combo box. Try this:
pWnd->GetParent()->GetDlgCtrlID() == IDC_COMBO