How to set textcolor of menu item in mfc - c++

I want to change text color of menu in mfc. I have searched a lot but didn't got a proper solution. Finally I was trying to use OnCtlColor which I generally use for setting the color of static text control. But I am confused here how to do the same for menu items because pWnd->GetDlgCtrlID() dont work on menu.My menu item id is ID_MENU_ITEM. My query is what should i write at "?" to get my job done. And if my approach is wrong please suggest me good alternative.
HBRUSH CMyClass::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr;
if ( ? == ID_MENU_ITEM)
{
pDC->SetTextColor(RGB(255, 0, 0));
hbr = (HBRUSH)m_whitebrush;
return hbr;
}
}

Related

How to draw an CComboBox on setFocus

HBRUSH CDialog23::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
int Element = pWnd->GetFocus()->GetDlgCtrlID();
if (pWnd->GetDlgCtrlID() == Element && nCtlColor != CTLCOLOR_STATIC)
{
pDC->SetBkMode(TRANSPARENT);
pDC->SetBkColor(RGB(255, 230, 153));
hbr = m_Gelb;
return hbr;
}
else
{
pDC->SetBkMode(TRANSPARENT);
pDC->SetBkColor(RGB(255, 255, 255));
hbr = m_Weiss;
return hbr;
}
}
With this code, my ComboBoxes are getting colored in yellow, when I set the focus to one of them. However, if the current focus is set to one of the ComboBoxes, all other ComboBoxes are getting colored yellow, when I hover over them using the cursor (without clicking them). Also, the List of the ComboBox doesn't get colored (they are formated as dropdown).
Any ideas?
This is because you are not checking combo box ID equals focused combo ID. The dropdown combo boxes never receive focus. It is complex control that contains child edit control and this control has ID=1001 (0x03E9). Hence you are getting focus on the window with 1001 ID and all windows by this ID also change the background.
Change logic and use windows handles instead of IDs.
As for the drop-down list is a popup window layered over the combo box window and you will have to change the background using a different approach. You have no control over drop list creation and the only way would be to dynamically subclass this window using a hook.

Mfc CComboBoxEx - How to change the background color

