Add custom controller to DialogBox: Faillure on Create - c++

I have to make a custom controller "MyCEdit" inherited from CEdit. I just want to push my custom controller in a dialogbox but the window crash on create. I saw the documention MSDN and made some adjustement :
On InitDialog I have:
if (message == WM_INITDIALOG)
{
CWnd* pWnd = CWnd::FromHandle(hwndDlg);
MyCEdit* pEdit = new MyCEdit();
pEdit->Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER,
CRect(10, 10, 100, 100), pWnd, IDC_CUSTOM_EDIT1); /* Failure here */
return TRUE;
}
I Have check the pointer pWnd, he's not NULL and point to the good window. And pEdit is not NULL.
My custom controller looks like (only override the PreTranslateMessage method):
class MyCEdit : public CEdit
{
public:
BOOL PreTranslateMessage(MSG* pMsg) override
{
if (pMsg->message == WM_KEYDOWN && ::GetKeyState(VK_CONTROL) != 0)
{
switch (pMsg->wParam)
{
case 'X': Cut(); return TRUE;
case 'C': Copy(); return TRUE;
case 'V': Paste(); return TRUE;
case 'Z': Undo(); return TRUE;
case 'A': SetSel(0, -1); return TRUE;
}
}
return CEdit::PreTranslateMessage(pMsg);
}
};
There is a step I miss or I make a wrong operation ?

Related

Question about WM_NOTIFY message for SysLink controls

In this Microsoft example on how to process the WM_NOTIFY message for a SysLink control they have this code,g_hLinkbeing the handle of the SysLink control:
// g_hLink is the handle of the SysLink control.
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
{
case NM_CLICK: // Fall through to the next case.
case NM_RETURN:
{
PNMLINK pNMLink = (PNMLINK)lParam;
LITEM item = pNMLink->item;
if ((((LPNMHDR)lParam)->hwndFrom == g_hLink) && (item.iLink == 0))
{
ShellExecute(NULL, L"open", item.szUrl, NULL, NULL, SW_SHOW);
}
else if (wcscmp(item.szID, L"idInfo") == 0)
{
MessageBox(hDlg, L"This isn't much help.", L"Example", MB_OK);
}
break;
}
}
break;
I don't uderstand why the (((LPNMHDR)lParam)->hwndFrom == g_hLink) condition is not needed for the else clause?
Or is this simply an error in the example?

Button not updating

I have an application, a game, that I've been working on and I stuck with a button not been (visually) updated.
The button is a pause button. When the app starts it is disabled (has WS_DISABLED style), but when the user starts a game, I simply remove that style responsable to disable it (WS_DISABLED).
The problem is: the button remains (visually) with the disabled style (when removing the style).
Or remains (visually) with the enable style (when adding the style).
However, the button is correctly updated when I click in it. I assume that this is a repaint/update issue.
I tried to repaint the window (no sucess):
RedrawWindow(hWnd,NULL,NULL,RDW_ALLCHILDREN | RDW_UPDATENOW);
Here is the code fragment located in WinProc function:
switch (message) {
case WM_CREATE:
CreateControls(hWnd);
break;
case WM_COMMAND:
{
switch (HIWORD(wParam)) {
case BN_CLICKED:
switch (LOWORD(wParam)) {
case 3:
{
char text[50];
GetDlgItemTextA(hWnd, 3, text, 50);
HWND pauseB = GetDlgItem(hWnd, 4);
LONG style = GetWindowLong(pauseB, GWL_STYLE);
if (strncmp(text, "Start", strlen(text)) == 0) {
SetDlgItemTextA(hWnd, 3, "Stop");
SetWindowLong(pauseB, GWL_STYLE, style & ~WS_DISABLED);
std::thread bt(RunGame, hWnd);
bt.detach();
} else {
SetDlgItemTextA(hWnd, 3, "Start");
SetWindowLong(pauseB,GWL_STYLE,style | WS_DISABLED);
}
RedrawWindow(hWnd,NULL,NULL,RDW_ALLCHILDREN | RDW_UPDATENOW);
//SendMessage(hWnd, WM_PAINT, NULL, NULL);
}
default:
break;
}
break;
default:
break;
}
}
break;
// other cases...
}
I may confess that I don't know much about c++. So sorry for my mistakes.

