如何使 CMFCToolBarComboBoxButton 能够在垂直模式下工作?
How to make CMFCToolBarComboBoxButton able to works in vertical mode?
MFC Feature Pack 工具栏组合按钮 (class CMFCToolBarComboBoxButton
) 在水平工具栏模式下工作完美。但在垂直布局模式下,它是没有组合框功能的简单按钮。
如何使CMFCToolBarComboBoxButton
能够在垂直模式下工作?
这是我的解决方案。我在垂直模式下覆盖了按钮的行为。现在按钮在垂直模式下按下时显示组合框下拉 window。
当您将组合框按钮添加到工具栏时,您应该在 ReplaceButton()
方法中使用 class CVerticalableToolBarComboBoxButton 而不是 CMFCToolBarComboBoxButton。
示例:在下图中,您可以看到按钮在水平和垂直模式下的行为。
水平模式
垂直模式
Class代码:
class CVerticalableToolBarComboBoxButton
: public CMFCToolBarComboBoxButton
{
DECLARE_SERIAL(CVerticalableToolBarComboBoxButton)
public:
typedef CMFCToolBarComboBoxButton TBase;
protected:
bool m_bDoVerticalMode;
public:
CVerticalableToolBarComboBoxButton(bool bDoVerticalMode = true);
CVerticalableToolBarComboBoxButton(UINT uiID, int iImage, DWORD dwStyle = CBS_DROPDOWNLIST, int iWidth = 0, bool bDoVerticalMode = true);
virtual ~CVerticalableToolBarComboBoxButton();
virtual void Serialize(CArchive& ar);
virtual BOOL OnClick(CWnd* pWnd, BOOL bDelay = TRUE);
virtual void OnChangeParentWnd(CWnd* pWndParent);
virtual void OnMove();
virtual void OnSize(int iSize);
protected:
void AdjustVerticalRect();
};
/////////////////////////////////////////////////////////////////////////////
// CVerticalableToolBarComboBoxButton
IMPLEMENT_SERIAL(CVerticalableToolBarComboBoxButton, CVerticalableToolBarComboBoxButton::TBase, VERSIONABLE_SCHEMA | 1)
CVerticalableToolBarComboBoxButton::CVerticalableToolBarComboBoxButton(bool bDoVerticalMode /*= true*/)
: m_bDoVerticalMode(bDoVerticalMode)
{}
CVerticalableToolBarComboBoxButton::CVerticalableToolBarComboBoxButton(UINT uiID, int iImage, DWORD dwStyle /*= CBS_DROPDOWNLIST*/, int iWidth /*= 0*/, bool bDoVerticalMode /*= true*/)
: TBase(uiID, iImage, dwStyle, iWidth)
, m_bDoVerticalMode(bDoVerticalMode)
{}
CVerticalableToolBarComboBoxButton::~CVerticalableToolBarComboBoxButton()
{}
void CVerticalableToolBarComboBoxButton::Serialize(CArchive& ar)
{
TBase::Serialize(ar);
if (ar.IsLoading()) {
ar >> m_bDoVerticalMode;
}
else {
ar << m_bDoVerticalMode;
}
}
BOOL CVerticalableToolBarComboBoxButton::OnClick(CWnd* pWnd, BOOL bDelay /*= TRUE*/)
{
BOOL bRes = FALSE;
bool bDefault = m_bHorz || !m_bDoVerticalMode;
if (!bDefault) {
if (IsFlatMode()) {
if (m_pWndEdit == NULL) {
m_pWndCombo->SetFocus();
}
else {
m_pWndEdit->SetFocus();
}
m_pWndCombo->ShowDropDown();
if (pWnd != NULL) {
pWnd->InvalidateRect(m_rectCombo);
}
bRes = TRUE;
}
}
if (bDefault) {
bRes = TBase::OnClick(pWnd, bDelay);
}
return bRes;
}
void CVerticalableToolBarComboBoxButton::OnChangeParentWnd(CWnd* pWndParent)
{
TBase::OnChangeParentWnd(pWndParent);
if (!m_bHorz & m_bDoVerticalMode) {
AdjustVerticalRect();
}
}
void CVerticalableToolBarComboBoxButton::OnMove()
{
TBase::OnMove();
if (!m_bHorz & m_bDoVerticalMode) {
AdjustVerticalRect();
}
}
void CVerticalableToolBarComboBoxButton::OnSize(int iSize)
{
TBase::OnSize(iSize);
if (!m_bHorz & m_bDoVerticalMode) {
AdjustVerticalRect();
}
}
void CVerticalableToolBarComboBoxButton::AdjustVerticalRect()
{
ASSERT(m_bDoVerticalMode);
ASSERT(!m_bHorz);
if (m_pWndCombo->GetSafeHwnd() == NULL || m_rect.IsRectEmpty()) {
m_rectCombo.SetRectEmpty();
m_rectButton.SetRectEmpty();
return;
}
CMFCToolBar* pParentBar = nullptr;
{
CWnd* pNextBar = m_pWndCombo->GetParent();
while (pParentBar == nullptr && pNextBar != nullptr) {
pParentBar = DYNAMIC_DOWNCAST(CMFCToolBar, pNextBar);
pNextBar = pNextBar->GetParent();
}
}
if (IsCenterVert() && (!m_bTextBelow || m_strText.IsEmpty()) && (pParentBar != nullptr))
{
const int nRowHeight = pParentBar->GetRowHeight();
const int yOffset = std::max<>(0, (nRowHeight - m_rect.Height()) / 2);
m_rect.OffsetRect(0, yOffset);
}
{
CRect rect;
m_pWndCombo->GetWindowRect(&rect);
const int nWidth = std::max<>(rect.Width(), m_iWidth);
rect.left = m_rect.left;
rect.top = m_rect.top;
rect.right = m_rect.left + nWidth;
rect.bottom = m_rect.top + m_nDropDownHeight;
if ((pParentBar != nullptr) && pParentBar->IsDocked()) {
const UINT nID = pParentBar->GetParentDockSite()->GetDockSiteID();
if (nID == AFX_IDW_DOCKBAR_RIGHT) {
rect.left = m_rect.right - nWidth;
rect.right = m_rect.right;
}
}
m_pWndCombo->SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER | SWP_NOACTIVATE);
m_pWndCombo->SetEditSel(-1, 0);
}
{
m_pWndCombo->GetWindowRect(&m_rectCombo);
m_pWndCombo->ScreenToClient(&m_rectCombo);
m_pWndCombo->MapWindowPoints(m_pWndCombo->GetParent(), &m_rectCombo);
}
if (m_bFlat) {
m_rectButton = m_rectCombo;
}
else {
m_rectButton.SetRectEmpty();
}
}
// CVerticalableToolBarComboBoxButton
/////////////////////////////////////////////////////////////////////////////
MFC Feature Pack 工具栏组合按钮 (class CMFCToolBarComboBoxButton
) 在水平工具栏模式下工作完美。但在垂直布局模式下,它是没有组合框功能的简单按钮。
如何使CMFCToolBarComboBoxButton
能够在垂直模式下工作?
这是我的解决方案。我在垂直模式下覆盖了按钮的行为。现在按钮在垂直模式下按下时显示组合框下拉 window。
当您将组合框按钮添加到工具栏时,您应该在 ReplaceButton()
方法中使用 class CVerticalableToolBarComboBoxButton 而不是 CMFCToolBarComboBoxButton。
示例:在下图中,您可以看到按钮在水平和垂直模式下的行为。
水平模式
垂直模式
Class代码:
class CVerticalableToolBarComboBoxButton
: public CMFCToolBarComboBoxButton
{
DECLARE_SERIAL(CVerticalableToolBarComboBoxButton)
public:
typedef CMFCToolBarComboBoxButton TBase;
protected:
bool m_bDoVerticalMode;
public:
CVerticalableToolBarComboBoxButton(bool bDoVerticalMode = true);
CVerticalableToolBarComboBoxButton(UINT uiID, int iImage, DWORD dwStyle = CBS_DROPDOWNLIST, int iWidth = 0, bool bDoVerticalMode = true);
virtual ~CVerticalableToolBarComboBoxButton();
virtual void Serialize(CArchive& ar);
virtual BOOL OnClick(CWnd* pWnd, BOOL bDelay = TRUE);
virtual void OnChangeParentWnd(CWnd* pWndParent);
virtual void OnMove();
virtual void OnSize(int iSize);
protected:
void AdjustVerticalRect();
};
/////////////////////////////////////////////////////////////////////////////
// CVerticalableToolBarComboBoxButton
IMPLEMENT_SERIAL(CVerticalableToolBarComboBoxButton, CVerticalableToolBarComboBoxButton::TBase, VERSIONABLE_SCHEMA | 1)
CVerticalableToolBarComboBoxButton::CVerticalableToolBarComboBoxButton(bool bDoVerticalMode /*= true*/)
: m_bDoVerticalMode(bDoVerticalMode)
{}
CVerticalableToolBarComboBoxButton::CVerticalableToolBarComboBoxButton(UINT uiID, int iImage, DWORD dwStyle /*= CBS_DROPDOWNLIST*/, int iWidth /*= 0*/, bool bDoVerticalMode /*= true*/)
: TBase(uiID, iImage, dwStyle, iWidth)
, m_bDoVerticalMode(bDoVerticalMode)
{}
CVerticalableToolBarComboBoxButton::~CVerticalableToolBarComboBoxButton()
{}
void CVerticalableToolBarComboBoxButton::Serialize(CArchive& ar)
{
TBase::Serialize(ar);
if (ar.IsLoading()) {
ar >> m_bDoVerticalMode;
}
else {
ar << m_bDoVerticalMode;
}
}
BOOL CVerticalableToolBarComboBoxButton::OnClick(CWnd* pWnd, BOOL bDelay /*= TRUE*/)
{
BOOL bRes = FALSE;
bool bDefault = m_bHorz || !m_bDoVerticalMode;
if (!bDefault) {
if (IsFlatMode()) {
if (m_pWndEdit == NULL) {
m_pWndCombo->SetFocus();
}
else {
m_pWndEdit->SetFocus();
}
m_pWndCombo->ShowDropDown();
if (pWnd != NULL) {
pWnd->InvalidateRect(m_rectCombo);
}
bRes = TRUE;
}
}
if (bDefault) {
bRes = TBase::OnClick(pWnd, bDelay);
}
return bRes;
}
void CVerticalableToolBarComboBoxButton::OnChangeParentWnd(CWnd* pWndParent)
{
TBase::OnChangeParentWnd(pWndParent);
if (!m_bHorz & m_bDoVerticalMode) {
AdjustVerticalRect();
}
}
void CVerticalableToolBarComboBoxButton::OnMove()
{
TBase::OnMove();
if (!m_bHorz & m_bDoVerticalMode) {
AdjustVerticalRect();
}
}
void CVerticalableToolBarComboBoxButton::OnSize(int iSize)
{
TBase::OnSize(iSize);
if (!m_bHorz & m_bDoVerticalMode) {
AdjustVerticalRect();
}
}
void CVerticalableToolBarComboBoxButton::AdjustVerticalRect()
{
ASSERT(m_bDoVerticalMode);
ASSERT(!m_bHorz);
if (m_pWndCombo->GetSafeHwnd() == NULL || m_rect.IsRectEmpty()) {
m_rectCombo.SetRectEmpty();
m_rectButton.SetRectEmpty();
return;
}
CMFCToolBar* pParentBar = nullptr;
{
CWnd* pNextBar = m_pWndCombo->GetParent();
while (pParentBar == nullptr && pNextBar != nullptr) {
pParentBar = DYNAMIC_DOWNCAST(CMFCToolBar, pNextBar);
pNextBar = pNextBar->GetParent();
}
}
if (IsCenterVert() && (!m_bTextBelow || m_strText.IsEmpty()) && (pParentBar != nullptr))
{
const int nRowHeight = pParentBar->GetRowHeight();
const int yOffset = std::max<>(0, (nRowHeight - m_rect.Height()) / 2);
m_rect.OffsetRect(0, yOffset);
}
{
CRect rect;
m_pWndCombo->GetWindowRect(&rect);
const int nWidth = std::max<>(rect.Width(), m_iWidth);
rect.left = m_rect.left;
rect.top = m_rect.top;
rect.right = m_rect.left + nWidth;
rect.bottom = m_rect.top + m_nDropDownHeight;
if ((pParentBar != nullptr) && pParentBar->IsDocked()) {
const UINT nID = pParentBar->GetParentDockSite()->GetDockSiteID();
if (nID == AFX_IDW_DOCKBAR_RIGHT) {
rect.left = m_rect.right - nWidth;
rect.right = m_rect.right;
}
}
m_pWndCombo->SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER | SWP_NOACTIVATE);
m_pWndCombo->SetEditSel(-1, 0);
}
{
m_pWndCombo->GetWindowRect(&m_rectCombo);
m_pWndCombo->ScreenToClient(&m_rectCombo);
m_pWndCombo->MapWindowPoints(m_pWndCombo->GetParent(), &m_rectCombo);
}
if (m_bFlat) {
m_rectButton = m_rectCombo;
}
else {
m_rectButton.SetRectEmpty();
}
}
// CVerticalableToolBarComboBoxButton
/////////////////////////////////////////////////////////////////////////////