winapi listview check item c++ - c++

I use minGW32 compiler.
I created a ListView with checkbox something like this:
HWND hListView = CreateWindowExW(0, WC_LISTVIEWW, L"",
WS_VISIBLE | WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_EDITLABELS,
10,10,500,500, hwnd, (HMENU)ID_LISTVIEW, GetModuleHandle(NULL), NULL);
SendMessage(hListView, WM_SETFONT, (WPARAM) font, TRUE);
ListView_SetExtendedListViewStyle(hListView, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_GRIDLINES/*LVSCW_AUTOSIZE_USEHEADER*/);
lvc.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH | LVCF_FMT;
lvc.fmt = LVCFMT_LEFT;
And I would like to check when any checkbox is checked. for example. If I check any checkbox show me a messagebox:
I use this WM_NOTIFY:
case WM_NOTIFY:
{
switch (LOWORD(wParam))
{
case ID_LISTVIEW:
{
switch (((LPNMHDR) lParam)->code)
{
case LVN_ITEMCHANGED :
MessageBoxW( NULL, (LPCWSTR)lpMsgBuf, L"Error", MB_OK | MB_ICONERROR );
}
break;
}
break;
}
break;
}
break;
But this alwas happened. When I click an empty area of the ListView or when just click any item. But I would like to run the messagebox ONLY when the checkbox is changed.

LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
if(pnmv->uChanged & LVIF_STATE) // item state has been changed
{
switch(pnmv->uNewState & LVIS_STATEIMAGEMASK)
{
case INDEXTOSTATEIMAGEMASK(2):
// pnmv->iItem was checked
break;
case INDEXTOSTATEIMAGEMASK(1):
//pnmv->iItem was unchecked
break;
}
}

Related

WINAPI/C++: mouse hover over any child doesn't work - what can be the reason?

I'm trying to catch mouse hovering over the buttons in my window, which I'm programming using plain C++14 in MSVS19 and WinAPI. Here's the code snippet and some context:
isTracking is defined as bool earlier
hBox is a button created in WM_CREATE using CreateWindowW
hBox = CreateWindowW(WC_BUTTON, L"TEST BOX", WS_TABSTOP | WS_VISIBLE | WS_CHILD, 300, 250, 100, 33, hWnd, (HMENU)IDC_BUTN10, NULL, NULL);
hWnd is a handle to window that a CALLBACK WndProc function receives
case WM_MOUSEMOVE:
{
HWND hTrack = hBox;
if (!isTracking) {
TRACKMOUSEEVENT tme = {};
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.hwndTrack = hTrack;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
isTracking = true;
}
break;
}
case WM_MOUSEHOVER:
{
OutputDebugStringW(L"HOVER\n");
MessageBox(nullptr, L"Entered", L"Info", MB_OK);
break;
}
case WM_MOUSELEAVE:
{
isTracking = false;
MessageBox(nullptr, L"Left", L"Info", MB_OK);
break;
}
And it doesn't work.
However when I set hTrack to hWnd - it detects hovering over main window area (but not over any of the children) and creates message boxes.
I've tried hTrack = GetDlgItem(hWnd,IDC_BUTN10) too - but it doesn't work either for that element or any other. Only hWnd itself gets any reaction from the program - but I want to detect hovering over specific buttons and other UI elements.
I tested it using your code, and I succeeded in implementing the functionality you wanted.
Maybe you are using the message callback incorrectly, you can refer to my code.
BOOL TestDlg::PreTranslateMessage(MSG* pMsg)
{
switch (pMsg->message)
{
case WM_MOUSEMOVE:
{
HWND hTrack = hBox;
if (!isTracking) {
TRACKMOUSEEVENT tme = {};
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.hwndTrack = hTrack;
tme.dwHoverTime = HOVER_DEFAULT;
TrackMouseEvent(&tme);
isTracking = true;
}
break;
}
case WM_MOUSEHOVER:
{
OutputDebugStringW(L"HOVER\n");
::MessageBox(nullptr, L"Entered", L"Info", MB_OK);
break;
}
case WM_MOUSELEAVE:
{
isTracking = false;
//::MessageBox(nullptr, L"Left", L"Info", MB_OK);
break;
}
}
return CDialogEx::TestDlg(pMsg);
}

Owner draw listbox alway return (LPDRAWITEMSTRUCT)->itemID = -1

