Click here to Skip to main content
15,888,351 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I would simply like to make a ListBox control, located on a Modeless dialog box, respond to key strokes. for example: one would first click on an item in the list and then press the Delete key to remove it from the list.

I have discovered that a blank dialog box responds via a WM_KEYDOWN. But when I place a ListBox on the dialog. The same WM_KEYDOWN is not processed. I then read that focus is set to a control on the dialog box. ok. I then come across WM_GETDLGCODE and I believe this my be the key to solving my problem. But I have not been able to figure it out.

I will keep reading too.

-Scott

What I have tried:

C++
#include <windows.h>
#include <shobjidl.h>
#include <string>
#include <fstream>
#include <stdio.h>
#include "resource.h"
#include <sstream>

using namespace std;

// Dialog handle
HWND ghListDlg = 0;

// Combobox dialog window procedure
BOOL CALLBACK listDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	// Text buffer to be filled with string user entered into edit control
	wchar_t msgText[256] = L"";

	// Handles to the combo box controls
	static HWND hListBox = 0;
	static HWND hEditBox = 0;
	static HWND hAddButton = 0;

	int index = 0;

	switch (msg)
	{

	case WM_GETDLGCODE:
		MessageBox(0, L"WM_GETDLGCODE recieved", L"ListBox Message", MB_OK);
		return DLGC_WANTALLKEYS;

	case WM_ACTIVATE:
		if (0 == wParam)             // becoming inactive
		{
		}
		else                         // becoming active
		{
			ghListDlg = hDlg;
		}
		return true;

	case WM_INITDIALOG:
		// Controls are child windows to the dialog they lie on. In order to get and send information to and from a control
		// we will need a handle to it. So save a handle to the controls as the dialog is being initialized.
		// Recall that we get a handle to a child control on a dialog box with the GetDlgItem
		hListBox = GetDlgItem(hDlg, IDC_LISTBOX);
		hEditBox = GetDlgItem(hDlg, IDC_EDIT_MSG);
		hAddButton = GetDlgItem(hDlg, IDC_ADDBUTTON);

		return true;

	case WM_COMMAND:
		switch (HIWORD(wParam))
		{
			//User selected a combo box item
		case LBN_SELCHANGE:
			index = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
			SendMessage(hListBox, LB_GETTEXT, (WPARAM)index, (LPARAM)msgText);
			MessageBox(0, msgText, L"ListBox Message", MB_OK);
			return true;
		}
		switch (LOWORD(wParam))
		{
			// User pressed the "Add" button
		case IDC_ADDBUTTON:
			// Get the text from the edit box
			GetWindowText(hEditBox, msgText, 256);

			// Add the text to the combo box only if the user entered a string greater than zero
			if (wcslen(msgText) > 0)
				SendMessage(hListBox, LB_ADDSTRING, 0, (LPARAM)msgText);
			return true;
		}

		return true;

	case WM_CLOSE:
		DestroyWindow(hDlg);
		return true;

	case WM_DESTROY:
		PostQuitMessage(0);
		return true;

	}
	return false;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR cmdLine, int showCmd)
{
	// Create the modeless dialog window. This program is a pure dialog window application, and the
	//dialog window application, and the dialog window is the "main" window.

	// Create the modless dialog window
	ghListDlg = CreateDialog(
		hInstance, // Application instance
		MAKEINTRESOURCE(IDD_LISTDLG), // Dialog resource ID
		0, // Parent window--null for no parent
		listDlgProc); // Dialog window procedure

	// Show the list button dialog
	ShowWindow(ghListDlg, showCmd);

	// Enter the message loop
	MSG msg;
	ZeroMemory(&msg, sizeof(MSG));

	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (NULL == ghListDlg || !IsDialogMessage(ghListDlg, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int)msg.wParam;
}
Posted
Updated 26-Nov-16 16:03pm
v2

1 solution

You can do this by sub-classing the control itself. This way, you get access to the WM_KEYUP messages it receives and thus, can see when it receives a VK_DELETE

First, you define a function to act as a window-proc for the control, next you subclass the control.

It's worth pointing out that your code steals focus from the control when you show a message-box displaying the item that was just selected. This means you click an item, a message-box is shown, you dismiss the box and hit delete, yet nothing happens. The fix is to either (0) Not show the message box, (1) manually (i.e in code) set the focus back to the control after the message box is dismissed or (2) click on an empty portion of the control before you hit the delete button.

Here's a very rough subclass function:

C++
LRESULT CALLBACK myListBoxSubclassProc(HWND hWnd,
                                UINT uMsg,
                                WPARAM wParam,
                                LPARAM lParam,
                                UINT_PTR uIdSubclass,
                                DWORD_PTR dwRefData)
{
    switch (uMsg)
    {
        case WM_KEYUP:
            if (wParam == VK_DELETE)
            {
                int selectedIndex = SendMessage(hWnd, LB_GETCURSEL,0,0);
                SendMessage(hWnd, LB_DELETESTRING, selectedIndex, 0);
                MessageBeep(MB_OK);
            }
            break;
    }
    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}



And here's how you set the control to use it:

C++
case WM_INITDIALOG:
    // Controls are child windows to the dialog they lie on. In order to get and send information to and from a control
    // we will need a handle to it. So save a handle to the controls as the dialog is being initialized.
    // Recall that we get a handle to a child control on a dialog box with the GetDlgItem
    hListBox = GetDlgItem(hDlg, IDC_LISTBOX);
    hEditBox = GetDlgItem(hDlg, IDC_EDIT_MSG);
    hAddButton = GetDlgItem(hDlg, IDC_ADDBUTTON);

    SetWindowSubclass(hListBox, myListBoxSubclassProc, 0, 0);

    return true;



You'll need to include <commctrl.h> and ensure that the following condition is met (before including it)
#if (_WIN32_WINNT >= 0x0501)
 
Share this answer
 
Comments
brokkster 27-Nov-16 11:49am    
Thank you so very much for your explanation. I'm gonna have some fun with this!
I have a one follow up question, if you don't mind.
Where does WM_GETDLGCODE come into play? I removed it from my program and it works.
enhzflep 27-Nov-16 22:16pm    
You're welcome, happy to help.
Only time I recall making use of the function is when I'm trying to simulate a dialog using a standard frame window. Basically, it handles things like the tab-button to focus the next/prev control in a dialog.
You can read more about it here: WM_GETDLGCODE message

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900