CMFCToolBarComboBoxEdit handle delete button - c++

CMFCToolBarComboBoxEdit handles the BackSpace button but it doesn't handle the delete button.
Is there any way to handle the delete button except PreTranslateMessage?
if yes, what is this way?
if no, then how can I get the current cursor position in the control and how to remove specific char using its index so I can remove the char which on the right of the cursor if nothing is selected?
Thanks in advance.

Yes use, PreTranslateMessage. If you detected the sequence that should be handled, call:
if (..) // Check if you have a message that should
// be passed to the window directly
{
TranslateMessage(pMsg);
DispatchMessage(pMsg);
return TRUE;
}
You can do this always in PreTranslateMessage, when you detect that the message should be handled by the default control, and should not be handled by any other control in the chain of windows that execute PreTranslateMessage. This is also helpful if you have a combo box open and want the Page Down/Up handled internally and not by the view or any accelerator.

I've handled the delete key in the PreTranslateMessage as follows:
BOOL PreTranslateMessage(MSG* pMsg)
{
if(WM_KEYDOWN == pMsg->message && VK_DELETE == pMsg->wParam)
{
int iStartChar = -1, iEndChar = -1;
GetSel(iStartChar, iEndChar);
if(iStartChar != iEndChar)
Clear(); //clear the selected text
else
{
SetSel(iStartChar, iStartChar + 1);
Clear();
}
}
return CMFCToolBarComboBoxEdit::PreTranslateMessage(pMsg);
}

Related

Is there an event that fires from a C++ program when a control is about to lose focus?

I am trying to fix a validation bug in a MFC CEdit control. Currently, validation is performed in an OnChange event handler. But this does not work because it validates data before the user is finished entering it.
So, instead, I am trying to validate inside an OnKillFocus event handler. If validation fails, then I use GotoDlgCtrl() to return focus to the edit box that contained the invalid data. And when I call GotoDlgCtrl(), the kill focus event fires again, and I'm in an infinite loop.
So, I'd like to handle an event that fires just before the control loses focus, so that if I determine that the data is invalid, I can stop focus from leaving and instead get the user to enter correct data.
I know I've seen a Validating event someplace, but that was probably in the .Net world. But it offers the functionality I'm looking for.
Right-click the dialog resource and invoke Class Wizard:
Next, go to the Virtual Functions tab, locate PreTranslateMessage and add it:
Then, you can do something like this:
BOOL CTestDlgDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_CHAR)
{
CWnd *pControl = GetDlgItem(IDC_EDIT1);
if (pControl->GetSafeHwnd() == pMsg->hwnd)
{
if (pMsg->wParam == _TINT('!'))
{
AfxMessageBox(_T("Not allowed ! character"));
return TRUE;
}
}
}
return CDialogEx::PreTranslateMessage(pMsg);
}
Normally the control is a member variable of type CEdit so you could compare against m_edit.GetSafeHwnd() instead.
Results:
Update
I realise you stated:
But this does not work because it validates data before the user is finished entering it.
You could use WM_KEYUP instead:
BOOL CTestDlgDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYUP)
{
CWnd *pControl = GetDlgItem(IDC_EDIT1);
if (pControl->GetSafeHwnd() == pMsg->hwnd)
{
CString str;
GetDlgItemText(IDC_EDIT1, str);
if (str.Find(_T("!")) >= 0)
{
AfxMessageBox(_T("Not allowed ! character"));
return TRUE;
}
}
}
return CDialogEx::PreTranslateMessage(pMsg);
}
That is give you a chance to validate after the display has been updated.
An alternative it to customize your DoDataExchange handler. In there you can validate as required. Then in your code you simple test the return value of UpdataData(TRUE) for FALSE.

Differentiate between user click and SetChecked() in CListCtrl

I have a CListCtrl with checkboxes that I need to enable or disable based on some external factor. However, when I have more items in the list that can be displayed I cannot use EnableWindow(FALSE) on the control as it also disables the scrollbar.
So, I have searched and came up with the following code in the message map:
ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHECKBOX_LIST, OnCheckboxChanged)
The callback function is implemented as:
void CUserPropertiesDialog::OnCheckboxChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*) pNMHDR;
LVHITTESTINFO hitInfo;
hitInfo.pt = pNMListView->ptAction;
int nItem = m_checkBoxList.HitTest(&hitInfo);
if (hitInfo.flags != LVHT_ONITEMSTATEICON) return;
std::string groupName = static_cast<LPCTSTR>(m_checkBoxList.GetItemText(nItem, 0));
if (!CCharmUserAdminGUIApp::getTheCharmUserAdminGUIApp().isAdministrator())
{
if (pNMListView->uChanged & LVIF_STATE)
{
if (((pNMListView->uNewState & INDEXTOSTATEIMAGEMASK(2)) != 0) && ((pNMListView->uOldState & INDEXTOSTATEIMAGEMASK(1)) != 0))
{
CH_INFO1("CUserPropertiesDialog::OnCheckboxChanged - CheckBox Now Selected", groupName);
}
else if (((pNMListView->uNewState & INDEXTOSTATEIMAGEMASK(1)) != 0) && ((pNMListView->uOldState & INDEXTOSTATEIMAGEMASK(2)) != 0))
{
CH_INFO1("CUserPropertiesDialog::OnCheckboxChanged - CheckBox Now Unselected", groupName);
}
}
}
}
The problem is that this function is called when a user clicks the checkbox (good!) but also when the SetChecked() function is called from code.
I had hoped the check on hitInfo.flags would enable me to tell the click and the function apart but this is not the case.
Is there, besides setting some global flag before/after the function call and use that in the callback, any other way to tell whether the click or the function call is used?
I use the same inmy program and I used a flag.
But I use LVN_ITEMCHANGING. With this message I can prevent any change.
I overwrote SetCheck (even it is not virtual) and set a flag before I Change the Status of a list box item. The internal OnItemChanging Routine sees the flag set and allows the Change. The flag is directly cleared after the return.
So if the same Action is done with the mouse the flag is not set and you Need to check in a different way.
Same when I am loading the box. I set the flag, so that all changes can pass through...