I created an owner draw listbox. Do you know why in WM_DRAWITEM message, I only receive (LPDRAWITEMSTRUCT)lParam->itemID = -1?
I'm coding with VS 2010 C++ Express and Win 7.
Create listbox and set scroll info:
lbHWND = CreateWindowExW(NULL, WC_LISTBOX, NULL,
WS_CHILD | WS_BORDER | WS_VISIBLE | LBS_NODATA |
LBS_OWNERDRAWFIXED | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT,
0, 0, 400, 400, tkHWND, (HMENU)IDC_LISTBOX_ENTRY, hInstance, 0);
SCROLLINFO lbSi = { 0 };
lbSi.cbSize = sizeof(SCROLLINFO);
lbSi.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
lbSi.nMin = 0;
lbSi.nMax = 1000;
lbSi.nPage = 20;
lbSi.nPos = 0;
SetScrollInfo(lbHWND, SB_VERT, &lbSi, TRUE);
WinProc:
LRESULT CALLBACK WndProc(HWND phwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_MEASUREITEM:
{
MEASUREITEMSTRUCT* lpmis = (LPMEASUREITEMSTRUCT)lParam;
switch (lpmis->CtlID)
{
case IDC_LISTBOX_ENTRY:
lpmis->itemHeight = 20;
break;
default:
break;
}
return TRUE;
}
case WM_DRAWITEM:
{
DRAWITEMSTRUCT* lpdis = (LPDRAWITEMSTRUCT)lParam;
// Check lpdis->itemID, for test purpose only
FILE *f;
if (!_wfopen_s(&f, L"E:\\lb.txt", L"ab"))
{
fprintf(f,"%d\r\n", lpdis->itemID);
fclose(f);
}
// lpdis->itemID always = -1
return TRUE;
}
}
}
I have find the answer: For an owner draw listbox with LBS_NODATA style, I have to tell the listbox number of items it has.
SendMessage(lbHWND, LB_RESETCONTENT, 0, 0); // Remove all items, if have any
SendMessage(lbHWND, LB_SETCOUNT, 1000, 0); // Set number of items (here is 1000)

check radiobutton state winapi

I use mingw32 compiler.
I created two radioButton:
radio1 = CreateWindowExW(WS_EX_TRANSPARENT , L"BUTTON", L"RadioButton1",
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON ,
0, 0, 0, 0,
hwnd, (HMENU)ID_RADIOBTN1,
GetModuleHandle(NULL), 0);
SendMessage(radioBtnDaily, WM_SETFONT, (WPARAM) font, TRUE);
radio2 = CreateWindowExW(WS_EX_TRANSPARENT , L"BUTTON", L"RadioButton2",
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON ,
0, 0, 0, 0,
hwnd, (HMENU)ID_RADIOBTN2,
GetModuleHandle(NULL), 0);
SendMessage(radio1, BM_SETCHECK , (WPARAM) font, TRUE);
SendMessage(radio2, WM_SETFONT, (WPARAM) font, TRUE);
And I handle the check state, something like this:
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_RADIOBTN1:
{
MessageBoxW( NULL, "radio1 is checked", L"radio", MB_OK | MB_ICONERROR );
}
break;
case ID_RADIOBTN2:
{
MessageBoxW( NULL, "radio2 is checked", L"radio", MB_OK | MB_ICONERROR );
}
break;
....
But this always run when I click the radiobutton so it not check the state.
How to check the state without use the click event?
Use IsDlgButtonChecked:
if(IsDlgButtonChecked(hwnd, ID_RADIOBTN1))
MessageBox(NULL, "radio1 is checked")
else
MessageBox(NULL, "radio1 is not checked")
Use the BM_GETCHECK message, or the Button_GetCheck() macro, to get the radio button's actual state, eg:
radio1 = CreateWindowExW(WS_EX_TRANSPARENT , L"BUTTON", L"RadioButton1",
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON ,
0, 0, 0, 0,
hwnd, (HMENU)ID_RADIOBTN1,
GetModuleHandle(NULL), 0);
SendMessage(radio1, WM_SETFONT, (WPARAM) font, TRUE);
radio2 = CreateWindowExW(WS_EX_TRANSPARENT , L"BUTTON", L"RadioButton2",
WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON ,
0, 0, 0, 0,
hwnd, (HMENU)ID_RADIOBTN2,
GetModuleHandle(NULL), 0);
SendMessage(radio2, WM_SETFONT, (WPARAM) font, TRUE);
.
case WM_COMMAND:
if ((HIWORD(wParam) == BN_CLICKED)
{
switch(LOWORD(wParam))
{
case ID_RADIOBTN1:
{
switch (Button_GetCheck(radio1))
{
case BST_CHECKED:
MessageBoxW( NULL, L"radio1 is checked", L"radio", MB_OK );
break;
case BST_INDETERMINATE:
MessageBoxW( NULL, L"radio1 is indeterminate", L"radio", MB_OK );
break;
case BST_UNCHECKED:
MessageBoxW( NULL, L"radio1 is unchecked", L"radio", MB_OK );
break;
}
}
break;
case ID_RADIOBTN2:
{
switch (Button_GetCheck(radio2))
{
case BST_CHECKED:
MessageBoxW( NULL, L"radio2 is checked", L"radio", MB_OK );
break;
case BST_INDETERMINATE:
MessageBoxW( NULL, L"radio2 is indeterminate", L"radio", MB_OK );
break;
case BST_UNCHECKED:
MessageBoxW( NULL, L"radio2 is unchecked", L"radio", MB_OK );
break;
}
}
break;
}
}
break;
Well that depends on what event you want to check the status of the button so you need some sort of interaction (this can be another event like window minimized, resized etc or another thread checking but not modifying the state of your control)
It you need to test the state of the radio button, you can use (in pascal):
if SendMessage(hradiobutton, BM_GETCHECK, 0, 0) = BST_CHECKED
(this for checked state).
You can replace BST_CHECKED with all the constants listed at:
Documentation from Microsoft
Please, forgive my errors.

BM_GETCHECK not working

I have code like this :
In WM_CREATE
hCheckBox = CreateWindowEx(0,"Button","Random text", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS| BS_AUTOCHECKBOX | BS_TEXT | WS_GROUP | WS_TABSTOP,150,323,300,20,hwnd,0,hInstance,0) ;
In WM_COMMAND
if ( SendMessage( hCheckBox , BM_GETCHECK, (WPARAM) NULL, (LPARAM) NULL ) == BST_CHECKED )
MessageBox( 0, "Working", "Msg", 0 );
Doesn't matter if the checkbox is checked or not, it never return BST_CHECKED.
Trying to make it work for the last 2 hours :(
It is not entirely apparent whether hCheckBox is a local automatic variable. If so, I can assure you it is not holding its value from the time the CreateWindow fires until the time the WM_COMMAND message is received. Use this instead:
LRESULT chk = SendDlgItemMessage(hDlg, IDC_CHECKBOX_CTRL_ID, BM_GETCHECK, 0, 0);
Where hDlg is your dialog or main window handle, and IDC_CHECKBOX_CTRL_ID is the control ID. To that, you need to specify the control id as a non-zero value for the HMENU parameter to your create-call:
hCheckBox = CreateWindowEx(0,"Button","Random text", WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS| BS_AUTOCHECKBOX | BS_TEXT | WS_GROUP |
WS_TABSTOP,150,323,300,20,hwnd, IDC_CHECKBOX_CTRL_ID, hInstance,0);
And in case it wasn't obvious. Define IDC_CHECKBOX_CTRL_ID as a non-zero integer.
EDIT
Assuming the control is setup correctly, you should be able to handle the WM_COMMAND for this checkbox as follows in your WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message)
{
case WM_CREATE:
CreateWindowExA(0,"Button","Random text", WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS| BS_AUTOCHECKBOX | BS_TEXT | WS_GROUP |
WS_TABSTOP,100,100,300,48, hWnd, (HMENU)IDC_CHECKBOX_CTRL_ID, hInst, 0);
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
if (wmId == IDC_CHECKBOX_CTRL_ID)
{
if (wmEvent == BN_CLICKED)
{
LRESULT chkState = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0);
if (chkState == BST_CHECKED)
MessageBoxA(hWnd, "Checkbox is checked!", "CheckBox", MB_OK);
}
break;
};
// fall-thru intentional
default:
return DefWindowProc(hWnd, message, wParam, lParam);
};
return 0;
}
I just slammed this into a stock generic WIN32 app with a blank window. the results are in the image below:

