Фон MFC CButton игнорируется Windows 7
Чтобы изменить внешний вид (цвет фона и цвет текста текста) флажка MFC и радиокнопки, я использовал следующую реализацию, которая прекрасно работала в Windows2000, наполовину в Windows XP, но не в Windows 7:
BEGIN_MESSAGE_MAP(mycheckbox, CButton)
...
ON_WM_CTLCOLOR_REFLECT()
...
END_MESSAGE_MAP()
HBRUSH mycheckbox::CtlColor(CDC* pDC, UINT nCtlColor)
{
pDC->SetBkColor( RGB( 255, 0, 0 ) );
pDC->SetTextColor( RGB( 0, 255, 0 ) );
return m_brush;
}
Это прекрасно работает, если используется тема Windows Classic. Однако при использовании другой темы:
- Симптомы в Windows XP:
SetBkColor
работает ноSetTextColor
игнорируется - Симптомы в Windows 7: оба
SetBkColor
а такжеSetTextColor
игнорируются
Я пытался OnEraseBkgnd, чтобы заполнить фон с пользовательским цветом (pDC->FillSolidRect
) но даже это не дало эффекта.
Я хочу избежать использования ownerdrawn OnPaint
поэтому отметки и отметки радио продолжают следовать теме, которая активна в Windows. Как написано ранее, этот код используется в W2000, Windows Xp, Vista и Windows 7... Я просто хочу изменить цвет фона и цвет текста.
4 ответа
Я написал CButton, который будет использовать ownerdraw, когда тематика активна в Windows (это не тот случай, когда используется Windows Classic), и будет делать это динамически. Этот пример кода не является полным, но он демонстрирует все необходимое для получения результатов.
Сложная часть заключается в том, что вам нужно представлять выделенные и нажатые состояния, см. Параметры для DrawCheckBox
, Я игнорирую их, поскольку они не будут полностью пропущены в моем заявлении.
IMPLEMENT_DYNAMIC(mycheckbox, CButton)
mycheckbox::mycheckbox()
: mv_bIsChecked( false )
{
m_brush.CreateSolidBrush( RGB( 0,0,255) );
}
mycheckbox::~mycheckbox()
{
}
BEGIN_MESSAGE_MAP(mycheckbox, CButton)
ON_WM_CTLCOLOR_REFLECT()
ON_WM_PAINT()
ON_CONTROL_REFLECT(BN_CLICKED, &mycheckbox::OnBnClicked)
END_MESSAGE_MAP()
HBRUSH mycheckbox::CtlColor(CDC* pDC, UINT nCtlColor)
{
pDC->SetBkColor( RGB( 255, 0, 0 ) ); // text background color
pDC->SetTextColor( RGB( 0, 255, 0 ) ); // text foreground color
return m_brush; // control background
}
void mycheckbox::DrawItem(LPDRAWITEMSTRUCT)
{
}
void mycheckbox::OnPaint()
{
if( ( GetStyle() & BS_OWNERDRAW ) == BS_OWNERDRAW )
{
CPaintDC dc( this );
RECT rect;
GetClientRect( & rect );
rect.right = rect.left + 20;
CMFCVisualManager::GetInstance()->DrawCheckBox(
& dc
, rect
, false // highlighted
, mv_bIsChecked ? 1 : 0 // state
, true // enabled
, false // pressed
);
// draw text next to the checkbox if you like
}
else
__super::OnPaint();
}
// when BS_OWNERDAW is active,
// GetCheck() is reporting a wrong value
// so we have to do a little bookkeeping ourselves
void mycheckbox::OnBnClicked()
{
mv_bIsChecked = ! mv_bIsChecked;
}
BOOL mycheckbox::PreCreateWindow( CREATESTRUCT & cs )
{
CString lv_szValue;
CSettingsStore lv_Registry( FALSE, TRUE );
lv_Registry.Open( _T("Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager") );
lv_Registry.Read( _T("ThemeActive"), lv_szValue );
lv_Registry.Close();
if( lv_szValue == _T("1") )
cs.style |= BS_OWNERDRAW;
return CButton::PreCreateWindow(cs);
}
Я даже пытался переключать темы во время выполнения, однако это дает нежелательный эффект при переключении с Windows 7
тема для Windows Classic
(флажок выглядит как обычная кнопка). Так что я не использую это, но, возможно, интересно поделиться:
void mycheckbox::OnNMThemeChanged( NMHDR * pNMHDR, LRESULT * pResult )
{
CString lv_szValue;
CSettingsStore lv_Registry( FALSE, TRUE );
lv_Registry.Open( _T("Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager") );
lv_Registry.Read( _T("ThemeActive"), lv_szValue );
lv_Registry.Close();
ModifyStyle( BS_OWNERDRAW, 0 ); // turn off
if( lv_szValue == _T("1") )
ModifyStyle( 0, BS_OWNERDRAW ); // turn on
// This feature requires Windows XP or greater.
// The symbol _WIN32_WINNT must be >= 0x0501.
// TODO: Add your control notification handler code here
*pResult = 0;
}
CButton не делает ничего больше, чем вызывает процедуру окна Windows по умолчанию для рисования кнопки. Вы можете переопределить код OnPaint, чтобы сделать свое дело, но я могу понять, почему вы хотели бы избежать этого - очень много работы, чтобы получить правильный взгляд при любых обстоятельствах.
MFC предоставляет другой класс CMFCButton, который имеет переопределяемый метод OnFillBackground
Посмотрите, работает ли это для вас.
Поверьте мне, лучшее решение здесь - иметь CStatic с текстом и CButton, содержащий только флажок. Начиная с Vista, изменение фона флажков является проблемой, если не сказать больше.
Согласно этой статье Microsoft:
Чтобы изменить цвет фона элемента управления кнопки в Windows 3.0 и более поздних версиях, необходимо создать кнопку рисования владельца.
Если вы хотите, чтобы определенные элементы управления выглядели по-другому, я думаю, что лучше подклассы.
Эта статья будет полезна для понимания подклассов.
Здесь, чтобы изменить фон и цвет текста кнопки, вам нужно получить новый класс из CButton
сказать MyButton
и переопределить его DrawItem
функция, чтобы добавить код для рисования этого конкретного элемента управления на вашем пути.
Примечание: вам нужно установить свойство draw владельца (BS_OWNERDRAW
) к этим элементам управления.