brokkster Ответов: 1

Как сделать так, чтобы элемент управления listbox, расположенный в немодальном диалоговом окне, реагировал на нажатия клавиш.


Я бы просто хотел, чтобы элемент управления ListBox, расположенный в Немодальном диалоговом окне, реагировал на нажатия клавиш. например: сначала нужно нажать на элемент в списке, а затем нажать клавишу Delete, чтобы удалить его из списка.

Я обнаружил, что пустое диалоговое окно отвечает через WM_KEYDOWN. Но когда я помещаю список в диалог. Тот же WM_KEYDOWN не обрабатывается. Затем я прочитал, что фокус установлен на элемент управления в диалоговом окне. Затем я натыкаюсь на WM_GETDLGCODE и считаю, что это ключ к решению моей проблемы. Но я так и не смог этого понять.

Я тоже буду продолжать читать.

-Скотт

Что я уже пробовал:

#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;
}

1 Ответов

Рейтинг:
5

enhzflep

Вы можете сделать это, подклассировав сам элемент управления. Таким образом, вы получаете доступ к сообщениям WM_KEYUP, которые он получает, и, таким образом, можете видеть, когда он получает VK_DELETE

Во-первых, вы определите функцию в качестве окна-прок для управления, рядом подкласс элемента управления.

Стоит отметить, что ваш код крадет фокус из элемента управления, когда вы показываете окно сообщения, отображающее только что выбранный элемент. Это означает, что вы щелкаете по элементу, появляется окно сообщения, вы закрываете окно и нажимаете удалить, но ничего не происходит. Исправление состоит в том, чтобы либо (0) не показывать окно сообщения, либо (1) вручную (то есть в коде) установить фокус обратно на элемент управления после того, как окно сообщения будет отклонено, либо (2) нажать на пустую часть элемента управления перед нажатием кнопки Удалить.

Вот очень грубая функция подкласса:

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);
}



И вот как вы устанавливаете контроль, чтобы использовать его:

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;



Вам нужно будет включить < commctrl.h> и убедиться, что выполнено следующее условие (прежде чем включать его)
#if (_WIN32_WINNT >= 0x0501)


brokkster

Большое вам спасибо за объяснение. Я собираюсь немного повеселиться с этим!
У меня есть еще один вопрос, если вы не возражаете.
Где WM_GETDLGCODE вступает в игру? Я удалил его из своей программы, и он работает.

enhzflep

Всегда пожалуйста, буду рад помочь.
Я помню, что использовал эту функцию только тогда, когда пытался смоделировать диалог с помощью стандартного фреймового окна. В основном он обрабатывает такие вещи, как кнопка tab, чтобы сфокусировать следующий/предыдущий элемент управления в диалоговом окне.
Подробнее об этом вы можете прочитать здесь: Сообщение WM_GETDLGCODE