Text Selection with CRichEditCtrl in MFC

I have CRichEditCtrl object which is read only(Text is for read and not allowed to modified). I want to provide functionality of Text Selection with Mouse for text displayed with CRichEditCtrl object.
Following Code is working to capture event for Left Mouse Button - DOWN & UP
BOOL CReportFormView::PreTranslateMessage(MSG* pMsg)
{
if (m_EditNs->GetFocus()!=NULL)
{
switch (pMsg->message)
{
case WM_LBUTTONDOWN:
return TRUE;
case WM_LBUTTONUP:
return TRUE;
}
}
}
Now looking for some code to write in case block which will highlight selected text. I want to know if there is any API available for CRichEditCtrl object which help to track at which location user pressed Left Mouse Button and released
You could use member function CString strText = m_myRichEditCtrl.GetSelText(); or some other member function. Like GetSel() just a suggestion.
I think you will need to use the EM_CHARFROMPOS message. ex. some form of this:
POINTL pt { x,y }; // ... screen coordinates to test relative to edit
DWORD info = m_EditNS->SendMessage(EM_CHARFROMPOS, 0, pt);
int charIndex = LOWORD(info);
int line = HIWORD(info);
After that, set the selection with normal selection methods.
https://msdn.microsoft.com/en-us/library/windows/desktop/bb761566(v=vs.85).aspx

Delete Key is not triggering KeyUp & KeyDown Event

I am currently dealing with a multi-form application and am having issue registering a del key press, the application that requires the del key is a form with a frame on it with objects painted on it that can be selected, upon pressing the del key the selected objects are to be deleted via a deleteObjects method. The code I am currently using is as follows
void __fastcall TF_Image::KeyUpKbd( WORD &Key )
{
if(Key == VK_DELETE || Key == VK_DKEY)
{
deleteSelectedObjects();
}
}
(Note: There are other paramenters in the function call but they aren't used)
TF_Image inherits from TFrame
I have tried mapping other keys other than the del key ie the D key and have found that the method is called with no problem. I have discovered that when pressing (physically) the del key the methods associated with KeyUp & KeyDown are not called.
Edit: So i've attempted to add the DeleteSelectedOb() method to my WndProc method without much luck either.
void __fastcall TF_ImgBrowserOA::WndProc(TMessage &Message)
{
if (Message.Msg == WM_KEYDOWN)
{
if (Message.WParam == VK_DELETE)
{
F_Image->DeleteSelectedOb();
}
}
//code that manages window resize
TForm::WndProc(Message);
}
The WndProc method doent appear to respond to keystrokes
So after cleaning up some code in some other modules and removing unneccessary menu's I decided to go back and look at this section again after I found a similar piece of code implementing a similar function, I couldn't see much difference between them and so I recompiled and attempted to run my Delete function from the KeyDown event and for some reason it just worked, I suspect it came down to an issue of another element holding focus in the Application. As a precaution I also called a SetFocus() to the frame in which I required this code to operate in. Its still a mystery to me why this didn't work intially though.
Here is a snippet for my TRichEdit control (Script_Edit).
TWndMethod *PrevWndProc = Script_Edit->WindowProc;
Script_Edit->WindowProc = MyWndProc;
void __fastcall My_Form::MyWndProc(TMessage &Message) {
switch (Message.Msg) {
case WM_KEYDOWN: {
// Check for DELETE and BACKSPACE keys
if( Message.WParam == VK_BACK ||
Message.WParam == VK_DELETE
) {
// Do whatever you need
}
break;
default:
// call default handler if not processed
PrevWndProc(Message);
}
}
You can't get much closer to the message core than this with VCL...

Handling arrow key in cedit control of mfc

I'm making matlab-like command window using cedit control of mfc.
For example, after I input several commands, I want to display old command using an arrow key (specifically the up key).
I succeeded in displaying old commands, but failed to locate the cursor on the end of this command.
The reason seems that the arrow key was input one more time after I locate the cursor in the end of this command.
Here is detailed situation.
First I input command 'play'
and then Play!.. message pops up.
and in the next command prompt I hit '↑' key
and I succeded the old command 'play' streamed automatically,
However, my cursor go up to upper line.
# play
Play!.. | (← cursor located here..)
# play| (← I want to locate the cursor here, after hitting '↑' key)
This is my code:
class CEditCommand::CEdit
{
public:
virtual BOOL PreTranslateMessage(MSG* pMsg);
}
BOOL CEditCommand::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_UP)
{
int nS = 0; nE =0;
GetSel(nS, nE);
int nLineIndex = LineIndex();
CString str = m_CommandHistory[m_nCommandIndex];
m_nCommandIndex--;
SetSel(nLineIndex, nE);
ReplaceSel(str);
SetSel(0, -1);
SetSel(-1, -1);
}
}
}
I don't know why '↑' key would be pushed again after executing PreTranslateMessage.
Does anyone have an idea about this?
Your edit control will still get the up-arrow message, so you will need to return TRUE in CEditCommand::PreTranslateMessage() for both WM_KEYDOWN and WM_KEYUP when pMsg->wParam == VK_UP