Realizzazione di una Finestra con le API Windows
Mer 03 Ott 2007
   





Inserimento di una Toolbar

La toolbar è una barra orizzontale in cui sono presenti dei bottoni, è considerata una finestra, ed è posizionata nella parte superiore della finestra genitrice.
Per quanto riguarda le icone da inserire nella toolbar vi sono delle icone appartenenti ad un insieme predefinito che è possibile utilizzare, oppure se ne possono definire delle altre utilizzando il resource builder. In questo caso quando si andrà a salvare oltre al file script.rc e al file resource.h sarà prodotto anche il file toolbarX.bmp che sarà una immagine costituita dalla barra di bottoni definita dall'utente con il resource builder.
Il gruppo di icone predefinito è il seguente STD_COPY, STD_PASTE, STD_CUT, STD_PRINT, STD_DELETE, STD_PRINTPRE, STD_FILENEW, STD_PROPERTIES, STD_FILEOPEN, STD_REDOW, STD_FILESAVE, STD_REPLACE, STD_FIND, STD_UNDO, STD_HELP, VIEW_LARGEICONS, VIEW_SORTNAME, VIEW_SMALLICONS, VIEW_SORTSIZE, VIEW_LIST, VIEW_SORTDATE, VIEW_DETAILS, VIEW_SORTTYPE  

Per aggiungere una toolbar ad una finestra la si deve prima creare. Per farlo, dal momento che viene considerata come una finestra, si utilizza la funzione CreateWindowEx

  1. handle = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE,
  2. 0, 0, 0, 0, hwnd, (HMENU)IDC_MAIN_TOOL,
  3. GetModuleHandle(NULL), NULL);

Come nome della finestra viene utilizzato il nome predefinito per le toolbar, TOOLBARCLASSNAME, viene poi indicato che la finestra che si sta costruendo sarà una finestra figlia di un'altra finestra (WS_CHILD), e dovrà essere visibile (WS_VISIBLE). La finestra genitrice sarà quella il cui handle è contenuto in hwnd.
La finestra creata per contenere la Toolbar ha come menù la Toolbar stessa. Praticamente si può considerare la finestra creata per contenere la Toolbar come una finestra costituita dal solo menù: la Toolbar ((HMENU)IDC_MAIN_TOOL). Non c’è nessuna istanza, nessuna applicazione associata alla finestra Toolbar, nessuna funzione che si dovrà occupare di processare i comandi inviati alla toolbar (GetModuleHandle(NULL)). È poi necessario per la toolbar inserire la seguente istruzione SendMessage(hTool,TB_BUTTONSTRUCTSIZE,(WPARAM)sizeof(TBBUTTON),0) se non la si inserisse la toolbar non verrebbe visualizzata.
Una volta costruita la toolbar si deve definirla indicando quali icone ne faranno parte. Per comporre la toolbar si utilizzerà la struttura TBADDBITMAP.
La struttura TBADDBITMAP è utilizzata per aggiungere una immagine bitmap, che contiene le immagini dei vari bottoni, alla toolbar.

  1. typedef struct {
  2. HINSTANCE hInst;
  3. UINT_PTR nID;
  4. } TBADDBITMAP, *LPTBADDBITMAP;

Il membro hInst conterrà l'handle dell'istanza del modulo del file eseguibile che contiene la risorsa bitmap. Per utilizzare gli handle delle immagini bitmap invece degli identificatori di risorsa si deve fissare hInst a NULL.
Se hInst è NULL fissare come valore di nID l'handle dell'immagine bitmap con le immagini dei bottoni, altrimenti fissare come valore di nID l'identificatore di risorsa dell'immagine bitmap contenente le immagini dei bottoni.
è possibile aggiungere alla lista delle immagini bitmap relative a bottoni indicando HINST_COMMCTRL come membro hInst e indicando come membro nID uno dei seguenti valori

IDB_STD_LARGE_COLOR Adds large, color standard bitmaps
IDB_STD_SMALL_COLOR Adds small, color standard bitmaps
IDB_VIEW_LARGE_COLOR Adds large, color view bitmaps
IDB_VIEW_SMALL_COLOR Adds small, color view bitmaps

