Фон 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) к этим элементам управления.

Другие вопросы по тегам