I've a dialog, CFormView, which holds some buttons and a panel which holds Tabcontrol, radiobuttons, text input fields etc.
So, on my panel, the CWnd, I create my input fields like this:
pEdit = new CEdit();
pEdit->CreateEx(WS_EX_CLIENTEDGE, _T("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | nAttrMultiline | m_clRect, pclPanel, iID)
Where m_clRect is a CRect, pclPanel is my CWnd, and iID is just the controller ID.
I want to fill my CEdit with text when a button is clicked, but somehow I can't get the controller who has focus.
My first attempt was to call GetFocus(), cast it into a CEdit and add the text, but this just changes the text on my button, of course.
Second attempt was to check for WM_SETFOCUS with ON_WM_SETFOCUS() and keep the previous wnd and cast it and add text, but that just changes the text on my dialog.
Third attempt was to move this to my CWnd but as far as I can see, WM_SETFOCUS is never called.
Edit:
Tried ON_WM_ACTIVATE with ::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) inside my CWnd.
But that's not being called either.
Anybody has an idea what to try next?
You just answered yourself. The correct way to do it is: on the function that handles the
ON_COMMAND(...)
of each button call
pEdit->SetWindowText(_T("text"));.
GetFocus() is wrong, because it will return the button, as when you clicked it, you just finished to put the focus on it. You can get the edit using
CEdit* pEdit= ( CEdit*) GetDlgItem(ID_OF_EDIT);
where ID_OF_EDIT is the value you passed to CreateEx as iId parameter.
Related
I have an mfc application where my mainframe contains multiple CDockablePanes.
In some of the CDockablePanes I have a CMFCToolbar and a CTreeView.
When I receive the AFX_WM_RESETTOOLBAR message in my mainframe class, I use CMFCToolBar::ReplaceButton to add a CMFCToolBarComboBoxButton to my toolbar.
This works fine and I am able to use the combobox as expected however I want to receive a notification each time the combo box's edit control's text is changed (Each key press etc) but I have not been able to catch a CBN_EDTITCHANGE message at all.
I have been using this line in my message map:
ON_CBN_EDITCHANGE(ID_TREEVIEWFILTER_COMBOBOX, Test)
But not hitting the function 'Test'. I have managed to catch other combo box messages eg. ON_CBN_DROPDOWN from in the toolbar class but not CBN_EDITCHANGE.
In my CMFCToolBarComboBoxButton derived class I override the CMFCToolBarComboBoxButton::CreateCombo function as shown:
CComboBox* FilterComboButton::CreateCombo(CWnd* pWndParent, const CRect& rect)
{
CComboBox* pCombo = new CComboBox();
if (!pCombo->Create(CBS_DROPDOWN | WS_VISIBLE | WS_TABSTOP | WS_VSCROLL | WS_CHILD, CRect(25,0,175,FILTERTOOLBARHEIGHT), pWndParent, ID_TREEVIEWFILTER_COMBOBOX))
{
LOG("Failed to create FilterComboBox");
delete pCombo;
pCombo = NULL;
}
return pCombo;
}
Adding the code: BOOL bSuccess = pCombo->ModifyStyle(CBS_DROPDOWNLIST, NULL); after the call to CComboBox::Create causes me to receive the CBN_EDITCHANGE, but interferes with the function of the combobox.
I have managed to catch the edit controls message EN_UPDATE but not EN_CHANGE. This is so close but so far away...
Any help would be much appreciated, thanks in advance!
I have been tasked with assigning tooltips to each item in a configuration menu. I have completed "adding" the tooltip to each control on the page, but it seems sometimes the tooltip shows up and sometimes it does not, depending on the position of the control on the screen.
To tooltip-erize the pages I first
EnableToolTips(TRUE);
In each CPropertyPage's OnInitDialog method.
I then add the notification map
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipText)
With the function OnToolTipText looking as such
BOOL CCfgPrefPage::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT nID = pNMHDR->idFrom;
if (pTTT->uFlags & TTF_IDISHWND)
{
nID = ::GetDlgCtrlID((HWND)nID);
if(nID)
{
if( nID == GetDlgItem(IDC_PICKDIST_EDIT)->GetDlgCtrlID())
_tcsncpy_s(pTTT->szText, _T("Tool Tip Text"), _TRUNCATE);
else if( nID == GetDlgItem(IDC_ENDPTTOL_EDIT)->GetDlgCtrlID())
_tcsncpy_s(pTTT->szText, _T("Tool Tip Text"), _TRUNCATE);
pTTT->lpszText = pTTT->szText; // Sanity Check
pTTT->hinst = AfxGetResourceHandle(); // Don't think this is needed at all
return TRUE;
}
}
return FALSE;
}
It seems for some of my controls the tool tip will not show up. For most of the check box controls the tool tip displays, but for a few they just do not show. There are no other controls covering them up, they are not disabled.
Another thing, if I use the non-standard cursor windows repeatedly flashes the tool tip, so much so it is unreadable in some cases. How can I fix this? This is not a problem on CEdit controls, so why is it a problem elsewhere?
EDIT: Update, the controls that have been on the pages for years seem to show tool tips. Any control that I try to add now/today will not show tool tips at all. No matter the position, control type, settings, I cannot get a single tool tip to show on a newly inserted control.
If you do not want to use helper class I have proposed then fix the problems in your code.
First, use ON_NOTIFY_EX_RANGE macro when mapping the even handler, like this (this will cover all IDs):
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
Next, you need to fix your function. I see a few problems here. First, when testing for TTF_IDISHWND flag you only need to re-initalise the nID. You do not need to apply this to the whole function. Second, after all manipulations, your nID will be the actual dialog ID. There is no need to GetDlgItem() function
BOOL CCfgPrefPage::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT nID = pNMHDR->idFrom;
if (pTTT->uFlags & TTF_IDISHWND)
{
nID = ::GetDlgCtrlID((HWND)nID);
}
if(nID)
{
if( nID == IDC_PICKDIST_EDIT)
_tcsncpy_s(pTTT->szText, _T("Tool Tip Text"), _TRUNCATE);
else if( nID == IDC_ENDPTTOL_EDIT)
_tcsncpy_s(pTTT->szText, _T("Tool Tip Text"), _TRUNCATE);
//pTTT->lpszText = pTTT->szText; // Sanity Check
*pResult = 0;
return TRUE;
}
return FALSE;
}
Working with a toolbar which repeats some menu items from menus of an older MFC application, I have worked on this issue of tool tips as well as (1) modifying the toolbar bit map to include additional icons and (2) providing user feedback on current application state. My problem is that I have to do most of this by hand rather than using the various wizards and tools.
What I have done is to (1) add new members to the CView derived class to handle additional messages, (2) modified the toolbar bit map to add in the additional icons using both MS Paint and the Resource Editor, and (3) added new event ids and event handlers to the message map for the CView derived class.
One problem I ran into with the toolbar bitmap change was that since I was inserting an icon, I had to shift an existing icon in the bitmap to the right. My first attempt at this resulted in the shifted icon showing as a blank on the application toolbar. Then I realized that I needed to add a bit more to the length of the toolbar bitmap. After adding a couple more columns to the last icon in the toolbar bitmap to make it a standard width in pixels, the icon displayed properly.
For tooltips I added the following to the message map:
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipText)
I then added the following method to my class to handle the notifications for my menu items. As a side note, it appears that OnToolTipText() is the standard method used in CFrameWnd class and CMDIChildWnd class however CView derives from CWnd as does CFrameWnd so I doubt it makes a difference as to what the method is named.
inline BOOL CPCSampleView::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
static wchar_t toolTextToggleExportSylk [64] = L"Toggle SYLK export.";
static wchar_t toolTextClearWindow [64] = L"Clear the log displayed.";
static wchar_t toolTextConnectLan [64] = L"Log on the POS terminal through the LAN.";
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
switch (pNMHDR->idFrom) {
case ID_TOGGLE_SYLK_EXPORT:
pTTT->lpszText = toolTextToggleExportSylk;
return TRUE;
case ID_WINDOW_CLEAR:
pTTT->lpszText = toolTextClearWindow;
return TRUE;
case ID_CONNECT_LAN_ON:
pTTT->lpszText = toolTextConnectLan;
return TRUE;
}
// if we do not handle the message then return FALSE to let someone else do it.
return FALSE;
}
For the user feedback on a menu item which toggles a file export when doing reports I provided the following changes to the message map and then implemented the necessary methods. There are two types of messages involved so I had to add two methods and two new message map entries:
// New message map entries to handle the menu item selection event
// and to update the menu item and the toolbar icon with state changes
ON_COMMAND(ID_TOGGLE_SYLK_EXPORT, OnToggleExportSylk)
ON_UPDATE_COMMAND_UI(ID_TOGGLE_SYLK_EXPORT, OnUpdateToggleExportSylk)
// New methods added to the CView derived class
// handle the menu selection event generated by either selecting the menu item
// from the menu or by clicking on the icon in the toolbar.
void CPCSampleView::OnToggleExportSylk()
{
// Exclusive Or to toggle the indicator bit from 0 to 1 and 1 to 0.
GetDocument()->ulReportOptionsMap ^= CPCSampleDoc::ulReportOptionsExportSylk;
}
// handle the request from the MFC framework to update the displayed state this
// not only does a check mark against the menu item it also causes the toolbar
// icon to appear depressed if click is set or non-depressed if click is not set
inline void CPCSampleView::OnUpdateToggleExportSylk (CCmdUI* pCmdUI)
{
if (GetDocument()->ulReportOptionsMap & CPCSampleDoc::ulReportOptionsExportSylk)
{
// SYLK export is turned on so indicate status to the user. This will
// put a check mark beside the menu item and show the toolbar button depressed
pCmdUI->SetCheck (1);
}
else
{
// SYLK export is turned off so indicate status to the user. This will
// remove the check mark beside the menu item and show the toolbar button as raised.
pCmdUI->SetCheck (0);
}
}
The resource file changes were needed to provide a new button for the toggle action as well as to add a new menu item for the toggle action. I am using the same resource id for several different things since these are all separate. So the id for the resource string is the same as for the menu item and is same for the toolbar button so as to simplify my life and make it easy to find all the particular bits and pieces.
The toolbar resource file definition looks like:
IDR_MAINFRAME TOOLBAR 16, 15
BEGIN
BUTTON ID_CONNECT_LAN_ON
SEPARATOR
BUTTON ID_WINDOW_CLEAR
SEPARATOR
BUTTON ID_TOGGLE_SYLK_EXPORT
SEPARATOR
BUTTON ID_APP_ABOUT
END
And the specific part of the menu, which uses the same resource id for the toggle event id looks like:
MENUITEM "Export to SYLK file", ID_TOGGLE_SYLK_EXPORT
Then to provide the status bar text which shows up with a mouse over there is a string table addition:
ID_TOGGLE_SYLK_EXPORT "Toggle export of SYLK format report files for spreadsheets."
The lpszText member of the struct is describe in the MSDN documentation for the TOOLINFO struct as:
Pointer to the buffer that contains the text for the tool, or
identifier of the string resource that contains the text. This member
is sometimes used to return values. If you need to examine the
returned value, must point to a valid buffer of sufficient size.
Otherwise, it can be set to NULL. If lpszText is set to
LPSTR_TEXTCALLBACK, the control sends the TTN_GETDISPINFO notification
code to the owner window to retrieve the text.
Reviewing the existing answer to this question, I wondered about the if statement check for the TTF_IDISHWND flag. The MSDN documentation for the TOOLINFO struct has this to say:
Indicates that the uId member is the window handle to the tool. If
this flag is not set, uId is the tool's identifier.
I have seen so many posts about how to prevent the escape key from closing a CDIalog but in my case I want to close the dialog but it doesn`t.
I have created a sample MFC Dialog application thats adds property sheet and 2 property pages. I tried putting pretranslatemessage, OnCancel, KillFocus overrides into the property pages and the dialog but that doesn't get hit.
Used following code:
#include "proppage1.h"
#include "proppage2.h"
#include "mySheet.h"
// ......
protected:
// proppage1,proppage2 are the class dervied from CPropertyPage
proppage1 pg1;
proppage2 pg2;
// mySheet is the class dervied from CPropertySheet
mySheet *m_sheet;
In CMFCDlg::OnInitDialog() of MFCDlg.CPP
m_sheet = new mySheet(L"mySheet",this,0);
m_sheet->AddPage(&pg1);
m_sheet->AddPage(&pg2);
m_sheet->Create(this, WS_CHILD | WS_VISIBLE , 0);
m_sheet->ModifyStyleEx (0, WS_EX_CONTROLPARENT);
m_sheet->ModifyStyle( 0, WS_TABSTOP );
I dont get any events fired in propertypages and dialog.
If I place some controls on the property pages, then events are fired and can be catched in property pages.
However,in other case why wouldn't the Esc and other event get fired?
Please suggest?
Thanks,
Nikhil
m_sheet = new mySheet(L"mySheet",this,0);
m_sheet->AddPage(&pg1);
m_sheet->AddPage(&pg2);
I believe both pg1 and pg2 are objects of type CPropertyPage or derived class. If they are CDialog or derived objects, it may not work - ensure the message-map is correctly mapped with CPropertyPage and not CDialog
Further, there is no need to call Create for a CPropertySheet object. Constructor does the thing. Where are you calling DoModal or ShowWindow? If you are calling CPropertySheet::DoModal, there is no need to allocate property-sheet on heap.
I would have simply used:
CPropertySheet sheet( _T("MySheet Title") );
CPropertyPage page1(ID1), page2(ID2);
sheet.AddPage(&page1);
sheet.AddPage(&page2);
sheet.DoModal();
In your property sheet, you can capture the WM_KEYDOWN message and check for escape
BOOL CInfoPropertySheet::PreTranslateMessage(MSG* pMsg)
{
switch(pMsg->message)
{
case WM_KEYDOWN:
{
if( pMsg->wParam == VK_ESCAPE )
I have an MFC MDI application I've developed in Visual Studio with a tabbed interface. I would like to open views in the tab group that are non-document views – i.e. they have no associated document, no need to save them, etc. In a way they would behave like a non-modal dialog, but tabbed. [These windows are simply to display information and take commands]
The internal machinery of the MDI apps seems very geared toward working with the DocTemplate – Document – Frame – View object structures along with their associated windows.
Q1) Anybody got any ideas on how to create such windows and add them into the already-established MDI tab group? I’ve tried to create a RichEdit window and added it in, with:
// m_wndListingView will be a non-editable CRichEditCtrl
m_wndListingView->Create(WS_CHILD | WS_VISIBLE | ES_WANTRETURN | WS_VSCROLL |
WS_HSCROLL | ES_MULTILINE | ES_LEFT | ES_AUTOHSCROLL | ES_SAVESEL |ES_READONLY,
CRect(0, 0, 20, 20), pMainFrame, 1234);
// get Tab control and add a new tab
CMFCTabCtrl *mm_wndTabCtrl = &pMainFrame->GetMDITabs();
mm_wndTabCtrl->AddTab (m_wndListingView, _T("LISTING"));
This created and displayed the window .. but it was not added to the tab group.
Q2) If I managed to get a window (perhaps it needs to be a frame window) displayed properly in the tab group, how do I tell the ‘system’ that when the user closes it, I do not want the app to prompt the user to Save the document ? Perhaps I can overload an 'OnClose' method ... but it can't be document::OnClose(), because there is no document.
Thanks for any ideas,
CAS
You need to create a frame and view on which to host your rich edit. This can be done without a document. The view will be the parent of the richedit (rather than pMainFrame).
Something along these lines (warning, untested):
CFrame* pFrame = (Crame*)RUNTIME_CLASS( CFrame )->CreateObject();
CCreateContext context;
context.m_pNewViewClass = RUNTIME_CLASS( CView );
context.m_pCurrentDoc = NULL;
context.m_pCurrentFrame = NULL;
context.m_pLastView = NULL;
context.m_pNewDocTemplate = NULL;
// NOTE: create IDR_SOMERESOURCE string (for tab title), menu, etc as needed
BOOL frameLoaded = pFrame->LoadFrame( IDR_SOMERESOURCE, WS_OVERLAPPEDWINDOW, pMainFrame, &context );
if (frameLoaded)
Frame->InitialUpdateFrame( NULL, TRUE );
// now create your rich edit with the view as its parent
How to set tooltip at runtime in MFC Treeview ?
I am creating treeview like this :
m_pTreeview->Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP |
TVS_SINGLEEXPAND,CRect(38, 82, 220 ,250), this, IDC_NDS_TREEVIEW);
Any help is appreciated..
Here some code : -- In .H file
afx_msg void OnMyTreeGetInfoTip(NMHDR pNMHDR, LRESULT pResult);
In BEGIN MESSAGE MAP block add -
ON_NOTIFY_REFLECT (TVN_GETINFOTIP, OnMyTreeGetInfoTip)
And use handler
void CMyTreeView::OnMyTreeGetInfoTip(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVGETINFOTIP pGetInfoTip = (LPNMTVGETINFOTIP)pNMHDR;
CString strItemTxt = m_TreeCtrl.GetItemText(pGetInfoTip->hItem);
strcpy(pGetInfoTip->pszText, strItemTxt);
*pResult = 0;
}
If you're referring to the tooltips for items in the tree control, you need to add TVS_INFOTIP to the window styles in Create (see list of tree-view styles). You'll also have to handle the TVN_GETINFOTIP notification message to provide the tooltip text depending on the item.
Use TVS_INFOTIP style to tree-view, and handle the TVN_GETINFOTIP notification using an ON_NOTIFY handler. Typecast the NMHDR ptr to NMTVGETINFOTOOLTIP ptr as
(NMTVGETINFOTOOLTIP *)pnmhdr and then set the tooltip string in this structure.
Pankaj's answer works if you are deriving your own control from CTreeControl.
Cassablanca's answer is correct only the code is missing.
So here are some tips from my own experience.
If you are not creating the control explicitly the GETINFOTIP style can be specified in the resource file where the control is being defined.
otherwise the style can be modified at runtime by getting the tree's window handle
HWND htreectrl = m_TreeCtrl.GetSafeHwnd();
LONG nOldStyle = GetWindowLong( htreectrl, GWL_STYLE);
LONG nNewStyle = nOldStyle & TVS_INFOTIP;
SetWindowLong( htreectrl, GWL_STYLE, nNewStyle);
To be able to handle GETINFOTIP:
If you are using the TreeControl as a member control inside a dialog:
ON_NOTIFY (TVN_GETINFOTIP, IDC_TREE, OnMyTreeGetInfoTip)
Else if you are deriving your own control from CTreeControl then use this:
ON_NOTIFY_REFLECT(TVN_GETINFOTIP, OnMyTreeGetInfoTip)
Hope this helps someone.