Quindi, una volta creata la finestra toolbar si compone la toolbar utilizzando la struttura TBADDBITMAP. Si fissa il membro hInst al valore predefinito HINST_COMMCTRL indicando che si intende aggiungere delle immagini di bottoni predefiniti alla lista di bottoni già presenti nella toolbar. Con nID si fissa il tipo dei bottoni presenti nella toolbar.
Si deve quindi informare la toolbar che la lista di bottoni che la costituiranno è stata definita nella struttura TBADDBITMAP. Per farlo si invierà un messaggio alla toolbar utilizzando la funzione SendMessage.
La sintassi della funzione SendMessage è la seguente

  1. lResult = SendMessage( // returns LRESULT in lResult
  2. (HWND) hWndControl, // handle to destination control
  3. (UINT) SB_SETTEXT, // message ID
  4. (WPARAM) wParam, // = (WPARAM) (INT) iPart
  5. -or-
  6. (WPARAM) wParam, // = (WPARAM) (UINT) utype
  7. (LPARAM) lParam // = (LPARAM) (LPSTR) szText
  8. );

I parametri sono iPart, che indica la sezione in cui scrivere (se iPart è fissato a SB_SIMPLEID la statusbar è considerata costituita da una sola sezione), uType, che indica il tipo di visualizzazione, e szText, che è un puntatore ad una null-terminated string in cui vi sarà il testo da scrivere.

Nel codice che segue si fissa la struttura TBADDBITMAP, e si invia un messaggio, il messaggio TB_ADDBITMAP, alla toolbar.

  1. TBADDBITMAP tbab;
  2.  
  3. tbab.hInst = HINST_COMMCTRL;
  4. tbab.nID = IDB_STD_SMALL_COLOR;
  5. SendMessage(handle, TB_ADDBITMAP, 0, (LPARAM)&tbab);

Il messaggio TB_ADDBITMAP ha la seguente struttura

  1. TB_ADDBITMAP
  2. wParam = (WPARAM) nButtons;
  3. lParam = (LPARAM) (LPTBADDBITMAP) lptbab;

Questo messaggio aggiunge una, o più, immagini alla lista delle immagini dei bottoni disponibile per la toolbar.
I "parametri" di questo messaggio sono due: nButtons, che indica il numero di immagini di bottoni presenti nella bitmap, e lptbab, puntatore alla struttura TBADDBITMAP che contiene l'identificatore della risorsa bitmap e l'handle dell'istanza del modulo del file eseguibile contenente la risorsa bitmap. Se lptbab indica una bitmap system-defined nButtons viene ignorato.

La toolbar sarà costituita da una barra di bottoni, si dovrà quindi utilizzare una struttura adeguata per memorizzare i dati relativi ad ogni bottone. A tale scopo si utilizza un'array. Un'array di tipo TBBUTTON.

La struttura TBBUTTON ha la seguente sintassi

  1. typedef struct _TBBUTTON {
  2. int iBitmap;
  3. int idCommand;
  4. BYTE fsState;
  5. BYTE fsStyle;
  6. #ifdef _WIN64
  7. BYTE bReserved[6] // padding for alignment
  8. #elif defined(_WIN32)
  9. BYTE bReserved[2] // padding for alignment
  10. #endif
  11. DWORD_PTR dwData;
  12. INT_PTR iString;
  13. } TBBUTTON, NEAR *PTBBUTTON *LPTBBUTTON;

e i membri sono i seguenti

iBitmap Indice delle button image
idCommand Identificatore del comando associato al bottone. Questo identificatore è usato nel messaggio WM_COMMAND quando il bottone è stato premuto.
fsState Button state flags. Indica lo stato del bottone, può essere una combinazione dei valori assumibili di bottoni di una toolbar.
fsStyle Button style. Indica lo stile di un bottone, può essere una combinazione dei valori di stile di un bottone di una toolbar.
dwData
iString Indice della button string, o puntatore ad una stringa che contiene testo per il bottone.

