C++ , Api win32 e Finestre

mercoledì 09 luglio 2008 - 12.38

luigidibiasi Profilo | Guru

Salve, spero che qualcuno mi possa essere utile : (scusate la lunghezza...)

Sto utilizzando Visual C++ 2008 ed ho importato l'header <windows.h>, non sto utilizzando un progetto di
tipo "applicazione win32" bensì applicazione console win32.

Ho utilizzato le api di windows per crearmi la finestra principale :

- ho registrato la mia classe ( ho usato la struttura WNDCLASSEX ).
- ho scritto la windows procedure ( nella funzione richiamo direttamente la DefWinProc perchè non mi interessa gestire i messaggi qui.)
- ho usato la CreateWindowEx per crearmi l'istanza della classe.
- ho mostrato la finestra a video e sono entrato in un ciclo di GetMessage

Fin qui tutto ok .. i messaggi dalla coda mi arrivano, chiamo DispathMessage e la windows procedure me li rileva correttamente.

Addesso ho la necessita di aggiungere 2 controlli di tipo button alla finestra principale.
Mi definisco due variabili in questo modo:

HWND button1;
HWND button2;

button1 = CreateWindowEx(NULL,L"Button",L"Button1",WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,20,20,100,40,mainWinHwnd,(HMENU) NULL,hInst,(void **) NULL);

button2 = CreateWindowEx(NULL,L"Button",L"Button2",BS_CHECKBOX|BS_NOTIFY|WS_VISIBLE|WS_CHILDWINDOW,20,70,100,40,mainWinHwnd,(HMENU) NULL,hInst,(void **) NULL);

Come argomento hwndParent gli passo il riferimento alla finestra creata prima e come argomento HISTANCE gli passo l'istanza della finestra principale.

Il problema nasce qui.... da MSDN leggo che quando avviene un evento sui controlli, tale evento dovrebbe essere notificato alla finestra padre sotto forma di messaggio WM_COMMAND o WM_NOTIFY e poi nei lParam e wParam dovrei andare a leggere quello che mi serve per gestirmelo.

In questo caso al pulsante dovrebbero arrivare WM_LBUTTONUP e WM_LBUTTONDOWN mentre dovrebbe arrivarmi un WM_COMMAND nella finestra principale.

Il ciclo che uso per leggere i messaggi è il seguente:


MSG msg;
while((GetMessage(&msg,NULL,0,0)))
{
// questo lo rielva
if(msg.hwnd==button1&&msg.message==WM_LBUTTONUP)
printf("\n mouse click\n");

TranslateMessage(&msg);
DispatchMessage(&msg);
switch(msg.message)
{
case WM_PAINT:printf("\n painting\n");break;
case WM_LBUTTONUP:printf("\n notify!\n");break;
case WM_COMMAND:printf("\n command\n");break;
}

}

Non ho passato nessun HWND come argomento quindi mi rileva tutti i messaggi compresi quelli che arrivano ai controlli ( msg.hwnd==button1). ( ma non voglio gestirmi a mano WMUP e DOWN, voglio gestire tutto tramiet BM_CLICK!!!!!)

Il problema è che non mi arriva mai WM_COMMAND o WM_NOTIFY.

Come mai?!?




Luigi Di Biasi

aiedail92 Profilo | Expert

Ciao

Secondo me è sbagliata l'impostazione del programma: i messaggi non vanno analizzati all'interno del message loop, ma all'interno del WndProc associato alla classe della finestra. Devi fare quindi una cosa di questo genere:

//il message loop: while(GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } //La WndProc associata alla finestra LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_PAINT: //-- necessario altrimenti il messaggio //continua ad essere chiamato -- PAINTSTRUCT ps; BeginPaint(hwnd, &ps); EndPaint(hwnd, &ps); //-- -- printf("painting\r\n"); break; //Command case WM_COMMAND: //Comando inviato da un child control if(lParam != 0) { //LOWORD(wParam) è l'identificatore del child control //cioè il valore che passi a CreateWindow come HMENU //per identificare i diversi controlli dai diversi valori //nella chiamata a CreateWindow switch(HIWORD(wParam)) { case BN_CLICKED: printf("A Button was clicked! The button id is %i\r\n", LOWORD(wParam)); break; } } //Comando generato da un Menu o un Acceleratore else { switch(HIWORD(wParam)) { case 0: //Menu //LOWORD(wParam) è l'identificatore del menu break; case 1: //Accelerator //LOWORD(wParam) è l'identificatore dell'acceleratore break; } } break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; }

Per riconoscere i bottoni uno dall'altro quando ricevi il WM_COMMAND devi dare diversi identificatori ai bottoni. L'identificatore viene assegnato al controllo (per i child controls) quando crei il controllo con CreateWindow. Il numero di identificazione è il parametro hMenu, che deve essere un valore intero castato su HMENU.

Se non sono stato chiaro chiedi di nuovo

Luca

luigidibiasi Profilo | Guru

Si, dalla window procedure ci riesco ma il mio intendo era prelevare il wm_command dal ciclo che usa getMessage.

Comunque credo non sia possibile perchè forse wm_command non và nella coda dei messaggi ma viene passato direttamente alla win proc.

Non ho ben capito però l'utilizzo che fai del parametro HMENU... puoi spiegarmelo meglio per favore?

Ipotizziamo di essere nella windows procedure:
Io per gestire i controlli mi mantenevo un riferimento HWND e poi facevo il test sul parametro hwnd che mi arriva quando viene richiamata la funzione... Utilizzando il parametro HMENU ti indicizzi i controlli o cosa?



Luigi Di Biasi

luigidibiasi Profilo | Guru

Ok.. ho risolto.... dalla dentro la win proc l'hwnd che mi arriva e della finestra perchè il messaggio è wm_command... da dento il ciclo invece l'hwnd era proprio dei tasti perchè recuperavo i messaggi diretti a loro....

Grazie per l'aiuto
Luigi Di Biasi

aiedail92 Profilo | Expert

In pratica quando chiami CreateWindow (o CreateWindowEx) per creare un Child Control, il valore del parametro hMenu non serve per identificare un menu (i child controls non ce l'hanno) ma per attribuire un identificatore univoco al controllo in modo che possa essere trovato fra tutti i child controls della finestra.

Se tu crei due controlli così:

HWND child1 = CreateWindow("Button", "Child1", WS_CHILD, x, y, w, h, hwnd, (HMENU)1, NULL, 0);
HWND child2 = CreateWindow("Button", "Child2", WS_CHILD, x, y, w, h, hwnd, (HMENU)2, NULL, 0);

Quando ricevi il messaggio WM_COMMAND, se è stato generato dal primo controllo, LOWORD(wParam) vale 1 (infatti avevamo usato (HMENU)1) se invece è stato generato dal secondo, vale 2. In questo modo si può controllare quale dei due pulstanti è stato premuto.

Puoi verificare qui le specifiche del messaggio WM_COMMAND:
http://msdn.microsoft.com/en-us/library/ms647591(VS.85).aspx

Luca

aiedail92 Profilo | Expert

Sono felice che tu abbia risolto

Luca
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5