Merci ...
ça se compile maintenant ...
Il faudrait que j'arrive à bien assimiler ces notations baroques avec ces ^ ..
Bon je regarde ce que je peux faire de ce que vous m'avez appris et je vous tiens au courant.
Bonne soirée
Merci ...
ça se compile maintenant ...
Il faudrait que j'arrive à bien assimiler ces notations baroques avec ces ^ ..
Bon je regarde ce que je peux faire de ce que vous m'avez appris et je vous tiens au courant.
Bonne soirée
Ah! j'ai oublié de dire que pour que ça compile j'ai dû changer :
par :
Code : Sélectionner tout - Visualiser dans une fenêtre à part formulairesOuverts = gcnew Dictionary <int, Form2^>;
Mais pourquoi? et est ce correct?
Code : Sélectionner tout - Visualiser dans une fenêtre à part Dictionary <int, Form2^>^ formulairesOuverts = gcnew Dictionary <int, Form2^>;
A l'exécution, ça se plante sur :
avec le message :
Code : Sélectionner tout - Visualiser dans une fenêtre à part if(!formulairesOuverts->ContainsKey(clef))
An unhandled exception of type 'System.NullReferenceException' occurred in essai_forme.exe
Additional information: La référence d'objet n'est pas définie à une instance d'un objet.
Bonne soirée
A un caractère ^ du Nirvana.
formulairesOuverts doit être "nullptr" à ce moment là.
doit avoir été fait avant.
Code : Sélectionner tout - Visualiser dans une fenêtre à part formulairesOuverts = gcnew Dictionary<int, Form2^>;
Mais
le compilo n'en veut pas !!
Code : Sélectionner tout - Visualiser dans une fenêtre à part formulairesOuverts = gcnew Dictionary<int, Form2^>;
Il me jette avec ça :
error C2440: '=' : cannot convert from 'System::Collections::Generic:ictionary<TKey,TValue> ^' to 'System::Collections::Generic:ictionary<TKey,TValue> ^'
Et pour moi c'est comme si on me disait que 2 ne vaut pas 2 !!
Bonne soirée
>Et pour moi c'est comme si on me disait que 2 ne vaut pas 2 !!
Bin non, c'est un template.
C'est comme : "x+y=z+w quelque soit x,y,z et w" est là c'est faux.
Le message d'erreur doit indiquer les types effectifs pour TKey et TValue.
Il doit avoir au moins un type différent à gauche et à droite.
Merci ça marche
J'ai remplacé :
par :
Code : Sélectionner tout - Visualiser dans une fenêtre à part formulairesOuverts = gcnew Dictionary<int, Form2^>;
Code : Sélectionner tout - Visualiser dans une fenêtre à part formulairesOuverts = gcnew Dictionary<int, Form^>;
J'ai rajouté une Textbox dans Form1 pour afficher la clef de la fenêtre qui est fermée au moment de l'appel à Unregister et on récupère bien la clef
Merci mille fois à Médinoc et à vous !!!
Bonne journée ..
En remplaçant Form2 par Form, vous avez assoupli les règles de typage.
Il faut toujours faire ces assouplissements avec beaucoup de précaution car vous empêchez indirectement le compilateur de vous aidez.
Cet assouplissement n'est pertinent que si vous voulez insérer d'autres types de formulaires que Form2 dans le dictionnaire "formulairesOuverts".
Sinon, c'est plutôt le ou les types déduit(s) de chaque coté de l'expression avec le "=" en erreur qu'il faut vérifier et corriger.
Merci encore.
C'est corrigé, j'avais oublié le 2 dans la déclaration des variables.
Bonne journée.
Je rajoute une petite précision ...
Vu qu'à chaque ouverture d'une fenêtre fille, je lui donne un nom ... J'ai utilisé ce nom en guise de clef .. donc au lieu de passer un int je passe un String^ et cela fonctionne très bien !!
Merci encore pour votre aide précieuse
Bonne journée
Bonjour,
Je reviens sur ce sujet car j'ai un peu compliqué les choses et j'ai de nouveau un petit souci.
J'ai rajouté un bout de code dans l'application "fille" qui, à la fermeture d'une fenêtre fille, enregistre l'état d'un objet dans un fichier.
Cela fonctionne parfaitement quand je ferme la fenêtre fille sans fermer l'application mère.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 private: System::Void Form2_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) { if (Stop_flag == false) { e->Cancel = true; FormFille_Close();} } public: Void FormFille_Close() { etape = 0; timerArret->Enabled = true; } private: System::Void timerArret_Tick(System::Object^ sender, System::EventArgs^ e) { switch (etape) { case 0: etape++; Ecrire_Fichier(); break; case 1: timer->Enabled = false; Stop_flag =true; Close(); break; default: break; } }
J'ai déclaré FormFille_Close() public pour qu'à l'arrêt de l'application mère, je puisse fermer successivement les fenêtres filles encore ouvertes et sauver l'état de l'objet associé.
Donc à l'arrêt de l'application j'ai de nouveau un bout de code qui ferme les fenêtres les unes après les autres en appelant FormFille_Close()
J'utilise une méthode similaire à celle de la fermeture de la FormFille en utilisant un timer
J'ai volontairement mis 3 secondes entre la fermeture de chaque fenêtre pour vérifier le fonctionnement.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 private: System::Void timerArret_Tick(System::Object^ sender, System::EventArgs^ e) { switch (etape) { case 0: ProgressBar->Value++; j= 0; etape++; if (n_formulaires == 0) etape++; // si aucun formulaire ouvert on saute l'étape suivante break; case 1: // on ferme les formulaires ouverts ProgressBar->Value++; int k = 0; for each (KeyValuePair<String ^, Form2^> ^ formulaire in formulairesOuverts) { if (k==0) // on ferme le premier formulaire trouvé { SelectedItem = formulaire->Key; formulairesOuverts[SelectedItem]->FormFille_Close(); // Note : à chaque fermeture le formulaire est supprimé par lui-même par Unregister } k++; } j++; if (j == n_formulaires) etape++; // quand tous les formulaires sont fermés on passe à la dernière étape break; case 2: Stop_flag = true; timerArret->Enabled = false; Close(); break; default: break; } }
Chaque fenêtre est donc bien fermée au moment voulu, mais l'état n'est pas sauvegardé laissant supposer que l'écriture du fichier par l'application fille ne se fait pas
Je n'arrive pas à voir ce qui différencie une fermeture manuelle d'une fenêtre fille (cas qui fonctionne parfaitement ) d'une fermeture en fin d'application (cas qui ne fonctionne pas)
Il y a sûrement une façon plus simple et plus astucieuse pour faire ça, mais cela ne me dit pas pourquoi ça ne marche pas comme je voudrais !!
En fait je me rends compte qu'il y a beaucoup de choses que je ne sais pas ..
Par exemple quand je fais :
Est ce que FormFille_Close() va s'exécuter immédiatement c'est à dire avant que la boucle "for each" soit finie ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part formulairesOuverts[SelectedItem]->FormFille_Close();
A quel moment "Unregister" va être exécuté?
Merci à ceux qui pourront m'aider
Bonne journée
Euh! Bon !!
Désolé d'avoir déranger ceux qui m'auraient lu ...
J'ai enfin trouvé la raison à ce truc sur lequel je butte depuis plus de 24 heures
C'est juste que chaque fenêtre en se fermant réécrit le fichier tel qu'elle l'a reçu en y ajoutant les modifications de son propre objet ... du coup elle efface les modifications faites dans les objets attachés aux autres fenêtres ..
J'ai résolu le problème en relisant le fichier avant de l'écrire de façon à ce que chaque modification soit bien prise en compte.
Mais je reste preneur pour toute méthode plus simple pour faire ce genre de chose.
Bonne journée
>J'ai volontairement mis 3 secondes entre la fermeture de chaque fenêtre pour vérifier le fonctionnement.
Oui, mais c'est combien de secondes entre l'étape 0 et 1 dans les formulaires enfants ?
La différence de l'un, c'est qu'il arrête de thread principal du processus et donc arrête aussi les timers et les autres threads.
Je trouve que votre architecture est horriblement complexe avec toute ces actions asynchrones avec ces timers dans tous les coins.
Il y a une grosse faille dans votre algorithme, c'est l'endroit où ou vous faites "j++".
Vous faites cela juste après l'appel de "FormFille_Close", il faudrait le faire dans le Close de la fenêtre fille, donc via une fonction de callback vers le formulaire principal. (donc une architecture encore plus complexe et couplée)
Je suis extrêmement circonspect sur la nécessité de cette usine à gaz.
Vous nous donnez votre "solution" à une problème, mais vous ne nous donnez pas le but de tout cela, donc difficile de vous donnez LA solution pour implémenter votre fonctionnalité.
La concurrence sur l'accès au fichier, l'ordonnancement de la sérialisation, la maintenabilité en cas de changement de couche graphique, etc... sont des chose que votre solution vas bloquée.
Si vous découpez votre application entre la couche graphique avec ses formulaires, et une couche métier/données qui sera en charge de conserver les données et d'appliquer les règles métiers, vous aurez une application bien plus simple à faire évoluée.
Dans ce cas, la sérialisation des données (enregistre l'état d'un objet dans un fichier) sera bien plus simple, car la couche métier à tout les objets et peut les sérialisées quand il veut, et de manière ordonnée.
Bonjour Bacelar et merci encore une fois pour votre aide précieuse ...
Je pense effectivement à découper mon application en une couche métier/données et une couche graphique ... Il faudra que je le fasse tôt ou tard
J'ai longtemps programmé avec des systèmes temps réel multi-tâches et je savais faire ça très bien .. Mais c'était au siècle dernier
En C++/CLI, je suis nul donc j'y vais pas à pas ...
Pour vous expliquer ce que je veux faire, je prends un exemple simple:
Disons que mes objets sont des avions caractérisés par leur position, cap, vitesse, altitude, n°de vol, etc .... les objets sont sérializables et stockés dans un fichier...
Ils sont récupérés et stockés dans un dictionnaire dont la clef est le n°de vol
Ma Form1 permet de rajouter, modifier, supprimer des objets .... et de les visualiser dans une listview ...
en double cliquant un objet de la listview j'ouvre une fenêtre fille qui me donne accès à un avion avec lequel je peux jouer ...
En ouvrant plusieurs fenêtres je peux jouer avec plusieurs avions ...
Quand je ferme une fenêtre fille, je sauvegarde l'état de mon avion pour le retrouver la fois suivante ...
Et quand je ferme l'application je récupère l'état de chaque avion pour la prochaine cession.
Pour l'instant un avion est censé être immobile quand sa fenêtre est fermée...
Mais un jour ou l'autre je sais que j'aurais envie de le faire voler tout seul en background donc il me faudra bien cette couche métier/données ...
Bon dimanche
L'histoire de la solution mais pas le problème, tout ça, c'était pour le fait que vous attendiez après la fermeture de la fenêtre fille.
Mais l'exposé de votre but montre bien qu'une couche métier/donnée est indispensable.
A la fermeture de votre fenêtre fille, vous notifiez votre couche données sur les données directement, sans attendre.
Cette couche métier fera les actions nécessaires à la sauvegarde des données, de manière synchrone.
Je ne vois pas pourquoi ne pas faire cette sauvegarde de manière synchrone ?
Un simple Activate() sur le form devrait suffire. Il m'a fallu moins d'une minute pour trouver ça, en comptant la recherche Google!
Désolé, Le problème n'a jamais été au niveau de l' "Activate" .
Je n'aurais pas dû rouvrir un post qui était marqué "résolu" .. Je comprends très bien que vous n'avez pas le temps de relire un post depuis le début.
Le problème était de ne pas générer x fois la même fenêtre dans l'Activate, mais de lui redonner le Focus si elle existe déjà.
Grâce à Bacelar et vous même ce problème est résolu et je vous en remercie encore
Le second problème a été de sauvegarder l'état des fenêtres à la fermeture de l'application.
J'avais fait un truc qui marchait mais j'étais assez lucide pour me rendre compte que c'était tarabiscoté asynchrone et merdique ....
Bacelar m'en a fait la remarque, je m'y attendais !!
Depuis j'ai amélioré, j'ai viré les timers inutiles et rendu la fermeture synchrone en passant par "Unregister" ..
En ce moment j'étudie comment faire ça de façon plus propre en créant une couche métier ...
Donc je suis en train d'apprendre à faire des threads en C++/CLI ...
Le problème présent est résolu et grâce à Bacelar et vous même j'ai appris à manipuler les Dictionnary et leurs clefs
Merci encore
Bonne soirée
Medinoc a me semble-t-il donné la bonne solution , je n'ai pas trop pigé ton problème qui semble sacrément tarabiscoté et compliqué...
??
L'état des fenêtres ? Si tu sauvegardes un Handle de fenêtre à la fermeture de l'application il sera invalide par la suite on ne peut sauvegarder que les positions écran des fenêtres
Tout cela me semble compliqué
Ensuite encore une fois il ne faut pas gérer des threads inutilement ça va ralentir l'application
on est au moins 2
Je ne vois pas où est le problème à vouloir sauvegarder l'état complet d'une fenêtre au moment où on la ferme de façon à ce qu'elle s'ouvre dans le même état la fois suivante.
C'est tout ce que je voulais faire et je n'avais pas pensé à utiliser Unregister pour faire ça ... Maintenant cela marche nickel sans usine à gaz !!
Merci à tout le monde.
C'est clair que si c'est fait de manière synchrone, c'est bien plus simple.
Nous venons d'éradiquer une usine à gaz, next.
Partager