Right Click on ListView WinAPI C++ - c++

I have a window with a listview which I would like to right click an entry in the listview and have certain options displayed in a context menu. I cant find any examples for C++. The similar question is here but this is for listbox and i cant make it work in my program
So far I could not find any examples for c++ online. I could make it work for WM_LBUTTONDOWN on my main window but not on listview. Anyway, this is my code which i cant make it work:
case WM_CONTEXTMENU:
if ((HWND)wParam == hWndListView) {
POINT cursor;
GetCursorPos(&cursor);
TrackPopupMenu((HMENU)GetSubMenu(LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT)), 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON, cursor.x, cursor.y, 0, hWnd, NULL);
}
break;
Any advise? Thanks
Answer:
case WM_NOTIFY:
// When right button clicked on mouse
if ((((LPNMHDR)lParam)->hwndFrom) == hWndListView)
{
switch (((LPNMHDR)lParam)->code)
{
case NM_RCLICK:
{
POINT cursor; // Getting the cursor position
GetCursorPos(&cursor);
// Creating the po-up menu list
TrackPopupMenu((HMENU)GetSubMenu(LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT)), 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON, cursor.x, cursor.y, 0, hWnd, NULL);
}
break;
}
break;
}
break;
This works under WndProc

Related

How to add checkbox beside a text using mfc

I'm learning mfc, activex controls and containers. I'm doing a assignment on containers(Dialog).I have created a dialog, when I do right click, there are system menu items like Minimize, Maximize, Move, Size. All these items appeared by selecting true in dialog properties. I have added another item "Always on top" which will be appear on top. When the user click on Always on top I provided a message box which will say "Do you want enable?" I gave yes or no for that, but I have to avoid this message box and need to add a checkbox beside the Always on top item. So that whenever user wants the dialog to appear on top they can use the checkbox.
I have tried in one possible way by adding a bitmap image of checkmark but somehow it's not working and I have less time. If anyone has any idea how I can add this checkbox please let me know.
This is the code where I have appended the item
BOOL CDiagDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
CMenu * pSystemMenu = GetSystemMenu(FALSE);
pSystemMenu->AppendMenu(MF_ENABLED, IDM_SYSCOMMAND_CUSTOM,_T("Always on top"));
return TRUE; // return TRUE unless you set the focus to a control
}
void CDiagDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if (nID == IDM_SYSCOMMAND_CUSTOM)
{
AfxMessageBox(
_T("Enable Always on top"), MB_YESNO
);
switch (iResponse) {
case IDYES:
SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOSIZE);
break;
case IDNO:
SetWindowPos(&CWnd::wndNoTopMost, 0, 0, 0, 0, SWP_NOSIZE);
break;
}
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}

How to add mouse double click to ListBox

To this code: https://www.dreamincode.net/forums/topic/163804-microsoft-working-with-listboxes-part-i/
It is displaying list and looping nicely.
Sadly my guru never finished his code.
So plan would be adding double click detection on a name. How?
case WM_COMMAND:
{
return 0;
}
Something like this? 11 is this child window where names are.
case WM_COMMAND:
{
if (LOWORD(wparam) == 11) {
if ((message) == LBN_DBLCLK) {
cout << "double click" << endl;
}
}
return 0;
}
Doesn't work
First, according to the documentation:
Parameters
wParam
The LOWORD contains the identifier of the list box. The HIWORD specifies the notification code.
lParam
Handle to the list box.
Remarks
This notification code is sent only by a list box that has the LBS_NOTIFY style.
So in the first step you need to add this style and use HIWORD (wParam) to determine whether to double-click the list.
Then if you need to get the elements of the list, you should not send LB_GETCURSEL to window_handle, but should send it to This->listbox_handle, which is the window handle of the listbox. Then you can get it by sending LB_GETTEXT Text content.
Here is the code:
case WM_COMMAND:
{
if (HIWORD(wparam) == LBN_DBLCLK) {
TCHAR temp[100]{};
int index = SendMessageW(This->listbox_handle, LB_GETCURSEL, 0, 0L);
SendMessageW(This->listbox_handle, LB_GETTEXT, index, (LPARAM)temp);
MessageBox(window_handle, temp, L"test", 0);
}
return 0;
}
And it works for me:
Try replacing:
if ((message) == LBN_DBLCLK)
with:
if (HIWORD (wParam) == LBN_DBLCLK)
Documentation here.

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.

How to change menu item text?

