[MFC] [RESOLU] Affichage message avant fermeture d une fenetre

Affichage message avant fermeture d une fenetre [MFC] [RESOLU] - C++ - Programmation

Marsh Posté le 14-10-2015 à 20:34:12    

Bonsoir à tous,
 
Je suis actuellement en train d'apprendre la bibliothèque objet MFC. Pour m’exercer, je teste l'affichage de messages selon différentes conditions.
Par exemple, avant l'apparition de la fenêtre principale, après la fenêtre principale, ...
 
Ce qui me pose un problème c'est d'afficher un message juste avant la fermeture de la fenêtre principale. J'ai trouvé que l'on devait utiliser WM_CLOSE cependant je n'arrive toujours pas à afficher un message juste avant la fermeture.
 
Pourriez-vous m'aider s'il vous plaît ?
 
Bonne soirée :)

Message cité 1 fois
Message édité par TP_78 le 08-11-2015 à 17:46:46

---------------
Mon topic d'achat de DRAGON QUEST http://forum.hardware.fr/hfr/JeuxV [...] 1589_1.htm
Reply

Marsh Posté le 14-10-2015 à 20:34:12   

Reply

Marsh Posté le 14-10-2015 à 22:33:21    

TP_78 a écrit :

Bonsoir à tous,
Je suis actuellement en train d'apprendre la bibliothèque objet MFC. Pour m’exercer, je teste l'affichage de messages selon différentes conditions.
Par exemple, avant l'apparition de la fenêtre principale, après la fenêtre principale, ...
 
Ce qui me pose un problème c'est d'afficher un message juste avant la fermeture de la fenêtre principale. J'ai trouvé que l'on devait utiliser WM_CLOSE cependant je n'arrive toujours pas à afficher un message juste avant la fermeture.
 
Pourriez-vous m'aider s'il vous plaît ?
 
Bonne soirée :)


Avec l'API win32, WM_CLOSE est envoyé à la fenêtre que l'utilisateur veut fermer, mais ce message est juste une notification, au programme de faire ce qui faut pour fermer ou non la fenêtre:

  • Tu peux afficher une fenêtre de confirmation (MessageBox).
  • Tu peux fermer la fenêtre (DestroyWindow), mais continuer le programme (genre service en arrière plan).
  • Ou tu peux aussi quitter le programme si la fenêtre principale est fermée (PostQuitMessage).

Le système ne peut pas avoir connaissance de ce genre de chose, c'est pourquoi WM_CLOSE est juste une notification.
 
Si tu transmet le message a DefWindowProc(), ça sera DestroyWindow() qui sera appelé.
 
Avec les MFC, il faut surcharger OnClose(), qui appelle aussi DestroyWindow() par défaut.
 
Et puis bon, c'est mon avis à moi: mais se faire chier avec les MFC/Win32 en 2015, c'est vraiment se prendre la tête pour pas grand chose, parce que bon, même microsoft a jeté l'éponge ...

Reply

Marsh Posté le 15-10-2015 à 00:05:11    

Bonsoir tpierron,
 
Merci pour ta réponse.  
D'après ce que tu as dit, j'en déduis qu'il faut faire quelque chose comme ça:
 
switch(???)
{
   ...
   case WM_CLOSE: ::MessageBox(_T("La fenetre va être fermée" ));
     break;
   ...
}
 
Cependant qui retourne la notification WM_CLOSE ?


---------------
Mon topic d'achat de DRAGON QUEST http://forum.hardware.fr/hfr/JeuxV [...] 1589_1.htm
Reply

Marsh Posté le 15-10-2015 à 15:20:47    

TP_78 a écrit :

Merci pour ta réponse.  
D'après ce que tu as dit, j'en déduis qu'il faut faire quelque chose comme ça:
switch(???)
{
   ...
   case WM_CLOSE: ::MessageBox(_T("La fenetre va être fermée" ));
     break;
   ...
}
Cependant qui retourne la notification WM_CLOSE ?


Hmm, tu n'as pas l'air de connaître grand chose de l'API Win32/MFC. Parce que ce n'est vraiment pas le genre d'API que tu peux apprendre sur le tas, faudra t'investir un minimum, d'autant que sur internet tu ne trouveras que des exemples de culte du cargo (ce sera d'ailleurs pas beaucoup mieux sur MSDN). Si tu comptes vraiment foncer tête baissé là dedans, t'auras vraiment l'impression d'enfoncer un clou avec la tête.
 