c++ winapi listview NM_CUSTOMDRAW: not getting CDDS_ITEMPREPAINT

I'm trying to change the row text-color of a list-view I made from a resource. For that, I handle NM_CUSTOMDRAW inside my dialog process. It's a modal dialog box, if that matters. According to the documentation,
dwDrawStage should equal CDDS_ITEMPREPAINT after returning CDRF_NOTIFYITEMDRAW. But this is not the case. I'm receiving CDDS_PREPAINT for every item.
What did I do wrong?
This is how I respond to the message:
case WM_NOTIFY:
if (((LPNMHDR)lParam)->hwndFrom == GetDlgItem(hwnd, IDC_List2) && ((LPNMHDR)lParam)->code == NM_CUSTOMDRAW)
{
int result = CDRF_DODEFAULT;
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
switch (lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
result = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT: //never gets executed
lplvcd->clrText = RGB(255, 0, 0);
result = CDRF_NEWFONT;
break;
}
//SetWindowLongPtr(hEdit, DWLP_MSGRESULT, result);
//return TRUE;
return result;
}
break;
these are the properties of the ListView:
IDC_List2,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,205,18,363,197,WS_EX_CLIENTEDGE
I figured out the problem:
WM_NOTIFY is handled inside a dialog so of course I have to return the values accordingly. The issue was, that I used the wrong variable for the window (hEdit in this case).
This is the corrected version if anyone cares:
case WM_NOTIFY:
if (((LPNMHDR)lParam)->hwndFrom == GetDlgItem(hwnd, IDC_List2) && ((LPNMHDR)lParam)->code == NM_CUSTOMDRAW)
{
int result = CDRF_DODEFAULT;
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
switch (lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
result = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
lplvcd->clrText = RGB(255, 0, 0);
result = CDRF_NEWFONT;
break;
}
SetWindowLongPtr(hDialog, DWLP_MSGRESULT, result);
return TRUE;
}
break;

How to get left click notification on an edit control?

I want to track event of single left-click on edit control.
I override PretranslateMessage function as below:
BOOL CMyClass::PreTranslateMessage(Msg* pMsg)
{
switch(pMsg->message)
case WM_LBUTTONDOWN:
{
CWnd* pWnd = GetFocus();
if (pWnd->GetDlgCtrlID == MY_EDIT_CTRL_ID)
{
//Do some thing
}
break;
}
}
The problem is that when I click on the edit control, all other control become disabled (for example buttons don't respond to clicks etc.)
How can I fix this problem? Or how can I track click notificationN on edit box?
You need this:
BOOL CMyClass::PreTranslateMessage(MSG* pMsg)
{
switch(pMsg->message)
{
case WM_LBUTTONDOWN:
{
CWnd* pWnd = GetFocus();
if (pWnd->GetDlgCtrlID() == MY_EDIT_CTRL_ID) // << typo corrected here
{
//Do some thing
}
break;
}
}
return __super::PreTranslateMessage(pMsg); //<< added
}
BTW its a bit awkword to use a switch statement here. Following code is cleaner IMO, unless you want to add morecases than only WM_LBUTTONDOWN:
BOOL CMyClass::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_LBUTTONDOWN)
{
CWnd* pWnd = GetFocus();
if (pWnd->GetDlgCtrlID() == MY_EDIT_CTRL_ID)
{
//Do some thing
}
}
return __super::PreTranslateMessage(pMsg); //<< added
}

Virtual listview doesn't get CDDS_ITEMPREPAINT c++