Per ogni elemento (per ogni bottone) della toolbar si deve fissare un elemento dell'array. Nel codice che segue si definiranno tre bottoni della toolbar

  1. ZeroMemory(tbb, sizeof(tbb));
  2. tbb[0].iBitmap = STD_FILENEW;
  3. tbb[0].fsState = TBSTATE_ENABLED;
  4. tbb[0].fsStyle = TBSTYLE_BUTTON;
  5. tbb[0].idCommand = ID_FILE_NEW;
  6.  
  7. tbb[1].iBitmap = STD_FILEOPEN;
  8. tbb[1].fsState = TBSTATE_ENABLED;
  9. tbb[1].fsStyle = TBSTYLE_BUTTON;
  10. tbb[1].idCommand = ID_FILE_OPEN;
  11.  
  12. tbb[2].iBitmap = STD_FILESAVE;
  13. tbb[2].fsState = TBSTATE_ENABLED;
  14. tbb[2].fsStyle = TBSTYLE_BUTTON;
  15. tbb[2].idCommand = ID_FILE_SAVEAS;

Con il membro iBitmap si indicherà il tipo di bottone, in questo caso si sono utilizzati dei bottoni predefiniti. Con il membro fsState si indica che il bottone è abilitato. Con il membro fsStyle si indica che va creato un bottone standard. Con il membro idCommand si indica l'identificatore del bottone che verrà inviato alla funzione che processerà il comando.
Una volta definito l'array dei bottoni bisogna renderlo noto alla toolbar, per farlo si invia un messaggio, il messaggio TB_ADDBUTTONS, alla toolbar tramite la funzione SendMessage.

  1. SendMessage(handle, TB_ADDBUTTONS, sizeof(tbb)/sizeof(TBBUTTON), (LPARAM)&tbb);

Il messaggio TB_ADDBUTTONS ha la seguente struttura

  1. TB_ADDBUTTONS
  2. wParam = (WPARAM)(UINT) uNumButtons;
  3. lParam = (LPARAM)(LPTBBUTTON) lpButtons;

Il messaggio TB_ADDBUTTONS, inviato alla toolbar, indica che si vuole aggiungere uno o più bottoni alla toolbar. I "parametri" di questo messaggio sono due: uNumButtons, indica il numero di bottoni da aggiungere, e lpButtons, puntatore ad un array di tipo TBUTTON che contiene le informazioni sui bottoni da aggiunere alla toolbar. Il numero degli elementi dell'array deve essere uguale a quanto indicato nel parametro uNumButtons.

Il codice per la creazione della toolbar sarà posizionato nella funzione WndProc in corrispondenza del messaggio WM_CREATE inviato quando la finestra è stata creata, ma non è ancora visibile. Inoltre è necessario chiamare InitCommonControls() prima della creazione della finestra, altrimenti la toolbar non verrà visualizzata.
Si deve inoltre inserire del codice per gestire il ridimensionamento della finestra. Quando la finestra viene ridimensionata o massimizzata si deve di conseguenza modificare anche la toolbar. Se così non fosse si avrebbe una situazione come quella descritta dalla figura seguente

Figura 12. Finestra con toolbar non ridimensionata.
in cui la finestra è stata ridimensionata dall'utente ma la dimensione della toolbar è rimasta invariata. In questo modo si ottiene questo effetto non certo gradevole.
Per evitare questo effetto si deve inserire del codice per gestire il ridimensionamento della toolbar in corrispondenza ad un ridimensionamento della finestra. Quando la finestra viene ridimensionata viene inviato un messaggio WM_SIZE alla funzione WinMain che viene inviato alla funzione WndProc per essere processato. è nella funzione WndProc che dovrà essere inserito il codice in questione.
Il programma completo è il seguente

