Subclassing winapi - Enter v editboxu – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Subclassing winapi - Enter v editboxu – C / C++ – Fórum – Programujte.comSubclassing winapi - Enter v editboxu – C / C++ – Fórum – Programujte.com

 

Toto vlákno bylo označeno za vyřešené.
ProXicT0
Návštěvník
21. 11. 2013   #1
-
0
-

Zdravím, snažím se zachytit klávesu enter, když má editbox focus. Strýček google napovídá subclassing, se kterým nemám žádné zkušenosti, takže vůbec netuším, jak by to mohlo fungovat. Snad mi někdo z vás poradí ;-)

Předem díky :)

Tady je můj kód:

#include <windows.h>
#include <winuser.h>

HDC hdc;
HWND edit;
HWND edit2;
#define ID_TEXTBOX						105

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow);

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
		case WM_DESTROY:
		{
			PostQuitMessage(0);
		}
		break;

		case WM_CLOSE:
		{
			DestroyWindow(hwnd);
		}
		break;

		case WM_CREATE:
		{
			edit = CreateWindow(
				TEXT("EDIT"),
				TEXT(""),
				WS_VISIBLE | WS_CHILD | WS_BORDER,
				5, 5,
				200, 20,
				hwnd,
				(HMENU)ID_TEXTBOX,
				NULL,
				NULL,
				);

			edit2 = CreateWindow(
				TEXT("EDIT"),
				TEXT(""),
				WS_VISIBLE | WS_CHILD | WS_BORDER,
				5, 30,
				200, 20,
				hwnd,
				(HMENU)ID_TEXTBOX,
				NULL,
				NULL,
				);
		}
		break;

		case WM_LBUTTONDOWN:
		{
			SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
			SetFocus(hwnd);
		}
		break;

		case WM_KEYDOWN:
		{
			if(GetKeyState(VK_RETURN))
			{
				char buffer[255];
				SendMessage(edit, WM_GETTEXT, 255, LPARAM(buffer));
				SendMessage(edit2, WM_SETTEXT, NULL, (LPARAM)buffer);
			}
		}
	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	TCHAR CLASS_NAME[] = TEXT("Title");
	WNDCLASSEX wc = {};

	wc.cbSize = sizeof(wc);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = CLASS_NAME;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = NULL;
	wc.hIconSm = NULL;
	wc.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(255, 255, 255));
	wc.lpszMenuName = NULL;

	RegisterClassEx(&wc);

	HWND hwnd = CreateWindowEx
		(
		NULL,
		CLASS_NAME,
		CLASS_NAME,
		WS_OVERLAPPED | WS_SYSMENU,

		640,
		300,
		640,
		480,

		NULL,
		NULL,
		hInstance,
		NULL);

	if(!hwnd)
	{
		return FALSE;
	}
	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);
	MSG msg;

	while(GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
Nahlásit jako SPAM
IP: 77.240.98.–
Radek Chalupa
~ Redaktor
+1
Super člen
22. 11. 2013   #2
-
0
-

#1 ProXicT
Subclassing znamená, že si přesměruješ "na sebe" proceduru okna příslušného ovl. prvku, a v té musíš chytat zprávy které dostává ten edit a nikoliv jeho rodičovské okno.

Tady je příklad: http://www.radekchalupa.cz/clanky/?kod=205&obsah=20

PS: V obsluze WM_CLOSE nemá volání DestroyWindow co dělat, okno se zruší následně samo a DestroyWindow slouží k tomu pokud chceš okno zrušit "ručně" někde z kódu. Obsluha WM_CLOSE slouží k tomu, že máš možnost vrácením 0 zrušit vyvolané zavření okna (např. běžný dotaz "chcete uložit soubor")

Radek Chalupa 
- vývoj software na zakázku 
- školení programování (C/C++, WinAPI, ATL, COM, ActiveX, C#, NET Framework, MFC) 
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
ProXicT0
Návštěvník
22. 11. 2013   #3
-
0
-

#2 Radek Chalupa
Díky za odpověď. Zkoušel jsem to, co je v příkladu a stále nic. Nevím kde mám chybu. 

Zde je můj kód: 

#include <windows.h>
#include <winuser.h>

HDC hdc;
HWND edit;
HWND edit2;
HINSTANCE hInstance;
#define ID_TEXTBOX						105
#define ID_TEXTBOX2						106

WNDPROC oldProc;
LRESULT CALLBACK WindowProcEdit(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow);

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
		case WM_DESTROY:
		{
			PostQuitMessage(0);
		}
		break;

		case WM_CLOSE:
		{
			DestroyWindow(hwnd);
		}
		break;

		case WM_CREATE:
		{
			edit = CreateWindow(
				TEXT("EDIT"),
				TEXT(""),
				WS_VISIBLE | WS_CHILD | WS_BORDER,
				5, 5,
				200, 20,
				hwnd,
				(HMENU)ID_TEXTBOX,
				NULL,
				NULL,
				);

			edit2 = CreateWindow(
				TEXT("EDIT"),
				TEXT(""),
				WS_VISIBLE | WS_CHILD | WS_BORDER,
				5, 30,
				200, 20,
				hwnd,
				(HMENU)ID_TEXTBOX2,
				NULL,
				NULL,
				);
		}
		break;

		case WM_LBUTTONDOWN:
		{
			SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
			SetFocus(hwnd);
		}
		break;

		case WM_KEYDOWN:
		{
			if(GetKeyState(VK_RETURN))
			{
				char buffer[255];
				SendMessage(edit, WM_GETTEXT, 255, LPARAM(buffer));
				SendMessage(edit2, WM_SETTEXT, NULL, (LPARAM)buffer);
			}
		}
		break;

		case WM_INITDIALOG:
			SetClassLongPtr(hwnd, GCLP_HICONSM, (LONG_PTR)LoadIcon(hInstance, MAKEINTRESOURCE(NULL)));
			oldProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwnd, ID_TEXTBOX), GWLP_WNDPROC, (LONG_PTR)WindowProcEdit);
			oldProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwnd, ID_TEXTBOX2), GWLP_WNDPROC, (LONG_PTR)WindowProcEdit);
			break;
	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