I have a class that is derived from CComboBoxEx and I'm trying to change the background color. I was thinking that it would work like a ComboBox (using the SetBkColor function), but it doesn't change the background color.
Here's what I have tried :
BEGIN_MESSAGE_MAP(CMyComboBoxEx, CComboBoxEx)
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
void CMyComboBoxEx::SetBkColor(COLORREF backgroundColor)
{
m_backgroundColor = backgroundColor;
m_brBkgnd.DeleteObject();
m_brBkgnd.CreateSolidBrush(backgroundColor);
}
HBRUSH CMyComboBoxEx::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH brush = __super::OnCtlColor(pDC, pWnd, nCtlColor);
pDC->SetBkColor(RGB(255,0,0));
return brush;
}
I've tried with OnEraseBkgnd() too and it didn't worked either.
Do I need to subclass a derived CComboBox class and set the background color in that class?
Thx.
The problem here is that WM_CTLCOLOR messages are sent to the parent window (dialog box, probably) of your combo control, not to the control itself; also, in the case of the drop-down 'list-box' part of the combo, this message is not sent (as the dialog doesn't need to draw it unless the control has been activated).
The way I have achieved what you want is by making the control owner-draw and then (manually) drawing each item in the list.
First, you need to add the CBS_OWNERDRAWFIXED style to your control in the .rc/.rc2 script; like this, for a typical combo:
COMBOBOX IDC_IGONG, 224, 68, 52,120,
CBS_DROPDOWNLIST | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED | WS_VSCROLL | WS_TABSTOP
Then, you need to add ON_WM_DRAWITEM() to the message map for your dialog class, and override its OnDrawItem() member. Note that the message is sent once for each item in the drop-down list, when the list is made visible by user-action:
void MyDialog::OnDrawItem(int nIDCtl, DRAWITEMSTRUCT *pDIS)
{
switch (pDIS->CtlType) { // You can switch on the ID if it's only one combo!
case ODT_COMBOBOX:
DrawDropDownBox(this, nIDCtl, pDIS);
break;
default:
CDialogEx::OnDrawItem(nIDCtl, pDIS);
break;
}
}
The DrawDropDownBox() does all the hard work:
void MyDialog::DrawDropDownBox(CWnd *box, int nID, DRAWITEMSTRUCT *pDIS)
{
CComboBox *pCBC = dynamic_cast<CMyComboBoxEx *>(box->GetDlgItem(nID));
if (pCBC == nullptr) return; // Skip if we can't get handle to the control
CDC *pDC = CDC::FromHandle(pDIS->hDC);
wchar_t buffer[4096]; // Or just char if you ain't using Unicode
if (pCBC->GetLBText(int(pDIS->itemID), buffer) == CB_ERR) return; // Maybe called during WM_DELETEITEM
int dcSave = pDC->SaveDC(); // Save DC state for later restoration
CPen pen(PS_SOLID, 0, ListColor); // ListColor is COLORREF for your desired b/g
if (pDIS->itemState & ODS_DISABLED) {
pDC->SelectStockObject(NULL_PEN);
pDC->SelectObject(BackBrush); // A CBrush for disabled: defined/created elsewhere
pDC->SetBkMode(TRANSPARENT);
}
else {
pDC->SelectObject(&pen);
pDC->SelectObject(ListBrush); // A CBrush that draws your desired b/g
pDC->SetBkMode(OPAQUE);
}
CRect rc(pDIS->rcItem); pDC->Rectangle(&rc); // This draws the b/g
if (pDIS->itemState & ODS_DISABLED) {
pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
}
else if (pDIS->itemState & ODS_SELECTED) { // Use Windows defaults if selected...
pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
pDC->SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
}
else {
pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
pDC->SetBkColor(ListColor); // Custom b/g color
}
unsigned format = DT_SINGLELINE | DT_VCENTER; // You desired text alignment
pDC->DrawText(CString(buffer), rc, format);
pDC->RestoreDC(dcSave); // Restore DC's saved state...
pDC->Detach(); // ...then 'release it'
return;
}
The code shown handles both disabled combos and selected items in the list; you could possibly skip some of these, if you want to simplify the operation.
Feel free to ask for further explanation and/or clarification.
If it's all about just changing Bk color of the control, then you have to handle WM_CTLCOLOR message in control's parent window:
HBRUSH CMyDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if (pWnd->GetDlgCtrlID() == IDC_MY_CONTROL)
{
pDC->SetBkColor(RGB(0, 0, 0)); //Black color
hbr = m_hbrBlack; //Black brush.
}
return hbr;
}
Otherwise, you have to draw your control totally yourself in your derived class, with CBS_OWNERDRAWFIXED or CBS_OWNERDRAWVARIABLE style, which is way more complicated, but ofc possible.
I'm surprised that all the answers you've got so far suggest either handling WM_CTLCOLOR in parent window or use one of OWNERDRAW styles.
Handling WM_CTLCOLOR in parent window means you'll need to duplicate that code in each parent window's class where you'll use such combobox. This is obviously a bad solution if you want to use combobox more than once.
Adding OWNERDRAW style may have impact on other existing controls that you'd like to subclass and you may need to handle additional problems. That's also far from a sinmple solution.
Fortunately, there's another way to solve it - use Message Reflection. And all you need to do is to add ON_WM_CTLCOLOR_REFLECT() entry to the message map and CtlColor handler.
In case of combobox control I'd do it like this:
MyComboBoxEx.h
class CMyComboBoxEx : public CComboBoxEx
{
public:
CMyComboBoxEx();
virtual ~CMyComboBoxEx();
protected:
CBrush m_BkBrush;
DECLARE_MESSAGE_MAP()
public:
afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
};
MyComboBoxEx.cpp
CMyComboBoxEx::CMyComboBoxEx()
{
m_BkBrush.CreateSolidBrush(RGB(0, 255, 0));
}
CMyComboBoxEx::~CMyComboBoxEx()
{
}
BEGIN_MESSAGE_MAP(CMyComboBoxEx, CComboBoxEx)
ON_WM_CTLCOLOR_REFLECT()
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()
HBRUSH CMyComboBoxEx::CtlColor(CDC* pDC, UINT nCtlColor)
{
pDC->SetTextColor(RGB(255, 0, 0));
pDC->SetBkColor(RGB(0, 255, 0));
return m_BkBrush;
}
HBRUSH CMyComboBoxEx::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
return CtlColor(pDC, nCtlColor);
}
Here's how such combobox looks:
If you want to have custom color for borders and glyph then you need to handle WM_PAINT yourself.

SendMessage in win32 project has different result

I have a win32 project that has 2 text windows(inputArea, outputArea) and 2 buttons(sendButton and ResetButton).
My problem is that when I press Reset I want to clear the text from both areas, and the inputArea gets cleared but the outputArea gets colored.
Here is the code I have tried:
case IDC_ResetButton:
{
SendMessage(hwndInputArea, WM_SETTEXT, NULL, NULL);
SendMessage(hwndOutputArea, WM_SETTEXT, NULL, NULL);
break;
}
my intial inputArea:
my initial outputArea:
And here is what happens to outputArea when I press Reset:
Also, I tried each line of code separately and they work, but when I put both of them I get this result of the outputArea and I can't find out why.
Thank you in advance.
I guess that is editcontrol.
There are three options of color for that.
・text color
・background color
・drawing brush
HBRUSH CXxxDlg::OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor ) {
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
pDC->SetTextColor(RGB(0,0,0));
pDC->SetBkColor(RGB(192,192,192)); // …(1)
HBRUSH hbrOrg = static_cast<HBRUSH>(GetStockObject(GRAY_BRUSH)); // …(2)
return hbrOrg;
}
(1)(2)… make the same color
try to get the handle of you edit control each time on your button case like this (Change IDC_EDIT1 and 2 to your edit control ID):
case IDC_ResetButton:
{
hwndInputArea = GetDlgItem(hwndDlg,IDC_EDIT1);
hwndOutputArea = GetDlgItem(hwndDlg,IDC_EDIT2);
SendMessage(hwndInputArea, WM_SETTEXT, 0, NULL);
SendMessage(hwndOutputArea, WM_SETTEXT, 0, NULL);
break;
}