wintoolbar.c
  1. #include <windows.h>
  2. #include <commctrl.h>
  3. #include "resource.h"
  4.  
  5. #define ID_TOOLBAR 212
  6. #define ID_FILE_NEW 300
  7. #define ID_FILE_OPEN 301
  8. #define ID_FILE_SAVEAS 302
  9.  
  10. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  11. {
  12. switch(msg)
  13. {
  14. case WM_CREATE:
  15. {
  16. HWND hTool;
  17. TBBUTTON tbb[3];
  18. TBADDBITMAP tbab;
  19.  
  20. HWND hStatus;
  21. int statwidths[] = {100, -1};
  22.  
  23. // Create Toolbar
  24. hTool = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
  25. WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)IDC_MAIN_TOOL,
  26. GetModuleHandle(NULL), NULL);
  27. if(hTool == NULL)
  28. MessageBox(hwnd, "Could not create tool bar.", "Error",
  29. MB_OK | MB_ICONERROR);
  30. SendMessage(hTool, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
  31. tbab.hInst = HINST_COMMCTRL;
  32. tbab.nID = IDB_STD_SMALL_COLOR;
  33. SendMessage(hTool, TB_ADDBITMAP, 0, (LPARAM)&tbab);
  34.  
  35. ZeroMemory(tbb, sizeof(tbb));
  36. tbb[0].iBitmap = STD_FILENEW;
  37. tbb[0].fsState = TBSTATE_ENABLED;
  38. tbb[0].fsStyle = TBSTYLE_BUTTON;
  39. tbb[0].idCommand = ID_FILE_NEW;
  40.  
  41. tbb[1].iBitmap = STD_FILEOPEN;
  42. tbb[1].fsState = TBSTATE_ENABLED;
  43. tbb[1].fsStyle = TBSTYLE_BUTTON;
  44. tbb[1].idCommand = ID_FILE_OPEN;
  45.  
  46. tbb[2].iBitmap = STD_FILESAVE;
  47. tbb[2].fsState = TBSTATE_ENABLED;
  48. tbb[2].fsStyle = TBSTYLE_BUTTON;
  49. tbb[2].idCommand = ID_FILE_SAVEAS;
  50.  
  51. SendMessage(hTool, TB_ADDBUTTONS, sizeof(tbb)/sizeof(TBBUTTON), (LPARAM)&tbb);
  52.  
  53. }
  54. break;
  55.  
  56. case WM_SIZE:
  57. {
  58. HWND hTool;
  59. RECT rcTool;
  60. int iToolHeight;
  61. // Calculate remaining height and size edit
  62. GetClientRect(hwnd, &rcClient);
  63. iEditHeight = rcClient.bottom - iToolHeight - iStatusHeight;
  64. hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT);
  65. SetWindowPos(hEdit, NULL, 0, iToolHeight, rcClient.right,iEditHeight, SWP_NOZORDER);
  66. }
  67. break;
  68.  
  69. case WM_CLOSE:
  70. DestroyWindow(hwnd);
  71. break;
  72.  
  73. case WM_DESTROY:
  74. PostQuitMessage(0);
  75. break;
  76.  
  77. case WM_COMMAND:
  78. switch(LOWORD(wParam))
  79. {
  80. case ID_FILE_SAVE:
  81. break;
  82.  
  83. case ID_FILE_OPEN:
  84. break;
  85.  
  86. case ID_FILE_SAVEAS:
  87. break;
  88. }
  89. break;
  90.  
  91. default:return DefWindowProc(hwnd, msg, wParam, lParam);
  92. }
  93. return 0;
  94. }
  95.  
  96. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
  97. int nCmdShow)
  98. {
  99. WNDCLASSEX wc;
  100. HWND handle;
  101. MSG message;
  102.  
  103. InitCommonControls();
  104.  
  105. wc.cbSize = sizeof(WNDCLASSEX);
  106. wc.style = 0;
  107. wc.lpfnWndProc = WndProc;
  108. wc.cbClsExtra = 0;
  109. wc.cbWndExtra = 0;
  110. wc.hInstance = hInstance;
  111. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  112. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  113. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  114. wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
  115. wc.lpszClassName = "wintoolbar";
  116. wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  117.  
  118. if(!RegisterClassEx(&wc))
  119. {
  120. MessageBox(NULL, "Registrazione della Finestra Fallita!", "Errore!",
  121. MB_ICONEXCLAMATION | MB_OK);
  122. return 0;
  123. }
  124.  
  125. handle = CreateWindowEx(
  126. 0,
  127. "wintoolbar",
  128. "Esempio Toolbar e Statusbar",
  129. WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  130. CW_USEDEFAULT, CW_USEDEFAULT, 480, 320,
  131. NULL, NULL, hInstance, NULL);
  132.  
  133. if(handle == NULL)
  134. {
  135. MessageBox(NULL, "Creazione della Finestra Fallita!", "Errore!",
  136. MB_ICONEXCLAMATION | MB_OK);
  137. return 0;
  138. }
  139.  
  140. ShowWindow(handle, nCmdShow);
  141. UpdateWindow(handle);
  142.  
  143. while(GetMessage(&message, NULL, 0, 0) > 0)
  144. {
  145. TranslateMessage(&message);
  146. DispatchMessage(&message);
  147. }
  148. return message.wParam;
  149. }

