Uso di Windows
Gli esempi in questa sezione descrivono come eseguire le attività seguenti:
- Creazione di una finestra principale
- Creazione, enumerazione e ridimensionamento di Finestre figlio
- Eliminazione di una finestra
- Uso di finestre a più livelli
Creazione di una finestra principale
La prima finestra creata da un'applicazione è in genere la finestra principale. Per creare la finestra principale, usare la funzione CreateWindowEx , specificando la classe della finestra, il nome della finestra, gli stili della finestra, le dimensioni, la posizione, l'handle di menu, l'handle di istanza e i dati di creazione. Una finestra principale appartiene a una classe di finestra definita dall'applicazione, pertanto è necessario registrare la classe window e fornire una routine finestra per la classe prima di creare la finestra principale.
La maggior parte delle applicazioni usa in genere lo stile WS_OVERLAPPEDWINDOW per creare la finestra principale. Questo stile offre alla finestra una barra del titolo, un menu finestra, un bordo di ridimensionamento e pulsanti per ridurre al minimo e ingrandire i pulsanti. La funzione CreateWindowEx restituisce un handle che identifica in modo univoco la finestra.
Nell'esempio seguente viene creata una finestra principale appartenente a una classe finestra definita dall'applicazione. Il nome della finestra principale verrà visualizzato nella barra del titolo della finestra. Combinando gli stili WS_VSCROLL e WS_HSCROLL con lo stile WS_OVERLAPPEDWINDOW, l'applicazione crea una finestra principale con barre di scorrimento orizzontali e verticali oltre ai componenti forniti dallo stile WS_OVERLAPPEDWINDOW. Le quattro occorrenze della costante CW_U edizione Standard DEFAULT impostano le dimensioni iniziali e la posizione della finestra sui valori predefiniti definiti dal sistema. Specificando NULL anziché un handle di menu, la finestra avrà il menu definito per la classe della finestra.
HINSTANCE hinst;
HWND hwndMain;
// Create the main window.
hwndMain = CreateWindowEx(
0, // no extended styles
"MainWClass", // class name
"Main Window", // window name
WS_OVERLAPPEDWINDOW | // overlapped window
WS_HSCROLL | // horizontal scroll bar
WS_VSCROLL, // vertical scroll bar
CW_USEDEFAULT, // default horizontal position
CW_USEDEFAULT, // default vertical position
CW_USEDEFAULT, // default width
CW_USEDEFAULT, // default height
(HWND) NULL, // no parent or owner window
(HMENU) NULL, // class menu used
hinst, // instance handle
NULL); // no window creation data
if (!hwndMain)
return FALSE;
// Show the window using the flag specified by the program
// that started the application, and send the application
// a WM_PAINT message.
ShowWindow(hwndMain, SW_SHOWDEFAULT);
UpdateWindow(hwndMain);
Si noti che l'esempio precedente chiama la funzione ShowWindow dopo aver creato la finestra principale. Questa operazione viene eseguita perché il sistema non visualizza automaticamente la finestra principale dopo la creazione. Passando il flag SW_SHOWDEFAULT a ShowWindow, l'applicazione consente al programma che ha avviato l'applicazione di impostare lo stato di visualizzazione iniziale della finestra principale. La funzione UpdateWindow invia la finestra il primo messaggio WM_PAINT .
Creazione, enumerazione e ridimensionamento di Finestre figlio
È possibile dividere l'area client di una finestra in aree funzionali diverse usando finestre figlio. La creazione di una finestra figlio è simile alla creazione di una finestra principale, che consente di usare la funzione CreateWindowEx. Per creare una finestra di una classe finestra definita dall'applicazione, è necessario registrare la classe window e fornire una routine finestra prima di creare la finestra figlio. È necessario assegnare alla finestra figlio lo stile di WS_CHILD e specificare una finestra padre per la finestra figlio al momento della creazione.
L'esempio seguente divide l'area client della finestra principale di un'applicazione in tre aree funzionali creando tre finestre figlio di dimensioni uguali. Ogni finestra figlio è la stessa altezza dell'area client della finestra principale, ma ognuno è di un terzo della larghezza. La finestra principale crea le finestre figlio in risposta al messaggio di WM_CREATE , che la finestra principale riceve durante il proprio processo di creazione della finestra. Poiché ogni finestra figlio ha lo stile WS_BORDER , ognuno ha un bordo linea sottile. Inoltre, poiché lo stile WS_VISIBLE non è specificato, ogni finestra figlio viene inizialmente nascosta. Si noti anche che a ogni finestra figlio viene assegnato un identificatore di finestra figlio.
Le dimensioni della finestra principale e posizionano le finestre figlio in risposta al messaggio di WM_SIZE , che la finestra principale riceve quando le dimensioni cambiano. In risposta a WM_SIZE, la finestra principale recupera le dimensioni dell'area client usando la funzione GetClientRect e quindi passa le dimensioni alla funzione EnumChildWindows. EnumChildWindows passa l'handle a ogni finestra figlio, a sua volta, alla funzione di callback EnumChildProc definita dall'applicazione. Questa funzione ridimensiona e posiziona ogni finestra figlio chiamando la funzione MoveWindow . Le dimensioni e la posizione sono basate sulle dimensioni dell'area client della finestra principale e sull'identificatore della finestra figlio. Successivamente, EnumChildProc chiama la funzione ShowWindow per rendere visibile la finestra.
#define ID_FIRSTCHILD 100
#define ID_SECONDCHILD 101
#define ID_THIRDCHILD 102
LONG APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
RECT rcClient;
int i;
switch(uMsg)
{
case WM_CREATE: // creating main window
// Create three invisible child windows.
for (i = 0; i < 3; i++)
{
CreateWindowEx(0,
"ChildWClass",
(LPCTSTR) NULL,
WS_CHILD | WS_BORDER,
0,0,0,0,
hwnd,
(HMENU) (int) (ID_FIRSTCHILD + i),
hinst,
NULL);
}
return 0;
case WM_SIZE: // main window changed size
// Get the dimensions of the main window's client
// area, and enumerate the child windows. Pass the
// dimensions to the child windows during enumeration.
GetClientRect(hwnd, &rcClient);
EnumChildWindows(hwnd, EnumChildProc, (LPARAM) &rcClient);
return 0;
// Process other messages.
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam)
{
LPRECT rcParent;
int i, idChild;
// Retrieve the child-window identifier. Use it to set the
// position of the child window.
idChild = GetWindowLong(hwndChild, GWL_ID);
if (idChild == ID_FIRSTCHILD)
i = 0;
else if (idChild == ID_SECONDCHILD)
i = 1;
else
i = 2;
// Size and position the child window.
rcParent = (LPRECT) lParam;
MoveWindow(hwndChild,
(rcParent->right / 3) * i,
0,
rcParent->right / 3,
rcParent->bottom,
TRUE);
// Make sure the child window is visible.
ShowWindow(hwndChild, SW_SHOW);
return TRUE;
}
Eliminazione di una finestra
È possibile usare la funzione DestroyWindow per eliminare definitivamente una finestra. In genere, un'applicazione invia il messaggio di WM_CLO edizione Standard prima di eliminare una finestra, dando alla finestra la possibilità di richiedere conferma all'utente prima che la finestra venga eliminata definitivamente. Una finestra che include un menu finestra riceve automaticamente il messaggio WM_CLO edizione Standard quando l'utente fa clic su Chiudi dal menu della finestra. Se l'utente conferma che la finestra deve essere eliminata definitivamente, l'applicazione chiama DestroyWindow. Il sistema invia il messaggio WM_DESTROY alla finestra dopo averlo rimosso dallo schermo. In risposta a WM_DESTROY, la finestra salva i dati e libera tutte le risorse allocate. Una finestra principale conclude l'elaborazione di WM_DESTROY chiamando la funzione PostQuitMessage per uscire dall'applicazione.
Nell'esempio seguente viene illustrato come richiedere la conferma dell'utente prima di eliminare una finestra. In risposta a WM_CLO edizione Standard, viene visualizzata una finestra di dialogo contenente i pulsanti Sì, No e Annulla. Se l'utente fa clic su Sì, viene chiamato DestroyWindow; in caso contrario, la finestra non viene eliminata definitivamente. Poiché l'applicazione gestisce il messaggio di WM_CLO edizione Standard, 0
viene restituito in tutti i casi. Poiché la finestra eliminata è una finestra principale, l'esempio chiama PostQuitMessage in risposta a WM_DESTROY.
case WM_CLOSE:
// Create the message box. If the user clicks
// the Yes button, destroy the main window.
if (MessageBox(hwnd, szConfirm, szAppName, MB_YESNOCANCEL) == IDYES)
DestroyWindow(hwndMain);
return 0;
case WM_DESTROY:
// Post the WM_QUIT message to
// quit the application terminate.
PostQuitMessage(0);
return 0;
Uso di finestre a più livelli
Per fare in modo che una finestra di dialogo venga visualizzata come finestra traslucente, creare prima di tutto il dialogo come di consueto. Quindi, in WM_INITDIALOG, impostare il bit a più livelli dello stile esteso della finestra e chiamare SetLayeredWindowAttributes con il valore alfa desiderato. Il codice potrebbe essere simile al seguente:
// Set WS_EX_LAYERED on this window
SetWindowLong(hwnd,
GWL_EXSTYLE,
GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// Make this window 70% alpha
SetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);
Si noti che il terzo parametro di SetLayeredWindowAttributes è un valore compreso tra 0 e 255, con 0 che rende la finestra completamente trasparente e 255 rendendola completamente opaca. Questo parametro simula la più versatile BLENDFUNCTION della funzione AlphaBlend.
Per rendere questa finestra completamente opaca, rimuovere il bit di WS_EX_LAYERED chiamando SetWindowLong e quindi chiedere alla finestra di eseguire nuovamente l'aggiornamento. La rimozione del bit è in grado di informare il sistema che può liberare memoria associata al layering e al reindirizzamento. Il codice potrebbe essere simile al seguente:
// Remove WS_EX_LAYERED from this window styles
SetWindowLong(hwnd,
GWL_EXSTYLE,
GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
// Ask the window and its children to repaint
RedrawWindow(hwnd,
NULL,
NULL,
RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
Per usare finestre figlio a più livelli, l'applicazione deve dichiararsi compatibile con Windows 8 nel manifesto.
Per windows 10/11, è possibile includere questo frammento di compatibilità nel relativo app.manifest
per renderlo compatibile con Windows 10:
...
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 GUID -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
...
Altre informazioni sulla modifica del manifesto dell'app sono disponibili qui: Manifesti dell'applicazione