Ton morceau de code, c'est de l'API Win32, une couche en-dessous des MFC. Avec les MFC, faut hériter d'une classe CWnd ou CDialog (la différence est importante), puis surcharger la méthode OnClose pour récupérer la notification de fermeture (qui par défaut appellera DestroyWindow).
 
Si tu veux passer par l'API Win32, ce message (WM_CLOSE) est transmis à la procédure enregistrée à la création de la classe de la fenêtre (structure WNDCLASS, champ lpfnWndProc, enregistré via RegisterClass). Cette procédure recevra une tétrachiée de notification: dans une de mes applications, le switch fait 800 lignes, et il ne contient pratiquement que des redirections.
 
Ne mélange pas les deux styles (MFC/Win32) à moins que tu saches très précisément ce que tu fais, ce qui n'est probablement pas le cas.

Reply

Marsh Posté le 27-10-2015 à 12:08:25    

Bonjour tpierron,
 
Si je tarde à te répondre c'est que j'ai essayé de faire ce que tu m'as dit mais je n'arrive pas à comprendre.
 
Mon programme pour l'instant se résume à un unique fichier source (main.cpp):
 

Code :
  1. #include <afxwin.h>
  2. class CTstApp : public CWinApp
  3. {
  4.   public:
  5.   BOOL InitInstance()
  6.   {
  7.     m_pMainWnd=new CWnd;
  8.     m_pMainWnd->CreateEx(0,AfxRegisterWndClass(CS_CLASSDC,0,::CreateSolidBrush(0xFF00FF),0),_T("AD-IHM" ),
  9.       WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,CRect(0,0,300,300),0,0);
  10.     m_pMainWnd->ShowWindow(m_nCmdShow);
  11.     return TRUE;
  12.   }
  13. };
  14. CTstApp NotreApp;


 
Avec mon code ci-dessus, pourrais tu m'indiquer (pas me donner la solution) comment faire s'il te plaît ?
 
En te remerciant par avance.
Bonne journée


---------------
Mon topic d'achat de DRAGON QUEST http://forum.hardware.fr/hfr/JeuxV [...] 1589_1.htm
Reply

Marsh Posté le 27-10-2015 à 14:24:16    

Bonjour !  
 
Comme vous l'indiquait tpierron, il faudrait que votre m_pMain ne soit pas une CWnd, mais une classe à vous qui dérive de CWnd et dans laquelle vous surchargez la méthode OnClose qui est appellée automatiquement lorsque le système demande la fermeture de la fenêtre.
 
C'est dans cette méthode que vous placez votre traitement, que ce soit une fenêtre de confirmation ou toute autre action pour libérer proprement un certain nombre de ressources.
 
Bonne continuation !


Message édité par Farian le 27-10-2015 à 14:24:50
Reply

Marsh Posté le 27-10-2015 à 14:59:31    

Ouéééé, je viens de dépoussiérer le SDK des MFC qui moisissait depuis 2002 ou 2003, et j'avais oublié combien cette API à mal vieilli.
 
Bon, déjà, je te conseille d'utilisez le wizard de Visual Studio pour rajouter des classes, parce que les MFC rajoutent une tétrachiée de fonctions à la création. Tu m'excusera si j'ai un peu oublié de détail en 12 ou 13 ans.
 
Ton code fonctionne (ce qui est déjà pas si mal), sauf que la fenêtre s'ouvre et se ferme immédiatement. À vu de nez, je dirai qu'une méthode n'est pas surchargée comme il faut (laquelle, j'ai oublié).
 
Si tu tiens vraiment à tout gérer à la main, je te conseille vivement de laisser tomber les MFC et utiliser directement les Win32. De toute façon entre les deux, c'est choisir entre la peste ou le cholera.

Reply

Marsh Posté le 29-10-2015 à 10:57:19    

tpierron a écrit :


Si tu tiens vraiment à tout gérer à la main, je te conseille vivement de laisser tomber les MFC et utiliser directement les Win32. De toute façon entre les deux, c'est choisir entre la peste ou le cholera.