Store a value from text field in a .txt

My problem is very simple (at least i think it is). I'd like to capture a value from a text input and store it inside a txt file. Right now i'm using this code, and the action button is intended to write the content in file when clicked. But i'm getting the value of button registered in the file instead.
case WM_CREATE:{
CreateWindow(
TEXT("EDIT"), TEXT("value"),
WS_VISIBLE | WS_CHILD | WS_BORDER,
190, 50, 50, 20,
hwnd, (HMENU) NULL, NULL, NULL
);
CreateWindow(
TEXT("BUTTON"), TEXT("Ok"),
WS_VISIBLE | WS_CHILD,
250, 10, 30, 20,
hwnd, (HMENU) ID_BTN, NULL, NULL
);
break;
}
case WM_COMMAND: {
if (LOWORD(wParam) == ID_BTN) {
std::ofstream outfile;
outfile.open("C:\\file.txt", std::ios_base::app);
outfile << ID_BTN;
outfile.close();
MessageBox(hwnd, "Done!", "Title", MB_ICONINFORMATION);
return 0;
}
break;
}
Thanks.
EDIT: #ZanLynx, I tried to do what you have said, but compiler keep saying hwndText wasn't declared, when it was.
107 `hwndText' undeclared (first use this function)
Here's the code
#define ID_BTN 1
#define ID_TXT 2
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
HWND hwndText = CreateWindow(
TEXT("Edit"), TEXT("Write here"),
WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
190, 10, 100, 20,
hwnd, (HMENU) ID_TXT, NULL, NULL
);
CreateWindow(
TEXT("BUTTON"), TEXT("OK"),
WS_VISIBLE | WS_CHILD,
250, 10, 30, 20,
hwnd, (HMENU) ID_BTN, NULL, NULL
);
break;
}
case WM_COMMAND:
{
if (LOWORD(wParam) == ID_BTN)
{
LRESULT iTextSize = SendMessage(hwndText, EM_GETLIMITTEXT, 0, 0);
char *szText = new char[iTextSize];
SendMessage(hwndText, WM_GETTEXT, iTextSize, (LPARAM)szText);
std::ofstream outfile;
outfile.open("C:\\f.txt", std::ios_base::app);
outfile << szText;
outfile.close();
MessageBox(hwnd, "Done!", "Title", MB_ICONINFORMATION);
return 0;
};
break;
}
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
Store the handle to your EDIT window.
Then you can use the Edit Control functions to get the text so you can write it into a file.