Coloring the entire background of an MFC static label

This Answer is really great if you want to change the background color of a "conventional" text label. But what if you want to put a border around that text label and expand its size so that the text is swimming in a veritable sea of color? It only paints the text background in the required color, and leaves the rest of the expanded control with the standard button face. How can one make the color consistent across the entire control?
Note: The attractive feature (to me anyway) about the above answer is that it makes use of OnCtlColor(), which provides a pointer to the CWnd control concerned. So there is no need to create a subclass of CStatic to handle the color change. An answer that avoids creating such a subclass would be preferred.
I'm not very sure about OP's Note section. Still posting this code for his help.
HBRUSH CSampleDlg::OnCtlColor(CDC* pDC, CWnd *pWnd, UINT nCtlColor)
{
switch (nCtlColor)
{
case CTLCOLOR_STATIC:
{
CRect rcWindow(0, 0, 220, 40);
//::GetWindowRect(pWnd->GetSafeHwnd(), &rcWindow);
pDC->FillSolidRect(rcWindow, RGB(49, 49, 49));
pDC->SetTextColor(RGB(255, 255, 255));
return (HBRUSH)GetStockObject(NULL_BRUSH);
}
default:
{
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
}
}
You can make the static control invisible in the resource editor then paint it from CMyDialog.
void CMyDialog::OnPaint()
{
CDialog::OnPaint();
paintstatic(IDC_STATIC1);
}
void CMyDialog::paintstatic(int id)
{
CClientDC dc(this);
CRect rc;
CWnd *child = GetDlgItem(id);
child->GetWindowRect(&rc);
CPoint offset(0, 0);
ClientToScreen(&offset);
rc.OffsetRect(-offset);
dc.FillSolidRect(rc, RGB(0, 255, 128));
CFont *font = GetFont();
dc.SelectObject(font);
CString text;
child->GetWindowText(text);
dc.DrawText(text, rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}

Change Color of read only CEdit control Artifacts and Text Highlighting issue

I have an Edit control that is read only that has text in it. I would like to switch the default gray background to white but have been having limited luck. In my first go, I was executing the following code during initialization of the dialog:
CEdit *m_ctrlEditOne = (CEdit*) GetDlgItem(IDC_EDIT1);
CDC *m_ctrlEEditWee = m_ctrlEditOne->GetDC();
m_ctrlEEditWee->SetBkColor(RGB(255,0,0));
Invalidate(true);
Another solution I tried was:
HBRUSH CTestingDlg::OnCtlColor(CDC* pDC, CWnd *pWnd, UINT nCtlColor)
{
if (pWnd->GetStyle() & ES_READONLY)
//if(pDC->GetRuntimeClass == & ES_READONLY)
{
switch (nCtlColor)
{
case CTLCOLOR_STATIC:
pDC->SetBkColor(RGB(255,255,255));
return (HBRUSH)GetStockObject(NULL_BRUSH);
default:
//return NULL;
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
}
//return NULL;
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}
In the screenshot below, you can see that the text is inserted after the fact (this is what needs to happen) and appears highlighted in blue - I have no idea where to begin on how to make it just appear as normal, non-highlighted text. When clicking on it, it appears normally. In the bottom left corners of each edit control, one can see a square which should not be appearing there. Also, you can see some artifacts of what looks like to be a combo box dropdown selection appearing in the larger boxes.
I would appreciate any pointers on how to get rid of the artifacts and fix the highlighting issue with inserted text.
I do as shown below. It will change the background of the read only edit control IDC_EDIT1 to white. This is a copy-paste straight out of one of my projects.
m_whitebrush is a private member of CTestOnCtlClorDlg of type HBRUSH and must be initialized to NULL in the constructor of CTestOnCtlClorDlg.
HBRUSH CTestOnCtlClorDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
int id = pWnd->GetDlgCtrlID( ) ;
if (id == IDC_EDIT1)
{
pDC->SetTextColor(RGB(0, 0, 0));
pDC->SetBkColor(RGB(255,255,255));
if (!m_whitebrush)
m_whitebrush = CreateSolidBrush(RGB(255,255,255)) ;
hbr = m_whitebrush ;
}
return hbr;
}
void CTestOnCtlClorDlg::OnDestroy()
{
CDialog::OnDestroy();
if (m_whitebrush !=NULL)
{
DeleteObject(m_whitebrush) ;
m_whitebrush = NULL ;
}
}