winapi - MFC:CMFCDropDownToolBar 除第一个按钮外的所有按钮均为空白
问题描述
创建了CMFCDropDownToolBar
一个CMainFrame::OnCreate
:
// Loading toolbar with a single icon/entry.
if (!m_wndMyDropdownToolBar.Create(this,
WS_CHILD|CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_HIDE_INPLACE|CBRS_SIZE_DYNAMIC|
CBRS_GRIPPER | CBRS_BORDER_3D,
ID_ACTION_BUTTON) ||
!m_wndMyDropdownToolBar.LoadToolBar (IDR_TOOLBAR_DROPDOWNSELECT))
{
TRACE0("Failed to create build toolbar\n");
return FALSE; // fail to create
}
// build list - use existing icon
for (UINT i=0; i<2; i++) {
CString s;
s.Format(_T("%i: Whatever %i\n"), i, i);
m_wndMyDropdownToolBar.InsertButton(CMFCToolBarButton(ID_COMMAND_START+i, 0, s));
};
然后剩下的:
afx_msg LRESULT CMainFrame::OnToolbarReset(WPARAM idtoolbar, LPARAM)
{
if (idtoolbar==IDR_MAINFRAME) {
ASSERT(m_wndMyDropdownToolBar.GetSafeHwnd() != NULL);
//-----------------------------------
// Replace dropdown button:
//-----------------------------------
m_wndToolBar.ReplaceButton(ID_ACTION_BUTTON_DUMMY,
CMFCDropDownToolbarButton(_T("Text that doesn't show anywhere"), &m_wndMyDropdownToolBar));
}
return 0;
}
BOOL CMainFrame::GetToolbarButtonToolTipText(CMFCToolBarButton* pButton, CString& strTTText)
{
if (pButton->m_nID>=ID_COMMAND_START && pButton->m_nID<=ID_COMMAND_END) {
// use text
strTTText=pButton->m_strText;
return TRUE;
}
return FALSE;
}
就下拉显示按钮而言,一切正常,悬停显示工具提示,但是当您选择通过InsertButton()
调用手动添加的按钮之一时,主工具栏上的按钮为空白且没有工具提示。如果我然后返回并选择第一个按钮(已加载资源的一部分),它会显示正确的图标和工具提示。
我做错了什么?
谢谢!!
解决方案
问题是这CMFCDropDownToolbarButton::SetDefaultCommand(UINT uiCmd)
是有缺陷的。如果不是bUserButton
类型,那么它假定索引m_ImagesLocked
是按位置而不是按钮iIndex
。您不能使用bUserButton
和支持bLargeButtons
,因为用户按钮的大小必须相同。此外,位于主工具栏上的按钮采用第一项m_strText
(通常是空字符串,因为加载了工具栏),因此通过CMainFrame::GetToolbarButtonToolTipText()
上面的工具提示更新也不起作用(它应该拉入按钮文本但没有)。所以可能测试最好的办法是afxdropdowntoolbar.cpp
在项目中复制它,然后用一个新的类名修复它。一点点代码膨胀,如果只是SetDefaultCommand()
虚拟的,可以很容易地修复它。
另请注意,如果使用LoadBitmap
/ LoadBitmapEx
,则应设置bLocked
为 TRUE (以及使用时InsertButton()
)
让一切都按照它应该开始的方式工作,如果你需要这个,这里是核心更改:
呃,需要覆盖受保护的 CMFCToolBarImages::CopyTemp() 所以不必重做几乎所有的 MFC 工具栏支持,我添加了这个 hack!我没有添加任何数据成员,因此应该保持与 CMFCToolBar 的兼容性。
class CMyToolBarImages : public CMFCToolBarImages
{
public:
void MyCopyTemp(CMyToolBarImages *imagesDest) const
{
imagesDest->Clear();
imagesDest->m_bIsTemporary = TRUE;
imagesDest->m_sizeImage = m_sizeImage;
imagesDest->m_sizeImageDest = m_sizeImageDest;
imagesDest->m_hbmImageWell = m_hbmImageWell;
imagesDest->m_bUserImagesList = m_bUserImagesList;
imagesDest->m_iCount = m_iCount;
imagesDest->m_bReadOnly = TRUE;
imagesDest->m_nBitsPerPixel = m_nBitsPerPixel;
}
};
class CMyDropDownToolBar : public CMFCToolBar
{
.
.
.
virtual BOOL OnUserToolTip(CMFCToolBarButton* pButton, CString& strTTText) const;
// HACK protected CMFCToolBarImages!!
void CopyTempAll(CMyDropDownToolBar *desttoolbar) const
{
((const CMyToolBarImages*) &m_ImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_ImagesLocked);
((const CMyToolBarImages*) &m_ColdImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_ColdImagesLocked);
((const CMyToolBarImages*) &m_DisabledImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_DisabledImagesLocked);
((const CMyToolBarImages*) &m_LargeImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_LargeImagesLocked);
((const CMyToolBarImages*) &m_LargeColdImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_LargeColdImagesLocked);
((const CMyToolBarImages*) &m_LargeDisabledImagesLocked)->MyCopyTemp((CMyToolBarImages*) &desttoolbar->m_LargeDisabledImagesLocked);
}
};
让它为工具提示调用 CMainFrame:
BOOL CMyDropDownToolBar::OnUserToolTip(CMFCToolBarButton* pButton, CString& strTTText) const
{
ASSERT_VALID(pButton);
CFrameWnd* pTopFrame = AFXGetParentFrame(this);
if (pTopFrame == NULL)
{
return FALSE;
}
CMyDropDownFrame* pDropFrame = DYNAMIC_DOWNCAST(CMyDropDownFrame, pTopFrame);
if (pDropFrame != NULL)
{
pTopFrame = AFXGetParentFrame(pDropFrame);
if (pTopFrame == NULL)
{
return FALSE;
}
}
CMDIFrameWndEx* pMainFrame = DYNAMIC_DOWNCAST(CMDIFrameWndEx, pTopFrame);
if (pMainFrame != NULL)
{
return pMainFrame->GetToolbarButtonToolTipText(pButton, strTTText);
}
else // Maybe, SDI frame...
{
CFrameWndEx* pFrame = DYNAMIC_DOWNCAST(CFrameWndEx, pTopFrame);
if (pFrame != NULL)
{
return pFrame->GetToolbarButtonToolTipText(pButton, strTTText);
}
else // Maybe, MDIChild frame
{
CMDIChildWndEx* pMDIChild = DYNAMIC_DOWNCAST(CMDIChildWndEx, pTopFrame);
if (pMDIChild != NULL)
{
return pMDIChild->GetToolbarButtonToolTipText(pButton, strTTText);
}
else // Maybe, OLE frame...
{
COleIPFrameWndEx* pOleFrame = DYNAMIC_DOWNCAST(COleIPFrameWndEx, pFrame);
if (pOleFrame != NULL)
{
return pOleFrame->GetToolbarButtonToolTipText(pButton, strTTText);
}
}
}
}
return FALSE;
}
对于开始整个事情所需的实际第一个修复:
void CMyDropDownToolbarButton::SetDefaultCommand(UINT uiCmd)
{
.
.
.
if (pButton->m_nID == uiCmd)
{
m_bLocalUserButton = pButton->m_bUserButton;
if (m_bLocalUserButton)
{
m_iSelectedImage = pButton->GetImage();
}
else
{
// FIXED HERE:
m_iSelectedImage=pButton->GetImage();
if (m_iSelectedImage==-1) {
m_iSelectedImage=iImage;
}
}
// FIXED HERE:
m_strText=pButton->m_strText;
break;
}
.
.
.
}
要使工具提示看起来与粗体和正常一致,请使用 CMainFrame::GetMessageString:
class CMyDropDownFrame : public CMiniFrameWnd
{
.
.
.
// For customizing the default messages on the status bar and second line of tooltip
virtual void GetMessageString(UINT nID, CString& rMessage) const;
};
// For customizing the default messages on the status bar and second line of tooltip
void CMyDropDownFrame::GetMessageString(UINT nID, CString& rMessage) const
{
CFrameWnd* pTopFrame = AFXGetParentFrame(this);
if (pTopFrame == NULL)
{
return;
}
CMFCDropDownFrame* pDropFrame = DYNAMIC_DOWNCAST(CMFCDropDownFrame, pTopFrame);
if (pDropFrame != NULL)
{
pTopFrame = AFXGetParentFrame(pDropFrame);
if (pTopFrame == NULL)
{
return;
}
}
CMDIFrameWndEx* pMainFrame = DYNAMIC_DOWNCAST(CMDIFrameWndEx, pTopFrame);
if (pMainFrame != NULL)
{
pMainFrame->GetMessageString(nID, rMessage);
return;
}
else // Maybe, SDI frame...
{
CFrameWndEx* pFrame = DYNAMIC_DOWNCAST(CFrameWndEx, pTopFrame);
if (pFrame != NULL)
{
pFrame->GetMessageString(nID, rMessage);
return;
}
else // Maybe, MDIChild frame
{
CMDIChildWndEx* pMDIChild = DYNAMIC_DOWNCAST(CMDIChildWndEx, pTopFrame);
if (pMDIChild != NULL)
{
pMDIChild->GetMessageString(nID, rMessage);
return;
}
else // Maybe, OLE frame...
{
COleIPFrameWndEx* pOleFrame = DYNAMIC_DOWNCAST(COleIPFrameWndEx, pFrame);
if (pOleFrame != NULL)
{
pOleFrame->GetMessageString(nID, rMessage);
return;
}
}
}
}
}
还需要更改 CMyDropDownFrame::OnCreate() 来处理保护成员:
int CMyDropDownFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
.
.
.
// "Clone" the original toolbar:
m_pWndOriginToolbar->CopyTempAll(&m_wndToolBar);
/*
m_pWndOriginToolbar->m_ImagesLocked.CopyTemp(m_wndToolBar.m_ImagesLocked);
m_pWndOriginToolbar->m_ColdImagesLocked.CopyTemp(m_wndToolBar.m_ColdImagesLocked);
m_pWndOriginToolbar->m_DisabledImagesLocked.CopyTemp(m_wndToolBar.m_DisabledImagesLocked);
m_pWndOriginToolbar->m_LargeImagesLocked.CopyTemp(m_wndToolBar.m_LargeImagesLocked);
m_pWndOriginToolbar->m_LargeColdImagesLocked.CopyTemp(m_wndToolBar.m_LargeColdImagesLocked);
m_pWndOriginToolbar->m_LargeDisabledImagesLocked.CopyTemp(m_wndToolBar.m_LargeDisabledImagesLocked);
*/
.
.
.
};
推荐阅读
- python - google-cloud-storage get_bucket 非常慢
- javascript - 无法将 GeoJSON 从 PostGIS 加载到 Leaflet
- python - 如何在 Python 中输出拟合数据以在 Origin 中使用
- javascript - Google Scripts / Sheets 添加前缀国际电话
- python - py2app“/usr/lib/libstdc++.6.dylib:没有这样的文件或目录”错误
- python-3.x - 如何使用 matplotlib 从数据框中的类标签中添加图例?
- javascript - 更改 ReactPlayer 字幕
- flask - 在heroku上部署烧瓶应用程序的麻烦
- android - Android Kotlin:当应用程序处于打盹模式时获取位置
- react-native - 添加商品时如何添加到购物车?