#define UM_KEY_IN_CONTROL ( WM_APP + 1 )
LRESULT CALLBACK WindowProcEdit(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_GETDLGCODE:
		return DLGC_WANTALLKEYS;
	case WM_KEYDOWN:
		if(GetKeyState(VK_RETURN)) MessageBox(hwnd, "awdaw", "awdhaw", MB_OK);
		break;
	}
	return CallWindowProc(oldProc, hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	TCHAR CLASS_NAME[] = TEXT("Title");
	WNDCLASSEX wc = {};

	wc.cbSize = sizeof(wc);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = CLASS_NAME;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = NULL;
	wc.hIconSm = NULL;
	wc.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(255, 255, 255));
	wc.lpszMenuName = NULL;

	RegisterClassEx(&wc);

	HWND hwnd = CreateWindowEx
		(
		NULL,
		CLASS_NAME,
		CLASS_NAME,
		WS_OVERLAPPED | WS_SYSMENU,

		640,
		300,
		640,
		480,

		NULL,
		NULL,
		hInstance,
		NULL);

	if(!hwnd)
	{
		return FALSE;
	}
	ShowWindow(hwnd, iCmdShow);
	UpdateWindow(hwnd);
	MSG msg;

	while(GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
Nahlásit jako SPAM
IP: 77.240.98.–
Radek Chalupa
~ Redaktor
+1
Super člen
22. 11. 2013   #4
-
0
-

#1 ProXicT

Na první náhled tam vidím 2 chyby:

1. WM_INITDIALOG ti do klasického okna nepřijde, takže to nastavení musíš dát do WM_CREATE poté co vytvoříš ten edit.

2. V WM_KEYDOWN otestuj wparam, v okamžiku zpracování zprávu už nemusí být klávesa stlačená.

Radek Chalupa 
- vývoj software na zakázku 
- školení programování (C/C++, WinAPI, ATL, COM, ActiveX, C#, NET Framework, MFC) 
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
ProXicT0
Návštěvník
22. 11. 2013   #5
-
0
-

#4 Radek Chalupa
Obecně moc nerozumím tomu subclassing. Mohl byste mi prosím poslat alespoň část toho, jak to má ve finále vypadat? Předem díky.

Nahlásit jako SPAM
IP: 77.240.98.–
Radek Chalupa
~ Redaktor
+1
Super člen
23. 11. 2013   #6
-
0
-

#5 ProXicT
Tady je fungující kód na zachycení enteru, nic složitého v tom není, jen to chce si přečíst něco málo teorie o WinAPI a jak fungují aplikace ve Windows. 

#define _TRIDA L"SubclassTest"

HWND _hwnd = NULL;
HWND _hwnd_edit = NULL;
WNDPROC _wndproc_orig = NULL;

LRESULT CALLBACK window_proc_edit(HWND hwnd, UINT zprava, WPARAM wparam, LPARAM lparam)
{
	switch (zprava)
	{
	case WM_KEYDOWN:
		if (wparam == VK_RETURN)
			MessageBox(_hwnd, L"Return", L"Test", MB_ICONINFORMATION);
		break;
	}
	return CallWindowProc(_wndproc_orig, hwnd, zprava, wparam, lparam);
}

LRESULT CALLBACK window_proc(HWND hwnd, UINT zprava, WPARAM wparam, LPARAM lparam)
{
	switch (zprava)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hwnd, zprava, wparam, lparam);
}


int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int)
{
	MSG msg;
	WNDCLASSEX wc;
	ZeroMemory(&wc, sizeof(wc));
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.lpfnWndProc = window_proc;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
	wc.lpszClassName = _TRIDA;
	if (!RegisterClassEx(&wc))
		return 1;

	_hwnd = CreateWindowEx(0, _TRIDA, L"Subclassing", WS_OVERLAPPEDWINDOW, 150, 100, 640, 480, NULL, NULL, hInstance, NULL);
	if (_hwnd == NULL)
		return 1;
	_hwnd_edit = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, L"Edit", WS_CHILD | WS_VISIBLE, 10, 10, 200, 30, _hwnd, (HMENU)1, hInstance, NULL);
	if (_hwnd_edit == NULL)
		return 1;
	_wndproc_orig = (WNDPROC)SetWindowLongPtr(_hwnd_edit, GWLP_WNDPROC, (LONG_PTR)window_proc_edit);
	if (_wndproc_orig == NULL)
		return 1;
	ShowWindow(_hwnd, SW_SHOW);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return (int) msg.wParam;
}