Affinché il programma funzioni però è necessario utilizzare la libreria comctl32.lib. In visual C++ sotto il menù Project->settings e poi nel tab link si deve inserire la libreria comctl32.lib.
La finestra risultante è la seguente

Figura 13. Finestra con menù e toolbar.

Inserimento di una Statusbar

La statusbar è una barra orizzontale posizionata nella parte inferiore della finestra. È possibile dividerla in più parti (sezioni), e in ciascuna parte si potrà inserire del testo o delle immagini, è considerata a sua volta una finestra. È utilizzata principalmente per visualizzare informazioni.
Per aggiungere una statusbar alla finestra si procede come per la toolbar, la statusbar viene considerata come una finestra e il menù di questa finestra è la statusbar stessa. Quindi per creare la toolbar si utilizzerà la funzione CreateWindowEx esattamente come per la toolbar

  1. handle = CreateWindowEx(0, STATUSCLASSNAME, NULL,
  2. WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0,
  3. hwnd, (HMENU)STATUSBAR, GetModuleHandle(NULL), NULL);

Come nome della finestra viene utilizzato il nome predefinito per le statusbar, STATUSCLASSNAME, viene poi indicato che la finestra che si sta costruendo sarà una finestra figlia di un'altra finestra (WS_CHILD), dovrà essere visibile (WS_VISIBLE), e la statusbar deve includere una sizing grip alla sua estremità di destra (SBARS_SIZEGRIP). La finestra genitrice sarà quella il cui handle è contenuto in hwnd. La finestra creata per contenere la statusbar ha come menù la statusbar stessa ((HMENU)STATUSBAR). Non c’è nessuna istanza, nessuna applicazione associata alla finestra statusbar, nessuna funzione che si dovrà occupare di processare i comandi inviati alla statusbar (GetModuleHandle(NULL)).
Con la CreateWindowEx si è semplicemente creata la statusbar, per dividerla in sezioni si deve inviare un messaggio, il messaggio SB_SETPARTS, alla statusbar tramite la funzione SendMessage

  1. SendMessage(handle, SB_SETPARTS, sizeof(statwidths)/sizeof(int),
  2. (LPARAM)statwidths);

Il messaggio SB_SETPARTS ha la seguente struttura

  1. SB_SETPARTS
  2. wParam = (WPARAM) nParts;
  3. lParam = (LPARAM)(LPINT) aWidths;

Con il messaggio SB_SETPARTS si indica in quante parti (quante sezioni) dovrà essere divisa la statusbar e le coordinate del bordo destro di ciascuna parte. Il messaggio ha due "parametri", nParts, che indica il numero di parti in cui è divisa la statusbar (massimo 256), e aWidths, puntatore ad un'array di interi in cui ciascun elemento specifica la posizione del bordo destro della corrispondente parte, se ad un elemento corrisponde -1 come posizione il bordo destro della corrispondente parte si estende al bordo della finestra. In sostanza l'elemento dell'array relativo all'ultima parte della statusbar deve essere pari a -1.

