IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

API Windows en C

Application MDI (en cours de rédaction).

Nous allons voir dans ce chapitre comment concevoir une application MDI.

Article lu   fois.

L'auteur

Profil ProSite personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Description

Une application MDI, c'est une application avec une fenêtre principale qui peut contenir des fenêtres redimensionnables.

Image non disponible

Le code présenté dans ce tutoriel est le code minimum pour une application MDI. L'application de fait rien à par céer et gérer les fenêtres enfants.
Le procédé est sensiblement le même que pour une simple fenêtre redimensionnables, mise à part que ce n'est pas la fenêtre principale qui contient les fenêtres enfants, mais une fenêtre spéciale dont le nom de classe de fenêtre est MDICLIENT que nous créerons lors de la création de la fenêtre principale.
Cette fenêtre est déjà programmée pour occuper toute la surface client de la fenêtre principale et gérer les fenêtres enfants qui lui sont rattachées.
Les fenêtres enfants quand à elles, seront crées avec la fonction CreateMDIWindow, après avoir préparer et enregistrer leur classe de fenêtre nommée "ChildWinClass" dans l'exemple.
La boucle de message est légèrement modifiée afin de traiter et d'envoyer les raccourcis clavier destinés aux fenêtres enfants avec l'appel à la fonction TranslateMDISysAccel.

 
Sélectionnez
    while (GetMessage(&msg, NULL, 0, 0))
    {
     if (!TranslateMDISysAccel(hwnd_mdi, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

Pour les applications MDI, la procédure de fenêtre par défaut de la fenêtre principale est DefFrameProc au lieu de DefWindowProc. Celle des fenêtres enfants est DefMDIChildProc.

Lors de la création de la fenêtre MDICLIENT on envoi des données supplémentaires via une structure CLIENTCREATESTRUCT leur rôles est d'ajouter au menu les options d'activation des fenêtres enfants.

 
Sélectionnez
    case WM_CREATE :
      {
        CLIENTCREATESTRUCT ccs;
        ccs.hWindowMenu = GetSubMenu(GetMenu(hwnd), 1);
        ccs.idFirstChild = IDM_WINCHILD;

        hwnd_mdi = CreateWindow("MDICLIENT", (LPCTSTR) NULL,
                 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
                   CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                                                       hwnd, NULL, hinst, &ccs);
        return 0;
      }

Il faut donc le handle du sous menu et l'ID de menu de la première fenêtre IDM_WINCHILD dans l'exemple. L'ID de menu des suivantes sera l'ID de la précédente + 1. (Donc attention à ne pas les utiliser pour d'autre ID de menu ou commande). On obtient l'handle du sous menu à l'aide de la fonction GetSubMenu (mettre le numéro d'ordre du sous menu désiré en son second paramètre). Il faut envoyer l'adresse de la structure à CreateWindow (dernier paramètre).
Veiller à envoyer les commandes non traitées à la procédure de fenêtre par défaut.
Les fenêtres enfants seront crées avec la fonction CreateMDIWindow dont l'utilisation est fort semblable à CreateWindow. (Dans le code d'exemple je ne récupère pas les handles de fenêtre retourné par la fonction, mais il va de soit que si vous en avez besoin il faudra le faire).
J'ai mis le code de la procédure de fenêtre des fenêtres enfants, nommé ChildWndProc dans l'exemple. Il ne fait rien à part envoyer les messages à la procédure de fenêtre par défaut.

II. Code complet

winmain.c :
Sélectionnez
#include <windows.h>
#include "menu.h"

#define IDM_WINCHILD 2000

HINSTANCE hinst;
HWND hwnd_mdi;

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
                                                  LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd;
    MSG msg;
    WNDCLASS wc={0};

    hinst = hinstance;

    wc.lpfnWndProc = MainWndProc;
    wc.hInstance = hinstance;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
    wc.lpszClassName = "MaWinClass";
    RegisterClass(&wc);

    wc.lpfnWndProc = ChildWndProc;
    wc.lpszClassName = "ChildWinClass";
    RegisterClass(&wc);

    HMENU hmenu = LoadMenu(hinst, "LEMENU");
    hwnd = CreateWindow("MaWinClass", "MDI Application",
                         WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
                                CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,
                                                  NULL, hmenu, hinstance, NULL);
    ShowWindow(hwnd, nCmdShow);

    while (GetMessage(&msg, NULL, 0, 0))
    {
     if (!TranslateMDISysAccel(hwnd_mdi, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return msg.wParam;
}
/******************************************************************************/

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_COMMAND :
        if(LOWORD(wParam) == IDM_QUIT)
          {
            PostMessage(hwnd, WM_CLOSE,0,0);
            return 0;
          }

        if(LOWORD(wParam) == IDM_ADD)
          {
            static int num = 0;
            num++;
            char wtitle[256];
            wsprintf(wtitle, "WinChild %d", num);

            CreateMDIWindow("ChildWinClass", wtitle, 0,
                    CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, hwnd_mdi, hinst, 0);
            return 0;
          }

        if(LOWORD(wParam) == IDM_CASCADE)
          {
            SendMessage(hwnd_mdi, WM_MDICASCADE, 0 ,0);
            return 0;
          }

        if(LOWORD(wParam) == IDM_TILE_H)
          {
            SendMessage(hwnd_mdi, WM_MDITILE, MDITILE_HORIZONTAL ,0);
            return 0;
          }

        if(LOWORD(wParam) == IDM_TILE_V)
          {
            SendMessage(hwnd_mdi, WM_MDITILE, MDITILE_VERTICAL ,0);
            return 0;
          }
        break;

    case WM_CREATE :
      {
        CLIENTCREATESTRUCT ccs;
        ccs.hWindowMenu = GetSubMenu(GetMenu(hwnd), 1);
        ccs.idFirstChild = IDM_WINCHILD;

        hwnd_mdi = CreateWindow("MDICLIENT", (LPCTSTR) NULL,
                 WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
                   CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                                                       hwnd, NULL, hinst, &ccs);
        return 0;
      }

    case WM_CLOSE :
        DestroyWindow(hwnd);
        return 0;

    case WM_DESTROY :
        PostQuitMessage(0);
        return 0;
    }
    return DefFrameProc(hwnd, hwnd_mdi, uMsg, wParam, lParam);
}

LRESULT CALLBACK ChildWndProc(HWND hwndchild, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {

    default :
        return DefMDIChildProc(hwndchild, uMsg, wParam, lParam);
    }
}
menu.h :
Sélectionnez
#define IDM_QUIT 1
#define IDM_ADD 2
#define IDM_CASCADE 3
#define IDM_TILE_H 4
#define IDM_TILE_V 5
menu.rc :
Sélectionnez
#include "menu.h"

LEMENU MENU
BEGIN
  POPUP "File"
    BEGIN
       MENUITEM "New", IDM_ADD
       MENUITEM SEPARATOR
       MENUITEM "Quit", IDM_QUIT
    END
  POPUP "Windows"
    BEGIN
       MENUITEM "Cascade", IDM_CASCADE
       MENUITEM "Tile Horizontal", IDM_TILE_H
       MENUITEM "Tile Vertical", IDM_TILE_V
    END
END

J'ai testé ce code avec MinGW et Visual C.


À vos PC.

Sommaire

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2021 CGi. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.