Radek Chalupa 
- vývoj software na zakázku 
- školení programování (C/C++, WinAPI, ATL, COM, ActiveX, C#, NET Framework, MFC) 
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
ProXicT0
Návštěvník
23. 11. 2013   #7
-
0
-

#6 Radek Chalupa
Super! Díky moc, snad už tomu z části rozumím. Jediná věc, co mě teď trápí je, že pokaždé když stisknu enter, tak se ozve MessageBeep(0xFFFFFFFF); a netuším, jak se toho zbavit. Zkoušel jsem dát do té podmínky když se stiskne enter "MessageBeep(NULL);", ale zvuk se pouze opozdí a přehraje se. Nevěděl byste, co s tím?

Nahlásit jako SPAM
IP: 77.240.98.–
Radek Chalupa
~ Redaktor
+1
Super člen
24. 11. 2013   #8
-
0
-

#7 ProXicT
Ten zvuk je vlastnost systému při výchozím zpracování té klávesy. Podobně jako např. zvuk při kliknutí na odkaz. Musel bys změnit nastavení zvuků v systému (je to někde v registru) nebo si ten edit napsat kompletně ve vlastní režii a především ty klávesové zprávy nepouštět do výchozího zpracování (tj. CallWindowProc) ale udělat sám vše potřebné, což je už je trochu práce...

Radek Chalupa 
- vývoj software na zakázku 
- školení programování (C/C++, WinAPI, ATL, COM, ActiveX, C#, NET Framework, MFC) 
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
ProXicT0
Návštěvník
24. 11. 2013   #9
-
0
-

#8 Radek Chalupa
Tak na konec jsem to vyřešil takto:
 

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	sCreateWindow(TEXT("Red Zone"), 0, 0, 0, WS_POPUP | DS_CENTER);
	
	if (!hwnd)
   {
      return FALSE;
   }

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
   
	while(GetMessage(&msg, NULL, 0, 0))
	{
		if(msg.message == WM_KEYDOWN && msg.wParam == VK_RETURN && GetFocus() == edit2)
		{
			MessageBox(hwnd, "Enter!", "Info:", MB_OK);
			continue;
		}
		if(msg.message == WM_KEYDOWN && msg.wParam == VK_RETURN && GetFocus() == button1)
		{
			MessageBox(hwnd, "Enter!", "Info:", MB_OK);
			continue;
		}
		if(msg.message == WM_KEYDOWN && msg.wParam == VK_TAB && GetFocus() == edit)
		{
			SetFocus(edit2);
			continue;
		}
		if(msg.message == WM_KEYDOWN && msg.wParam == VK_TAB && GetFocus() == edit2)
		{
			SetFocus(button1);
			continue;
		}
		if(msg.message == WM_KEYDOWN && msg.wParam == VK_TAB && GetFocus() == button1)
		{
			SetFocus(edit);
			continue;
		}
		
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
    return msg.wParam;
}

Žádný zvuk to nedělá a funguje to tak, jak má :)

Nahlásit jako SPAM
IP: 77.240.98.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 78 hostů

Podobná vlákna

Enter v editboxu — založil Tom9k

Enter — založil Ondřej Šplíchal

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý