How to get the background colour of CTabCtrl? - c++

I have a CTabCtrl on my dialog, and it has several labels (CStatic) on them. The problem is, the tab control has a white background, and the labels have grey backgrounds. I know why - the parent of the labels is actually the dialog, not the tab control. However, I should be able to use CWnd::OnCtlColor to provide a custom background brush for the labels:
HBRUSH MyDialog::OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor)
{
HBRUSH hBrush = __super::OnCtlColor(pDC, pWnd, nCtlColor);
const int dialogId = pWnd->GetDlgCtrlID();
if (dialogId == IDC_MY_CONTROL)
{
pDC->SetBkMode(TRANSPARENT);
hBrush = m_nullBrush;
}
return hBrush;
}
Here I use m_nullBrush to provide a brush to paint the background of the labels with, the only trouble is, I don't know how to get the tab's background colour, and instead have got it hardcoded with m_nullBrush.CreateStockObject(WHITE_BRUSH);.
Even if I re-parent the labels onto the tab control, they still end up with a grey background (even though the tab control has a white background).
How do I retrieve the background colour of a CTabCtrl?

You can put your controls in a child dialog and you must enable theme for this child dialog using EnableThemeDialogTexture.
#include "Uxtheme.h"
...
BOOL CTabDemoDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
COneDlg* OneDlg= new COneDlg;
OneDlg->Create(IDD_ONE, this);
AddPage(OneDlg, L"One");
return TRUE;
}
void CTabDemoDlg::AddPage(CDialog *Dialog, const wchar_t* Title)
{
if (IsAppThemed())
EnableThemeDialogTexture(*Dialog, ETDT_ENABLETAB);
CRect Rect;
TabCtl.GetWindowRect(Rect);
Rect.top+= 20;
Rect.InflateRect(-4, -4);
ScreenToClient(Rect);
Dialog->MoveWindow(Rect);
TabCtl.InsertItem(0, Title);
}
IDD_ONE DIALOGEX 0, 0, 224, 111
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
EXSTYLE WS_EX_CONTROLPARENT
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "Check1",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,16,39,10
LTEXT "Static",IDC_STATIC,20,36,19,8
EDITTEXT IDC_EDIT1,20,48,40,14,ES_AUTOHSCROLL
PUSHBUTTON "Button1",IDC_BUTTON1,84,16,50,14
END

Related

How do I refresh MFC dialog before Sleep() call

I have an array of buttons holding bitmap images.
I'm trying to change the image of one of the buttons to a different image for one second, and then change it again - but during the sleep, the UI still displays the older image as if I hadn't changed it - this means I don't see bmp_explosion displayed at all.
void COOPFinalDlg::ShowExplosion(int position)
{
SetButtonImage(position, bmp_explosion);
Sleep(1000);
SetButtonImage(position, bmp_tile);
}
void COOPFinalDlg::SetButtonImage(int buttonId, int imageId)
{
CButton* button = buttons[buttonId - ButtonRangeStart];
CBitmap bmp;
bmp.LoadBitmap(imageId);
button->SetBitmap(bmp);
}
The buttons were initalized to a bitmap the following way:
CBitmap bmp;
bmp.LoadBitmap(bmp_tile);
CRect rect(....);
CButton* button = new CButton;
button->Create(NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | DT_CENTER | WS_BORDER, rect, this, idCounter++);
button->ModifyStyle(0, BS_BITMAP);
button->SetBitmap(bmp);
buttons.Add(button);

Ownerdraw ComboBox Text Align Vertically Center

I am using owner-draw ComboBox in my MFC dialog based application.
I can draw Combobox's ListBox items but I cant set the ComboBox text in the ComboBox's edit control with vertical center alignment, it always renders on the top left of the edit control.
I need the text to be rendered on vertical center in the edit control.
How to achieve it?
CombobOx style :- CBS_DROPDOWN | CBS_OWNERDRAWFIXED | CBS_SORT | CBS_HASSTRINGS | CBS_UPPERCASE | WS_VSCROLL | WS_TABSTOP
BOOL CTestComboDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
COMBOBOXINFO cbi = { sizeof cbi};
m_ctrlCombo.GetComboBoxInfo(&cbi);
CRect r;
CWnd* p = CWnd::FromHandle(cbi.hwndItem);
((CEdit*)p)->GetRect(&r);
r.DeflateRect(10,10);
((CEdit*)p)->SetRect(r);
m_ctrlCombo.AddString("GHKL");
m_ctrlCombo.AddString("FGHJKL");
m_ctrlCombo.AddString("ASDFGH");
m_ctrlCombo.AddString("QWERTY");
m_ctrlCombo.SetCurSel(0);
return TRUE; // return TRUE unless you set the focus to a control
}
void CMyComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
LPCTSTR lpszText = (LPCTSTR) lpDrawItemStruct->itemData;
ASSERT(lpszText != NULL);
if (lpDrawItemStruct->itemID != -1)
dc.DrawText(lpszText, strlen(lpszText),
&lpDrawItemStruct->rcItem,
DT_LEFT|DT_SINGLELINE|DT_VCENTER);
dc.Detach();
}
Thanks
The owner-drawn combo box control will be displayed taller than it is set in the dialog resource: default height of the combo box in the resource editor is 12 pixels, but in the running application it will be displayed 2 pixels taller.
So I used below code to adjust the height of the edit control of combobox and got the text vertically center aligned
TEXTMETRIC tm;
HDC hDC = ::GetDC(NULL);
CFont* pFont = GetFont();
HFONT hFontOld = (HFONT)SelectObject(hDC, pFont->GetSafeHandle());
GetTextMetrics(hDC, &tm);
SetItemHeight(-1,tm.tmHeight + tm.tmExternalLeading + 1);
SelectObject(hDC, hFontOld);
::ReleaseDC(NULL, hDC);