I am trying to change the color of listview item based on what I type on text box. When user type some text based on some logic I use I have below code
ListView_SetItemState(hList, wordid, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
Then on my WM_NOTIFY block I have this;
case WM_NOTIFY:
{
NMHDR *pNMHDR= (NMHDR*)lParam;
switch(pNMHDR->code){
case LVN_GETDISPINFO:
OnGetdispinfo(pNMHDR);
break;
case NM_CUSTOMDRAW:
wmnot= OnDraw(pNMHDR);
return wmnot;
break;
}
return 0;
}
OnGetdispinfo function fills my virtual listview by using Sqlite. In my ondraw function I have this
int OnDraw (NMHDR* pNMHDR){
int nIndex,state;
int result;
NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );
if (pLVCD->nmcd.hdr.hwndFrom==hList)
{
switch (pLVCD->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
result= CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
result=CDRF_NOTIFYSUBITEMDRAW;
break;
case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
nIndex=pLVCD->nmcd.dwItemSpec;
state=ListView_GetItemState(hList,nIndex,LVIF_TEXT |LVIF_PARAM);
if(state&LVIS_SELECTED==LVIS_SELECTED)
{
pLVCD->clrTextBk=RGB(124,34,78);
return CDRF_NEWFONT;
}
result= CDRF_DODEFAULT;
break;
default:
result=CDRF_DODEFAULT;
break;
}
}
return result; // CDRF_DODEFAULT
}
I get CDDS_PREPAINT message but I don't get CDDS_ITEMPREPAINT message at all.
My Listview has this styles according to Spy++
Windows Styles (5021580D)
WS_CHILDWINDOW
WS_VISIBLE
WS_VSCROLL
WS_TABSTOP
LVS_REPORT
LVS_SINGLESEL
LVS_SHOWSELALWAYS
Extended Styles (00000204)
WS_EX_LEFT
WS_EX_LTRREADING
WS_EX_RIGHTSCROLLBAR
WS_EX_NOPARENTNOTIFY
WS_EX_CLIENTEDGE
If your control is in a dialog, you have to return your result code using:
SetWindowLongPtr(hWnd, DWLP_MSGRESULT, result);
and then return TRUE from the DlgProc itself.
I finally solved the problem. Here is the fixed code.
First of all I added onchange notifier function so that I can detect changes for selection.
void OnItemChange (LPARAM lParam)
{
LPNMLISTVIEW pNMListView = reinterpret_cast<LPNMLISTVIEW>(lParam);
if ((pNMListView->uChanged & LVIF_STATE)
&& (pNMListView->uNewState & LVNI_SELECTED))
{
ListView_RedrawItems(hList,Query.WordID,pNMListView->iItem);
ListView_RedrawItems(hList,pNMListView->iItem,Query.WordID);
Query.WordID=pNMListView->iItem;
//DO STUFF;
}
}
Then I modified my custom draw function as well.
LRESULT OnDraw (LPARAM lParam)
{
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
int nIndex;
int state;
if (lplvcd->nmcd.hdr.hwndFrom!=hList)
return CDRF_DODEFAULT;
switch(lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT : //Before the paint cycle begins
return CDRF_NOTIFYITEMDRAW;
case CDDS_ITEMPREPAINT:
return CDRF_NOTIFYSUBITEMDRAW;
case CDDS_POSTPAINT:
nIndex=lplvcd->nmcd.dwItemSpec;
state=lplvcd->nmcd.uItemState;
return CDRF_DODEFAULT;
case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
nIndex=lplvcd->nmcd.dwItemSpec;
state=lplvcd->nmcd.uItemState;
if ( nIndex==Query.WordID) {
lplvcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
lplvcd->clrTextBk = GetSysColor(COLOR_HIGHLIGHT);
return CDRF_NEWFONT;
}
else{
lplvcd->clrText = GetSysColor(COLOR_WINDOWTEXT);
lplvcd->clrTextBk = GetSysColor(COLOR_WINDOW);
return CDRF_NEWFONT;
}
default:
return CDRF_DODEFAULT;
}
return CDRF_DODEFAULT;
}
So basically, I am not selecting items by ListView Messages. Instead i set Query.WordID to the item I want to select and if the item is selected(either by mouse or programmatically) I manually change the color of the item.