|
Your classes are great!;)
However, there is a problem with the mechanism of message reflection provided by MFC (Please see MSDN: TN062: Message Reflection for Windows Controls).
Message reflection allows notification messages to be handled in either the child control window or the parent window, or in both. In this case, they can be handled in CMainFrame or CMainToolBar. However, when the chevron of the main toolbar is pushed, the notification messages are sent by the toolbar control ( m_tbCtrl ) of the CToolBarPopup window. So the notification messages are reflected to m_tbCtrl but not the main tool bar (even though they have the same ID). Hence, you can no long handle reflected messages in CMainToolBar.
Possible solution:
1. In CMainFrame::OnNotify, reflects the notification messages according the the control ID but not the handle:
BOOL CMainFrame::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// TODO: Add your specialized code here and/or call the base class
// forward to m_pToolBar first -- Li Lirong 08/10/2001
BOOL bResult = FALSE;
NMHDR* pNMHDR = (NMHDR*)lParam;
CWnd* pwndFrom = CWnd::FromHandlePermanent(pNMHDR->hwndFrom);
CWnd* pwndFromParent;
if(pwndFrom &&
(pwndFromParent = pwndFrom->GetParent()) &&
pwndFromParent->IsKindOf(RUNTIME_CLASS(CToolBarPopup)))
{
class LTBP : public CToolBarPopup
{
friend class CMainFrame;
};
CWnd* pwnd = ((LTBP*)pwndFromParent)->m_pToolBar;
if (pwnd)
{
// reflect the message through the message map as OCM_NOTIFY
int nCode = pNMHDR->code;
AFX_NOTIFY notify;
notify.pResult = pResult;
notify.pNMHDR = pNMHDR;
bResult = pwnd->OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), & notify, NULL);
}
} // if(pwndFrom)
return bResult ? bResult : CMDIFrameWndEx::OnNotify(wParam, lParam, pResult) ;
}
2. In CToolBarPopup, reflects the messages to CToolBarEx?
I also have another question:
How can I put a CSizingControlBar inside the rebar?
Best regards.
Lirong
http://homex.coolconnect.com/member3/lilirong/
|
|
|
|
|
CSizingControlBar works properly with Rebar, what error with your project?
Maybe you forgot to add following code both:
EnableDocking(CBRS_ALIGN_ANY);
m_wndMyBar.EnableDockingCBRS_ALIGN_ANY);
|
|
|
|
|
I use to be able to do this
CMDIFrameWndEx* pMDIFrameWnd = (CMDIFrameWndEx*)GetMDIFrame();
pMenu = pMDIFrameWnd->GetMenu()->GetSubMenu(3);
while(pMenu->GetMenuString(i,mitems,MF_BYPOSITION)){
i++;
}
But now using
pMenu = pMDIFrameWnd->GetMenu()->GetSubMenu(3);
always returns NULL when called in the CMDIChildWndEx derived class.
Any Clues why.
Thanks
Chris
|
|
|
|
|
Chris,
You should use
pMenu = CMenu::FromHandle( pMDIFrameWnd->m_wndMenuBar.GetMenu() )->GetSubMenu( 3 )
Regards,
Nikolay
|
|
|
|
|
If I add more then one toolbars to m_wndReBar all toolbars are in a separate band.
How can I dock toolbars together at startup.
With normal toolbars there is a function "DockControlBarLeftOf" but how to do this with the
toolbars in m_wndReBar?
|
|
|
|
|
If I add more then one toolbars to m_wndReBar all toolbars are in a separate band.
How can I dock toolbars together at startup.
With normal toolbars there is a function "DockControlBarLeftOf" but how to do this with the
toolbars in m_wndReBar?
|
|
|
|
|
I'm not sure I understand what you mean by "dock toolbars together". And where did you find DockControlBarLeftOf function? Could you please clarify your point?
Regards,
Nikolay
|
|
|
|
|
I want to set two toolbars together in one band if I start my program the first time.
|
|
|
|
|
Why don't you simply put your bands in one row? Keep in mind that each band can own only one window.
|
|
|
|
|
Yes, I simply want to put two bands (or toolbars) in one row but I want to do this in the program at the first start and not by hand with the mouse.
Imagine I have five short bands or toolbars. What happens at the first start?
|
|
|
|
|
Just don't set RBBS_BREAK style when you add bar to the re-bar control.
|
|
|
|
|
Is there an easy way to place a combo box (or other control) in the toolbar?
Correct working in the "Customize Toolbar" dialog seems to be a problem.
|
|
|
|
|
The technique i know is a bit crude since the combo box is created using the default system font (that ugly, large, bold font), but anyway here it is:
Step 1
======
Create a toolbar class that subclasses the MFC CToolBar, for example CMyToolBar, and add the combobox as a member variable to it:
class CMyToolBar : public CToolBar
{
public:
CComboBox m_wndCombo;
}
Step 2
======
You have to create the toolbar and its combo box here, so in CMainFrame::OnCreate(..) add a member variable for your subclassed toolbar (e.g. m_wndMyToolbar) to replace the MFC-generated m_wndToolbar, and add the code to create your subclassed toolbar, similar to the MFC auto-generated code for its toolbars. Then add the following two lines:
/* this sets the first button on the toolbar to a combo box */
/* IDW_COMBO is defined in string table - if i remember well! */
m_wndMyToolbar.SetButtonInfo(0, IDW_COMBO, TBBS_SEPARATOR, 100);
/* this creates the combo box */
CRect y_Rect;
m_wndMyToolbar.GetItemRect(0, &y_Rect);
y_Rect.top = 3;
y_Rect.bottom = y_Rect.top + 150;
if (!m_wndMyToolbar.m_wndCombo.Create(CBS_DROPDOWNLIST|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL, rect, &m_wndMyToolbar, IDW_COMBO)) /* note the ID of the combo box used earlier */
{
TRACE0("Failed to create combo-box\n");
return FALSE;
}
That's it. You can then access the combo box from the mainframe as follows:
void CMainFrame::ClearComboBox()
{
m_wndMyToolbar.m_wndCombo.ResetContent();
}
(I hope i remembered the technique correctly!)
Regards,
Chris Spiteri
|
|
|
|
|
Yes, this will work on principle but if I use this with the sample program I got problems.
I've created a new toolbar derived from the CToolBarEx class and then inserted a combo box.
After this I added the toolbar to the m_wndReBar member.
All this works fine but in the "Customize Toolbar" dialog the combo box is not handled correctly.
I got to items in the "Customize Toolbar" dialog for the combo box and the position in the toolbar is corrupt after leaving the dialog.
Maybe in the framework some things should be changed to better handle the position and number of inserted controls.
|
|
|
|
|
Yes, the CToolBarEx class should be reworked somehow to handle combo-boxes properly. Unfortunately, I don't have any ready solution now. I would suggest you to place your combo in a separate band...
Regards,
Nikolay
|
|
|
|
|
-- // Commonres.h
#define IDC_COMBOBOXEX1 1160
#define IDC_STATIC_COMBO 1161
-- // MainFrm.cpp
{ { 0, IDC_COMBOBOXEX1, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0 }, false },
-- // String Table ( IDC_COMBOBOXEX1 Combo\nCombo)
-- //ToolBarEx.h CComboBoxEx m_comboBox; CStatic m_stCombo;
// ToolBarEx.cpp
--> bool CToolBarEx::Create(....
if (!m_comboBox.Create(
CBS_DROPDOWNLIST|WS_VISIBLE|WS_TABSTOP,
CRect(0, 0, 0, 200), this, IDC_COMBOBOXEX1))
{
TRACE0("Failed to create combo-box\n");
return FALSE;
}
if (!m_stCombo.CreateEx(WS_EX_TRANSPARENT, _T("STATIC"), NULL,
WS_VISIBLE|WS_CHILD,
CRect(0, 0, 0, 0), this, IDC_STATIC_COMBO))
{
TRACE0("Failed to create static-box\n");
return FALSE;
}
m_stCombo.SetFont(GetFont());
m_stCombo.SetWindowText(" Combo"); ......
--> void CToolBarEx::UpdateParentBandInfo()
{
CToolBarCtrl& tbCtrl = GetToolBarCtrl();
tbCtrl.AutoSize();
TBBUTTONINFO ptbbi;
CRect rctcb;
ptbbi.dwMask= TBIF_SIZE;
ptbbi.cbSize= sizeof(TBBUTTONINFO);
tbCtrl.GetButtonInfo(IDC_COMBOBOXEX1, &ptbbi);
ptbbi.cx=120;
tbCtrl.SetButtonInfo( IDC_COMBOBOXEX1, &ptbbi);
tbCtrl.GetRect(IDC_COMBOBOXEX1, rctcb);
m_comboBox.MoveWindow(rctcb); ........
rctcb.top=rctcb.top+24;
m_stCombo.MoveWindow(rctcb);
int inc=CommandToIndex( IDC_COMBOBOXEX1 );
inc++;
--> // Modify parent band info accordingly
REBARBANDINFO rbbi;
rbbi.cbSize = sizeof( rbbi );
rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE;
if(inc==tbCtrl.GetButtonCount())
rbbi.cxIdeal = cxIdeal-ptbbi.cx;
else
rbbi.cxIdeal = cxIdeal;
rbbi.cxMinChild = ptbbi.cx;
rbbi.cyMinChild = cyChild;
VERIFY( GetParentReBarCtrl().SetBandInfo( GetParentBandIndex(), &rbbi ) );
Invalidate(); // visual feedback
It looks good handled in the "Customize Toolbar" . But combobox is not created in the
CMainToolBar!
M. H.
|
|
|
|
|
Where u ever able to get your code to show the combo box in the CMainToolBar ?
Chris
|
|
|
|
|
How to set the fixed width of toolbar button if button's text is too long?
And how to create logo bar likes IE placed on right-top corner of the window?
|
|
|
|
|
1. Try to play with CToolBarCtrl::SetButtonWidth( int cxMin, int cxMax ).
2. Study MFCIE sample in MSDN Library.
|
|
|
|
|
Is there any easy way to modify the menubar so that it acts more like the menubar in Visual Studio, i.e. so that a menu is collapsed if the (top-level) menu button is clicked while the menu is dropped down? Currently the menubar buttons function like push buttons rather than check buttons, which is more appropriate, I think.
Otherwise, great stuff of course!
|
|
|
|
|
Janne,
Good point!
As for the solution, the first one that comes to mind is to modify
CMenuBar::HookMessageProc() and CMenuBar::MessageProc() as follows:
bool CMenuBar::HookMessageProc( UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_LBUTTONDOWN:
{
CPoint pt( LOWORD( lParam ), HIWORD( lParam ) );
ScreenToClient( &pt );
if ( GetToolBarCtrl().HitTest( &pt ) == m_nItem )
{
GetParentFrame()->PostMessage( WM_CANCELMODE );
return true;
}
break;
}
...
}
return false;
}
LRESULT CALLBACK CMenuBar::MessageProc( int code, WPARAM wParam, LPARAM lParam )
{
ASSERT( m_pMenuBar != 0 );
if ( code == MSGF_MENU )
{
MSG* pMsg = ( MSG* )lParam;
if ( m_pMenuBar->HookMessageProc( pMsg->message,
pMsg->wParam, pMsg->lParam ) )
{
return 1;
}
}
return ::CallNextHookEx( m_hMsgHook, code, wParam, lParam );
}
But this approach has considerable drawback: you lose ability to close
MDI child window by double-clicking sys-menu icon. To overcome this
issue you will need to make some additional efforts. I hope I will
include workaround in the next version of the menubar.
Regards,
Nikolay
|
|
|
|
|
To use toolbar icons in more than 16 colors change:
ToolBarEx.cpp
line 165: VERIFY( imageList.Create( nIDCold, szIcon.cx, 0, clrMask ) );
to
VERIFY(imageList.Attach( ImageList_LoadImage(AfxGetResourceHandle(),MAKEINTRESOURCE(nIDCold),szIcon.cx, 0, clrMask,IMAGE_BITMAP,LR_CREATEDIBSECTION)));
and
line 171: VERIFY( imageList.Create( nIDHot, szIcon.cx, 0, clrMask ) );
to
VERIFY(imageList.Attach( ImageList_LoadImage(AfxGetResourceHandle(),MAKEINTRESOURCE(nIDHot),szIcon.cx, 0, clrMask,IMAGE_BITMAP,LR_CREATEDIBSECTION)));
|
|
|
|
|
Because that sample covers exactly what I need actually (excellent job!) I ried
to use it in my application that involves a splitter window. I placed all files (many more than written in the article !?) and removed the generated code
a mentioned in the article.
Finally I got a running application, but the difference to the generic app is the the rebar is missing and all toolbars and menubars are flat in the frame view.
My stupid question is: What do I have to pay attention to, if I want to use this excellent menubar etc. in a splitter application??
--
regards Matthias
|
|
|
|
|
Matthias,
I am glad to know that there are people who like this article .
You are absolutely right that more files than it is said in the article should be added to newly created projects. This is because the first part of the article is outdated Thank you for pointing this out. As for your question, I have created a test app with a splitter and I can say that it works just fine. Here are some tips:
1. Add the following files to your project:
CommonRes.h
CustomizeDialog.*
(MDI)FrameWndEx.*
GlobalData.*
MenuBar.*
SizableReBar.*
ToolBarEx.*
2. Include CommonRes.rc into your resource file (I did it manually by adding lines like #include "..\Common\CommonRes.rc").
3. Study carefully CMainFrame::OnCreate() and CToolBarEx derived class in the demo. It gives a sample of how to create and initialize toolbars correctly. Maybe it would make sense to cut and copy implementation of CMainFrame::OnCreate() and then customize it according to your specific needs.
4. Don't forget to create large toolbar bitmap (24x24) and hot bitmaps (only if you like hot tracking, of course). Important remark: toolbar's back color should be RGB( 255, 0, 255 ) = Purple (am I right? ).
Should you still have any problems using this set of classes, just let me know.
Regards,
Nikolay
PS: Well, now I see that it would be a good idea to update text of the article to reflect all these issues .
|
|
|
|
|
Thanx Nikolay, I revered the way to create a splitter. First I tried to transfer your classes to my project, Now I changed your sample to be a splitter and will continue with this.
I guess I never will fully understand who these Control-, Re- and whatever Bars are coming together.
Anyway, thanx again,;P
--
regards Matthias
|
|
|
|
|