How do I create a button in c++ with my own custom image?

I've been looking for a way to make a picture a button in c++ for a few hours now.. I've found stuff on using bitmaps, what what i am currently using to display the image is GDI+, because i want to use jpg/png files.
This is how i created my Image with gdiplus:
void Example_DrawImage(HDC hdc) {
Graphics graphics(hdc);
image = Image::FromFile(L"Path:/To/Image");
myBitmap = dynamic_cast<Bitmap*>(image);
Pen pen(Color(0, 0, 0, 0), 2);
graphics.DrawImage(image, 10, 10);
}
I converted that to a bitmap with:
myBitmap = dynamic_cast<Bitmap*>(image);
Then, in WM_CREATE I created a button which it's standard style is a Windows XP Button:
button = CreateWindow(TEXT("button"), TEXT("Hello"),
WS_VISIBLE | WS_CHILD | BS_BITMAP,
10, 10, /* x & y*/ 80, 25, /*width & height*/
hwnd, (HMENU) 1, hInstance, NULL
);
button is globally defined as HWND button;
All I want is to have a button that is a jpg picture. I tried doing it manually by seeing if a mouse click was inside a certain area, but I could not find a way to find the position of the Image.

Disable button animation for a single application in Win32 C++

With this call
SystemParametersInfo(SPI_SETCLIENTAREAANIMATION, 0, (LPVOID)FALSE, 0);
I disable the animation of buttons in my Win32 C++ project (no MFC or anything else) that has Visual Styles Common Controls 6.0.0.0 enabled and correctly initialized by calling InitCommonControlsEx function. Is there an alternative method to do this? I am asking because I don't want to disable the animation for the whole system but ONLY for my application. The buttons I create are Custom Drawn (not Owner Drawn).
I create a button like this in the WM_CREATE message (hwndbutton is defined before as static so that I can share it between all WM messages):
hwndbutton = CreateWindowEx(0, L"BUTTON", L"example", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, x, y, width, height, hwnd, (HMENU)button_id, GetModuleHandle(NULL), NULL);
and I draw it
...
case WM_NOTIFY:
{
LPNMHDR item = (LPNMHDR)lParam;
if (item->idFrom == button_id && item->code == NM_CUSTOMDRAW)
{
LPNMCUSTOMDRAW item_draw = (LPNMCUSTOMDRAW)item;
if (item_draw->uItemState & CDIS_HOT)
{
SetDCBrushColor(item_draw->hdc, RGB(180, 180, 180));
SelectObject(item_draw->hdc, GetStockObject(DC_BRUSH));
}
else
{
SetDCBrushColor(item_draw->hdc, RGB(255, 255, 255));
SelectObject(item_draw->hdc, GetStockObject(DC_BRUSH));
}
SetDCPenColor(item_draw->hdc, RGB(0, 0, 0));
SelectObject(item_draw->hdc, GetStockObject(DC_PEN));
RoundRect(item_draw->hdc, item_draw->rc.left, item_draw->rc.top, item_draw->rc.right, item_draw->rc.bottom, 0, 0);
return CDRF_DODEFAULT; // Return would be CDRF_SKIPDEFAULT but I want to keep the text "example" drawn
}
break;
...
By "button animation", I mean for example the fading effect that takes place in the button color when you move the cursor over a button and then leave it: I would like it to be colorA when normale state or colorB when mouse is over and not colorA when normal and fade_until_you_reach_colorB when mouse is over.
Thanks
EDIT: I add two gifs
The first is what I want (and I obtain with a previous call to SystemParametersInfo) and the second is the animation I would like to avoid
What I want
What I DON'T want
Theme for individual windows and controls can be disabled as follows:
SetWindowTheme(hbutton, L" ", L" ");
Animation should already be disabled because you are using custom draw. This method will also disable mouse-hover effect.
Normally when you disable a button's theme it may look weird with old 3-D borders on newer systems. You can add BS_FLAT to button's style.

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);
}