I need to change menu item text on runtime. I've try to use GetMenuItemInfo() and SetMenuItemInfo():
case WM_NOTIFYICONMSG:
switch (lParam) {
case WM_LBUTTONDBLCLK:
someAction();
break;
case WM_RBUTTONDOWN:
{
POINT point;
GetCursorPos(&point);
HMENU hMenu;
HMENU hMenuTrackPopup;
hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENU));
if (hMenu) {
MENUITEMINFOA menuitem = { sizeof(MENUITEMINFOA) };
GetMenuItemInfoA(hMenu, IDM_EXIT, false, &menuitem);
menuitem.dwTypeData = "New text here";
SetMenuItemInfoA(hMenu, IDM_EXIT, false, &menuitem);
hMenuTrackPopup = GetSubMenu(hMenu, 0);
TrackPopupMenu(hMenuTrackPopup, 0, point.x, point.y, 0, hWnd, NULL);
DestroyMenu(hMenu);
}
}
break;
default:
break;
}
break;
But it doesn't work, text doesn't changed. What I am doing wrong? How to implement it?
As #HansPassant pointed out the solution is:
You are not using MENUITEMDATA correctly, you forgot to set the fMask member. Read the MSDN article for the struct for details
and then:
add menuitem.fMask = MIIM_TYPE | MIIM_DATA; and it works well
I can't take credit for this solution but am providing it here so that the next person that needs an answer to that question can easily find it without parsing the comments' section

C++ window draggable by its menu bar

So I'm using Visual C++, and I have created a draggable, borderless window. Anyway, there is a toolbar along the top, and i want to be able to drag the window by that toolbar. I still want the toolbar to be functional, but i have no earthly idea how to be able to drag the window by it. This is my current window (see the toolbar on the top):
And this is my current code to make it draggable:
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
if(hit == HTCLIENT) hit = HTCAPTION;
return hit;
}
break;
You are on the right track with hooking WM_NCHITTEST. Now, you need to make change what constitutes a client hit versus a caption hit. If I understand your code right now, anywhere you click within the client area of the window (everything but the border) will allow you to drag the window elsewhere. This will make interacting with your application very difficult. Instead, you should be returning HTCAPTION only after you have determined that the hit was within the menubar area. Specifically, the area of the menubar that does not hold the File/Edit/Help buttons.
case WM_NCHITTEST: {
LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
if (hit == HTCLIENT) { // The hit was somewhere in the client area. Don't know where yet.
// Perform your test for whether the hit was in the region you would like to intercept as a move and set hit only when it is.
// You will have to pay particular attention to whether the user is actually clicking on File/Edit/Help and take care not to intercept this case.
// hit = HTCAPTION;
}
return hit;
break;
}
Some things to keep in mind here:
This can be very confusing to a user that wants to minimize, close, or move your application. Menubars do not convey to the user that you can move the window by dragging them.
If you are concerned with vertical pixels you may consider doing what other applications on Windows are starting to do -- moving the menubar functionality to a single button that is drawn in the titlebar. (See recent versions of Firefox/Opera or Windows explorer in Windows 8 for some idea to move things to the titlebar.
In one of my applications I also wanted to make the window what I call "client area draggable". Unfortunately the mentioned solution (replacing HTCLIENT with HTCAPTION)
does have a serious flaws:
Double-clicking in the client area now shows the same behaviour as
double-clicking the caption (i.e. minimizing/maximizing the window)!
To solve this I did the following in my message handler (excerpt):
case WM_MOUSEMOVE:
// Move window if we are dragging it
if (mIsDragging) // variable: bool mIsDragging;
{
POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
mIsDragging = (ClientToScreen(hWnd, &mousePos) &&
SetWindowPos(hWnd,
NULL,
mDragOrigin.left + mousePos.x - mDragPos.x,
mDragOrigin.top + mousePos.y - mDragPos.y,
0,
0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE));
}
break;
case WM_LBUTTONDOWN:
// Check if we are dragging and safe current cursor position in case
if (wParam == MK_LBUTTON)
{
POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
if (ClientToScreen(hWnd, &mousePos) &&
DragDetect(hWnd, mousePos))
{
// Check if the cursor is pointing to your new caption here!!!!
mIsDragging = true;
mDragPos = mousePos;
GetWindowRect(hWnd, &mDragOrigin);
SetCapture(hWnd);
}
}
break;
// Remove this case when ESC key handling not necessary
case WM_KEYDOWN:
// Restore original window position if ESC is pressed and dragging active
if (!mIsDragging || wParam != VK_ESCAPE)
{
break;
}
// ESC key AND dragging... we restore original position of window
// and fall through to WM_LBUTTONUP as if mouse button was released
// (i.o.w. NO break;)
SetWindowPos(hWnd, NULL, mDragOrigin.left, mDragOrigin.top, 0, 0,
SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
case WM_LBUTTONUP:
ReleaseCapture();
break;
case WM_CAPTURECHANGED:
mIsDragging = false;
break;
The (pseudo) code omits the return values (default: 0) and variable definitions but
should make the procedure clear anyway!? (If not drop me a line and I'll add more
or all code).
ps: I just found another comprehensive description which also explains the differences
of these two solutions: http://tinyurl.com/bqtyt3q