+1 c'est aussi ce que je me suis dit en voyant le titre du topic. Tu as vraiment besoin d'apprendre les MFC, et même les API Windows en général ? C'est dans quel but au final ?
Si le besoin est justifié et que tu ne veux pas qu'on fasse digresser le topic pas de souci [:faman:1]  


---------------
Topic .Net - C# @ Prog
Reply

Marsh Posté le 02-11-2015 à 18:42:24    

Merci pour vos réponses. Je fais ça et vous tiens au courant :)
 
Oui malheureusement cela est dans le cadre de mes études.
 
EDIT: Donc suite à vos réponses, j'ai surchargé ma methode OnClose cependant je ne peux pas car elle est protégée. Des suggestions ? :)
 

Code :
  1. class Fenetre : public CWnd
  2. {
  3. public:
  4. Fenetre()
  5. {
  6. }
  7. void OnClose()
  8. {
  9.  CWnd::OnClose();
  10.  MessageBox(_T("Voulez-vous fermer la fenetre ?" ), _T("TEST" ), MB_OK);
  11.  //_super::OnClose();
  12. }
  13. private:
  14. };
  15. class CTstApp : public CWinApp
  16. {
  17.   public:
  18.   BOOL InitInstance()
  19.   {
  20.   m_pMainWnd = new Fenetre;
  21.   m_pMainWnd->CreateEx(0, AfxRegisterWndClass(CS_CLASSDC, 0, ::CreateSolidBrush(0xFF00FF), 0), _T("AD-IHM" ),
  22.    WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, CRect(0, 0, 300, 300), 0, 0);
  23.   m_pMainWnd->OnClose(); // Le compilateur me dit gentiment que je ne peux accèder à la fonction car elle est protegee
  24.   m_pMainWnd->ShowWindow(m_nCmdShow);
  25.     return TRUE;
  26.   }
  27. };


Message édité par TP_78 le 02-11-2015 à 19:48:49

---------------
Mon topic d'achat de DRAGON QUEST http://forum.hardware.fr/hfr/JeuxV [...] 1589_1.htm
Reply

Marsh Posté le 02-11-2015 à 20:34:11    

Ah ouais, quand même  :sweat: Toutes mes condoléances. Sinon, j'ai un peu revu ton code (juste la classe "Fenetre", le reste me parait bon) pour faire fonctionner le bouzin. C'est tellement dégueux, que je ne vais même pas essayer de donner des explications:

Code :
  1. class Fenetre : public CFrameWnd
  2. {
  3. public:
  4.     Fenetre() {}
  5. protected:
  6.     DECLARE_DYNAMIC(Fenetre)
  7.  
  8. // Generated message map functions
  9. protected:
  10.     afx_msg void OnClose(void);
  11.     DECLARE_MESSAGE_MAP()
  12.  
  13. };
  14.  
  15. IMPLEMENT_DYNAMIC(Fenetre, CFrameWnd)
  16.  
  17. BEGIN_MESSAGE_MAP(Fenetre, CFrameWnd)
  18.     ON_WM_CLOSE()
  19. END_MESSAGE_MAP()
  20.  
  21. void Fenetre::OnClose()
  22. {
  23.     MessageBox(_T("Voulez-vous fermer la fenetre ?" ), _T("TEST" ), MB_OK);
  24.     CWnd::OnClose();
  25. }


Quelques trucs à faire gaffe:

  • La classe de base pour une fenêtre c'est CFrameWnd, pas CWnd (oups, petit oubli)
  • J'avais oublié l'assignation à m_pMainWnd dans InitInstance, ce qui faisait que la fenêtre se fermait immédiatement.
  • Si tu redirige OnClose, faut l'appeler la classe mère après avoir demandé confirmation (MessageBox)

[:shlavos] bordel de merde, mais qu'est ce que c'est moche.

Reply

Marsh Posté le 02-11-2015 à 20:34:11   

Reply

Marsh Posté le 05-11-2015 à 17:17:44    

Salut tpierron,
 
J'ai recopié le code que tu m'as soumis dans mon programme et j'obtiens toujours que la fonction OnClose() est protégée :/
 De ton coté cela fonctionne ?
 