Una volta suddivisa la statusbar si devono inserire i vari testi nelle varie sezioni. Per inserire un testo in una sezione si dovrà inviare un messaggio, il messaggio SB_SETTEXT, alla statusbar

  1. SendMessage(handle, SB_SETTEXT, 0, (LPARAM)"Esempio Status Bar");

Il messaggio SB_SETTEXT ha la seguente struttura

  1. SB_SETTEXT
  2. wParam = (WPARAM) iPart | uType;
  3. lParam = (LPARAM)(LPSTR) szText;

Con il messaggio SB_SETTEXT si fissa il testo nella sezione specificata della statusbar. Il messaggio ha due "parametri", con iPart si indica in quale sezione dovrà essere posto il teso, con uType si indica come dovrà essere visualizzato il testo, può assumere i seguenti valori: 0, SBT_NOBORDERS, SBT_OWNERDRAW, SBT_POPOUT, SBT_RTLREADING. Con szText, stringa terminata dal carattere nullo, si specifica il testo da scrivere.

Nell'esempio che segue si è creata una statusbar con tre sezioni,

  1. int statwidths[] = {100, 200, -1};
  2.  
  3. SendMessage(handle, SB_SETTEXT, 0, (LPARAM)"Esempio Status Bar");
  4. SendMessage(handle, SB_SETTEXT, 1, (LPARAM)"Seconda Sezione");
  5. SendMessage(handle, SB_SETTEXT, 2, (LPARAM)"Terza, ed Ultima Sezione");

Il codice (esclusa la funzione WinMain che è identica a quella del programma relativo alla toolbar) che produce la statusbar è il seguente

winstatusbar.c
  1. #include <windows.h>
  2. #include <commctrl.h>
  3. #include "resource.h"
  4.  
  5. #define STATUSBAR 213
  6.  
  7. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  8. {
  9. switch(msg)
  10. {
  11. case WM_CREATE:
  12. {
  13. HWND hStatus;
  14. int statwidths[] = {100, 200, -1};
  15.  
  16. // Create Status bar
  17. hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL,
  18. WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0,
  19. hwnd, (HMENU)STATUSBAR, GetModuleHandle(NULL), NULL);
  20. if(hTool == NULL)
  21. MessageBox(hwnd, "Could not create tool bar.", "Error",
  22. MB_OK | MB_ICONERROR);
  23.  
  24. SendMessage(hStatus, SB_SETPARTS, sizeof(statwidths)/sizeof(int),
  25. (LPARAM)statwidths);
  26. SendMessage(handle, SB_SETTEXT, 0, (LPARAM)"Prima Sezione");
  27. SendMessage(handle, SB_SETTEXT, 1, (LPARAM)"Seconda Sezione");
  28. SendMessage(handle, SB_SETTEXT, 2, (LPARAM)"Terza,
  29. ed Ultima Sezione");
  30. }
  31. break;
  32.  
  33. case WM_SIZE:
  34. {
  35. HWND hStatus;
  36. RECT rcStatus;
  37. int iStatusHeight;
  38.  
  39. // Size status bar and get height
  40. hStatus = GetDlgItem(hwnd, STATUSBAR);
  41. SendMessage(hStatus, WM_SIZE, 0, 0);
  42. GetWindowRect(hStatus, &rcStatus);
  43. iStatusHeight = rcStatus.bottom - rcStatus.top;
  44. }
  45. break;
  46.  
  47. case WM_CLOSE: DestroyWindow(hwnd); break;
  48.  
  49. case WM_DESTROY: PostQuitMessage(0); break;
  50.  
  51. case WM_COMMAND:
  52. switch(LOWORD(wParam))
  53. {
  54. case ID_FILE_SAVE:
  55. break;
  56.  
  57. case ID_FILE_OPEN:
  58. break;
  59.  
  60. case ID_FILE_SAVEAS:
  61. break;
  62. }
  63. break;
  64.  
  65. default:return DefWindowProc(hwnd, msg, wParam, lParam);
  66. }
  67. return 0;
  68. }

La finestra risultante sarà la seguente

Figura 14. Finestra con menù e statusbar.

Pagina 5 di 5
Prec 1 2 3 4 5 Succ