Par la même occasion, pourrais tu m'expliquer à quoi correspond DECLARE_DYNAMIC() et IMPLEMENT_DYNAMIC s'il te plaît ?
 
Bonne soirée.
 
Merci de ta persévérance :)


---------------
Mon topic d'achat de DRAGON QUEST http://forum.hardware.fr/hfr/JeuxV [...] 1589_1.htm
Reply

Marsh Posté le 05-11-2015 à 18:09:29    

Tu parles de cette ligne dans InitInstance() :

Code :
  1. m_pMainWnd->OnClose(); // Le compilateur me dit gentiment que je ne peux accèder à la fonction car elle est protegee


Si tu cherches un moyen de fermer la fenêtre autrement que par une action de l'utilisateur, la méthode que tu cherches c'est "DestroyWindow". Cette fonction enverra une notification OnDestroy, mais pas de OnClose cela dit.
 
Si tu veux simuler un clic sur le bouton de fermeture, ça doit être un truc du genre :

Code :
  1. m_pMainWnd->SendMessage(WM_CLOSE);
  2. // Cet appel va bloquer si tu affiche un dialogue de confirmation, pour continuer malgré tout, tu peux utiliser:
  3. // m_pMainWnd->PostMessage(WM_CLOSE);


 
Edit: les macros à rajouter sont des bidules propres aux MFC, j'ai oublié le détail (ça, c'est une manière polie de dire que je ne veux pas m'en souvenir).


Message édité par tpierron le 05-11-2015 à 18:11:26
Reply

Marsh Posté le 08-11-2015 à 17:42:57    

Bonsoir tpierron,
 
c'est bon j'ai enfin réussi, mon objectif était de fermer la fenêtre selon que l'utilisateur clique sur X ou par une autre action.
Au final, voici mon code:  
 

Code :
  1. #include <afxwin.h>
  2. class Fenetre : public CFrameWnd
  3. {
  4. public:
  5. Fenetre()
  6. {
  7. }
  8. void OnClose()
  9. {
  10.  if (AfxMessageBox(_T("Voulez-vous fermer la fenetre 3?" ), MB_YESNO) == IDYES)
  11.  {
  12.   CWnd::OnClose();
  13.  }
  14.  //_super::OnClose();
  15. }
  16. protected:
  17. DECLARE_MESSAGE_MAP()
  18. protected:
  19. DECLARE_DYNAMIC(Fenetre)
  20. private:
  21. };
  22. IMPLEMENT_DYNAMIC(Fenetre,CFrameWnd)
  23. BEGIN_MESSAGE_MAP(Fenetre, CFrameWnd)
  24. ON_WM_CLOSE()
  25. END_MESSAGE_MAP()
  26. class CTstApp : public CWinApp
  27. {
  28.   public:
  29.   BOOL InitInstance()
  30.   {
  31.   /*m_pMainWnd=new CWnd;
  32.     m_pMainWnd->CreateEx(0,AfxRegisterWndClass(CS_CLASSDC,0,::CreateSolidBrush(0xFF00FF),0),_T("AD-IHM" ),
  33.       WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX,CRect(0,0,300,300),0,0);
  34.     m_pMainWnd->ShowWindow(m_nCmdShow);*/
  35.   AfxMessageBox(_T("Fenetre 1" ), MB_OK);
  36.   m_pMainWnd = new Fenetre;
  37.   m_pMainWnd->CreateEx(0, AfxRegisterWndClass(CS_CLASSDC, 0, ::CreateSolidBrush(0xFF00FF), 0), _T("AD-IHM" ),
  38.    WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, CRect(0, 0, 300, 300), 0, 0);
  39.   m_pMainWnd->ShowWindow(m_nCmdShow);
  40.   AfxMessageBox(_T("Fenetre 4" ), MB_OK);
  41.     return TRUE;
  42.   }
  43. };
  44. CTstApp NotreApp;


 
Merci beaucoup à Farian et surtout à tpierron de m'avoir aidé :)
Aller hop, c'est parti pour la prochaine étape !


---------------
Mon topic d'achat de DRAGON QUEST http://forum.hardware.fr/hfr/JeuxV [...] 1589_1.htm
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed