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

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++/CLI Discussion :

Appeler une fonction à partir d'un contrôle utilisateur


Sujet :

C++/CLI

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut Appeler une fonction à partir d'un contrôle utilisateur
    Bonjour à tous,

    J'ai enfin réussi à créer un contrôle utilisateur.

    Maintenant je butte sur un problème sûrement idiot ....

    Les boutons de mon contrôle font appel à des fonctions déclarées dans la Form principale et le compilo me dit :

    'ma_fonction'*: identificateur introuvable


    Pour mieux expliquer, j'ai écrit un petit exemple appelé "test_boutons" qui contient une Form Form1 et un contrôle utilisateur que j'ai appelé pupitre

    Le contrôle utilisateur est très simple, il contient :
    1- un numericUpDown pour sélectionner un appareil (une vanne dans ce cas)
    2- un bouton "Ouvrir"
    3 -un bouton "Fermer"



    Quand on sélectionne la vanne indexée i, si on appuie sur ouvrir on est censé ouvrir la vanne i.

    Les fonctions Ouvrir (int i) et Fermer (int i) sont déclarées dans Form1 car elles utilisent un port série qui est ouvert dans Form1.

    Voici le code

    pupitre.cpp

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #include "StdAfx.h"
    #include "pupitre.h"
    pupitre.h

    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    #pragma once
     
    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
     
     
    namespace test_boutons {
     
    	/// <summary>
    	/// Description résumée de pupitre
    	/// </summary>
    	public ref class pupitre : public System::Windows::Forms::UserControl
    	{
    	public:
    		pupitre(void)
    		{
    			InitializeComponent();
    			//
    			//TODO*: ajoutez ici le code du constructeur
    			//
    		}
     
    	protected:
    		/// <summary>
    		/// Nettoyage des ressources utilisées.
    		/// </summary>
    		~pupitre()
    		{
    			if (components)
    			{
    				delete components;
    			}
    		}
    	private: System::Windows::Forms::Button^  button1;
    	private: System::Windows::Forms::Button^  button2;
    	private: System::Windows::Forms::GroupBox^  groupBox1;
    	private: System::Windows::Forms::Label^  label1;
    	private: System::Windows::Forms::NumericUpDown^  numericUpDown1;
    	protected: 
     
    	private:
    		/// <summary>
    		/// Variable nécessaire au concepteur.
    		/// </summary>
    		System::ComponentModel::Container ^components;
     
    #pragma region Windows Form Designer generated code
    		/// <summary>
    		/// Méthode requise pour la prise en charge du concepteur - ne modifiez pas
    		/// le contenu de cette méthode avec l'éditeur de code.
    		/// </summary>
    		void InitializeComponent(void)
    		{
    			this->button1 = (gcnew System::Windows::Forms::Button());
    			this->button2 = (gcnew System::Windows::Forms::Button());
    			this->groupBox1 = (gcnew System::Windows::Forms::GroupBox());
    			this->label1 = (gcnew System::Windows::Forms::Label());
    			this->numericUpDown1 = (gcnew System::Windows::Forms::NumericUpDown());
    			this->groupBox1->SuspendLayout();
    			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->numericUpDown1))->BeginInit();
    			this->SuspendLayout();
    			// 
    			// button1
    			// 
    			this->button1->Location = System::Drawing::Point(151, 19);
    			this->button1->Name = L"button1";
    			this->button1->Size = System::Drawing::Size(75, 23);
    			this->button1->TabIndex = 0;
    			this->button1->Text = L"Ouvrir";
    			this->button1->UseVisualStyleBackColor = true;
    			this->button1->Click += gcnew System::EventHandler(this, &pupitre::button1_Click);
    			// 
    			// button2
    			// 
    			this->button2->Location = System::Drawing::Point(151, 57);
    			this->button2->Name = L"button2";
    			this->button2->Size = System::Drawing::Size(75, 23);
    			this->button2->TabIndex = 1;
    			this->button2->Text = L"Fermer";
    			this->button2->UseVisualStyleBackColor = true;
    			this->button2->Click += gcnew System::EventHandler(this, &pupitre::button2_Click);
    			// 
    			// groupBox1
    			// 
    			this->groupBox1->BackColor = System::Drawing::SystemColors::GradientInactiveCaption;
    			this->groupBox1->Controls->Add(this->label1);
    			this->groupBox1->Controls->Add(this->numericUpDown1);
    			this->groupBox1->Controls->Add(this->button1);
    			this->groupBox1->Controls->Add(this->button2);
    			this->groupBox1->Location = System::Drawing::Point(3, 3);
    			this->groupBox1->Name = L"groupBox1";
    			this->groupBox1->Size = System::Drawing::Size(237, 100);
    			this->groupBox1->TabIndex = 2;
    			this->groupBox1->TabStop = false;
    			this->groupBox1->Text = L"Commande vanne";
    			// 
    			// label1
    			// 
    			this->label1->AutoSize = true;
    			this->label1->Location = System::Drawing::Point(9, 41);
    			this->label1->Name = L"label1";
    			this->label1->Size = System::Drawing::Size(51, 13);
    			this->label1->TabIndex = 3;
    			this->label1->Text = L"Vanne n°";
    			// 
    			// numericUpDown1
    			// 
    			this->numericUpDown1->Location = System::Drawing::Point(66, 39);
    			this->numericUpDown1->Maximum = System::Decimal(gcnew cli::array< System::Int32 >(4) {20, 0, 0, 0});
    			this->numericUpDown1->Minimum = System::Decimal(gcnew cli::array< System::Int32 >(4) {1, 0, 0, 0});
    			this->numericUpDown1->Name = L"numericUpDown1";
    			this->numericUpDown1->Size = System::Drawing::Size(60, 20);
    			this->numericUpDown1->TabIndex = 2;
    			this->numericUpDown1->Value = System::Decimal(gcnew cli::array< System::Int32 >(4) {1, 0, 0, 0});
    			// 
    			// pupitre
    			// 
    			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
    			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
    			this->Controls->Add(this->groupBox1);
    			this->Name = L"pupitre";
    			this->Size = System::Drawing::Size(250, 111);
    			this->groupBox1->ResumeLayout(false);
    			this->groupBox1->PerformLayout();
    			(cli::safe_cast<System::ComponentModel::ISupportInitialize^  >(this->numericUpDown1))->EndInit();
    			this->ResumeLayout(false);
     
    		}
    #pragma endregion
     
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
    		{
    			 int i = safe_cast <int> (numericUpDown1->Value);
    			 Ouvrir (i);
    		}
     
    private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) 
    		{
    			 int i = safe_cast <int> (numericUpDown1->Value);
    			 Fermer (i);
    		}
     
     
    };
    }
    Form1.h

    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
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    #include "pupitre.h"
    #pragma once
     
     
    namespace test_boutons {
     
    	using namespace System;
    	using namespace System::ComponentModel;
    	using namespace System::Collections;
    	using namespace System::Windows::Forms;
    	using namespace System::Data;
    	using namespace System::Drawing;
     
    	/// <summary>
    	/// Description résumée de Form1
    	///
    	/// AVERTISSEMENT*: si vous modifiez le nom de cette classe, vous devrez modifier la
    	///          propriété 'Nom du fichier de ressources' de l'outil de compilation de ressource managée
    	///          pour tous les fichiers .resx dont dépend cette classe. Dans le cas contraire,
    	///          les concepteurs ne pourront pas interagir correctement avec les ressources
    	///          localisées associées à ce formulaire.
    	/// </summary>
    	public ref class Form1 : public System::Windows::Forms::Form
    	{
    	public:
    		Form1(void)
    		{
    			InitializeComponent();
    			//
    			//TODO*: ajoutez ici le code du constructeur
    			//
    		}
     
    	protected:
    		/// <summary>
    		/// Nettoyage des ressources utilisées.
    		/// </summary>
    		~Form1()
    		{
    			if (components)
    			{
    				delete components;
    			}
    		}
    	private: test_boutons::pupitre^  pupitre1;
     
     
    	private: System::ComponentModel::IContainer^  components;
    	protected: 
     
    	protected: 
     
    	protected: 
     
    	private:
    		/// <summary>
    		/// Variable nécessaire au concepteur.
    		/// </summary>
     
     
    #pragma region Windows Form Designer generated code
    		/// <summary>
    		/// Méthode requise pour la prise en charge du concepteur - ne modifiez pas
    		/// le contenu de cette méthode avec l'éditeur de code.
    		/// </summary>
    		void InitializeComponent(void)
    		{
    			this->pupitre1 = (gcnew test_boutons::pupitre());
    			this->SuspendLayout();
    			// 
    			// pupitre1
    			// 
    			this->pupitre1->Location = System::Drawing::Point(16, 12);
    			this->pupitre1->Name = L"pupitre1";
    			this->pupitre1->Size = System::Drawing::Size(250, 111);
    			this->pupitre1->TabIndex = 0;
    			// 
    			// Form1
    			// 
    			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
    			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
    			this->ClientSize = System::Drawing::Size(278, 227);
    			this->Controls->Add(this->pupitre1);
    			this->Name = L"Form1";
    			this->Text = L"Form1";
    			this->ResumeLayout(false);
     
    		}
    #pragma endregion
     
    		void Ouvrir (int i)
    			{
    				// mettre ici le code pour ouvrir la vanne i
    			}
     
    		void Fermer (int i)
    			{
    				// mettre ici le code pour fermer la vanne i
    			}
     
     
    	};
    }
    Le message d'erreur :

    error C3861: 'Ouvrir'*: identificateur introuvable
    error C3861: 'Fermer'*: identificateur introuvable
    J'ai essayé de mettre les fonctions ailleurs, de rajouter des include, rien à y faire ... C'est probablement tout bête mais ..

    Si je mets les deux lignes d'appel en commentaires ... ça compile nickel ...

    Et si j'appelle Ouvrir ou Fermer à partir d'un simple bouton positionné dans Form1 ... les fonctions marchent nickel ...

    Merci à ceux qui pourront m'aider

    Bonne soirée
    Jean-Louis

  2. #2
    Membre chevronné

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    426
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 426
    Par défaut
    Bonjours Jean-Louis,

    Il semble que ces deux fonction soient privées dans Form1, tu ne peut donc les appeler que depuis Form1.
    Essaye de les mettre en "public:" et de les appeler comme ça : "Form1::Ouvrir (i);" et "Form1::Fermer (i);" .

    dans pupitre.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
    		{
    			 int i = safe_cast <int> (numericUpDown1->Value);
    			 Form1::Ouvrir (i);
    		}
     
    private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) 
    		{
    			 int i = safe_cast <int> (numericUpDown1->Value);
    			 Form1::Fermer (i);
    		}
    et dans Form1.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	public:void Ouvrir (int i)
    			{
    				// mettre ici le code pour ouvrir la vanne i
    			}
     
    	public:void Fermer (int i)
    			{
    				// mettre ici le code pour fermer la vanne i
    			}
    Bertrand

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Citation Envoyé par bertry Voir le message
    Essaye de les mettre en "public:" et de les appeler comme ça : "Form1::Ouvrir (i);" et "Form1::Fermer (i);" .
    Bonsoir Bertrand,

    Merci, j'avais déjà essayé, mais ça ne marche pas ...

    Le compilo me dit :

    error C2653: 'Form1'*: n'est pas un nom de classe ni d'espace de noms


    J'ai aussi essayé de créer une classe vanne avec des méthodes Ouvrir() et Fermer()

    J'ai fait une liste de vannes déclarées dans Form1, je crois que le problème est là; il faudrait la déclarer ailleurs ou autrement mais où ou comment???

    Dans ce cas, les fonctions Ouvrir() et Fermer() sont reconnues mais pas la liste de vannes.

    Voici les bouts de codes :

    Dans Form1.h déclaration de la liste de vannes:

    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
    	public:
    		Form1(void)
    		{
    			InitializeComponent();
    			l_vannes = gcnew List<Vanne^>();
    ................
    ................
    ...........
    #pragma endregion
     
    	private:
            List<Vanne^>^ l_vannes;
     
     
    	public:void Ouvrir (int i)
    			{
    				// mettre ici le code pour ouvrir la vanne i
    			}
     
    	public:void Fermer (int i)
    			{
    				// mettre ici le code pour fermer la vanne i
    			}
    dans pupitre.h appels aux méthodes Ovrir() et Fermer()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
    		 {
    			 int i_vanne = safe_cast <int> (numericUpDown1->Value);
    			 l_vannes[i_vanne]->Ouvrir();
    		 }
    private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) 
    		 {
    			 int i_vanne = safe_cast <int> (numericUpDown1->Value);
    			 l_vannes[i_vanne]->Fermer();
    		 }
    Et le noyau du .h de la classe vanne :

    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
    #include "stdafx.h"
    using namespace System;
     
    ref class Vanne 
    {
    public :
    	Vanne()
    	{
    	}
    	void Ouvrir ()
    	{
    		// code pour ouvrir
    		return;
    	}
    	void Fermer ()
    	{
    		// code pour fermer
    		return;
    	}
    private:
    };
    Cela me paraît normal que la liste étant déclarée dans Form1.h on ne puisse y accéder au niveau de pupitre.h

    Où la déclarer ou comment faire pour la rendre accessible? That is the question?

    J'ai essayé des tas de choses, mais je ne comprends pas grand'chose à ces variables managées ...

    Bonne soirée.

  4. #4
    Membre chevronné

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    426
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 426
    Par défaut
    Euh... Une question bête :

    Tu as pensé à mettre : au début de "pupitre.h" après avoir mis les deux fonctions en "public"?
    ( Je dis ça parce que je ne le vois pas au début du fichier "pupitre.h" )

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Citation Envoyé par bertry Voir le message
    Euh... Une question bête :

    Tu as pensé à mettre : au début de "pupitre.h" après avoir mis les deux fonctions en "public"?
    ( Je dis ça parce que je ne le vois pas au début du fichier "pupitre.h" )
    Bonjour Bertrand,

    panel.h étant déjà inclus dans Form1.h, si j'inclus Form1.h dans panel.h le compilo tourne en rond et me jette avec un niveau d'inclusions trop grand

    J'ai lu un truc ici; ce n'est pas du C++/CLI , mais il se pourrait que l'idée soit la même!!
    Dès demain il faut que je me penche dessus ... L'utilisation d'un User Control n'a pas l'air triviale


    Je ne comprends pas cela ne fonctionne pas de la même façon qu'un contrôle classique comme un Button ou une Textbox, mais ce sont ces petits détails qui font les charmes de la programmation !!


    Bonne journée et merci

  6. #6
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    Bonjour.

    Vous avez des difficultés parce que votre design n'est pas correct. Il y a plusieurs façons de modéliser les choses, en voici une :

    Le code qui gère le port série doit se trouver dans une classe :

    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
    //------------------------------------------------------------------------
    // cserie.h
    //------------------------------------------------------------------------
    #ifndef CSERIE_H
    #define CSERIE_H
     
    ref class CSerie{
     
      public:
     
    	CSerie(){}
    	~CSerie(){}
     
    	bool InitPortSerie();
            bool ClosePortSerie();
     
    	bool OpenVanne(const int iVanne);
    	bool CloseVanne(const int iVanne);
     
      private:
     
            // mes variables, fonctions, etc...
    };
     
    #endif
    C'est bien pour la logique et la maintenance du code, et de plus cette classe pourra être utilisé dans un autre programme tel quelle.

    Ainsi vous pourriez déjà utiliser cette classe directement dans pupitre.h :

    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
    34
    35
    36
     
     
    ...
     
    public ref class pupitre : public System::Windows::Forms::UserControl
    	{
    	public:
    		pupitre(void)
    		{
    			InitializeComponent();
    			CSerie^ cserie = gcnew CSerie;
                            cserie->InitPortSerie();
    		}
                    ~pupitre()
                    {
                        cserie->ClosePortSerie();
                        ...
                    }
     
    ...
     
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
    		{
    			 int i = safe_cast <int> (numericUpDown1->Value);
    			 cserie->OpenVanne(i);
    		}
     
    private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) 
    		{
    			 int i = safe_cast <int> (numericUpDown1->Value);
    			 cserie->CloseVanne(i);
    		}
     
     
    };
    }
    Après je n'ai pas compris l'intérêt de faire une classe pupitre, alors que vous pouvez la designer directement dans la Form. Donc dans le cas où Form1 doit gérer la classe serie, Vous pouvez passez l'objet au constructeur de la classe pupitre :

    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
     
    ...
     
    public:
    		pupitre(CSerie^ cserie) : m_cserie(cserie)
    		{
    			InitializeComponent();
    			//
    			//TODO*: ajoutez ici le code du constructeur
    			//
    		}
     
    ...
     
    private: CSerie^ m_cserie;
     
    ...
     
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
    		 {
    			 int i = safe_cast <int> (numericUpDown1->Value);
    			 m_cserie->OpenVanne(i);
    		 }
    private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) 
    		 {
    			 int i = safe_cast <int> (numericUpDown1->Value);
    			 m_cserie->CloseVanne(i);
    		 }
    Vous aurez ici une référence supplémentaire. Peut-être un singleton serait tout aussi approprié, enfin tout dépends de l'ensemble de l'architecture de votre code et des objectifs sous-jacents.

    PS : lorsque vous avez une référence circulaire de classes qui doivent se connaître, vous pouvez utiliser la déclaration anticipée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public ref class Form1;
    public ref class pupitre;
     
    #include "Form1.h"
    #include "pupitre.h"
    J'ai déclaré les deux classes mais une seule suffirait ici.

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Merci Moldavi pour ces renseignements,

    Je débute avec C++/CLI et ne suis pas habitué à la POO.

    Au début j'ai cherché à apprendre comment utiliser les outils de Visual C++/CLI.

    Puis j'ai développé une application petit à petit en développant une IHM, puis en communiquant avec un port série, puis en gérant des tableaux et des images, des timers ...

    Il y a donc beaucoup de choses, ça marche mais c'est un plat de spaghetti.

    Tout est dans Form1.h et c'est une horreur ...
    Je voudrais donc maintenant la rendre plus propre.

    Mon objectif est surtout d'apprendre.

    Donc comme j'ai des "pupitres" (un peu plus compliqués que celui que j'ai présenté) qui sont dupliqués en plusieurs exemplaires sur l'IHM, j'ai pensé faire un Controle Utilisateur puisque Visual C++/CLI le propose ..

    L'utilisation de CU rend Form1 déjà beaucoup plus lisible

    Mais je pensais qu'un Contrôle Utilisateur fonctionnerait comme un contrôle ordinaire mais ce n'est pas le cas et je butte sur ce point..

    J'essaie pour l'instant de remettre en C++/CLI le petit bout de programme qui est ici histoire d'apprendre un peu plus.

    Sortir la partie "communication avec le port série" pour en faire une classe est aussi au programme. Mais là aussi mon manque d'expériences me fait butter sur certaines choses.

    Par exemple au démarrage, mon application cherche seule sur quel port sont connectés les appareils ...
    Donc J'ai une fonction dans Form1 qui teste le port COM1, puis COM2, ..... en parallèle il y a une ProgressBar et quand le port est trouvé une MessageBox qui alerte l'utilisateur ...
    Je n'arrive pas encore clairement à voir comment scinder ces tâches pour sortir une classe "Communication"

    Mais avec de la persévérance cela viendra ..

    Bonne soirée et merci encore ...

  8. #8
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 470
    Par défaut
    Un contrôle utilisateur fonctionne comme un contrôle standard.

    Pour pouvoir l'utiliser simplement, les contrôles standards déclarent de événements. Il faut faire de même pour les contrôles utilisateur.

    Pour que le contrôle soit réutilisable, il ne doit pas dépendre des WinForms qui l'inclus.
    Le plus simple est que votre contrôle déclare un évènement "ChangementEtatVanne" sur lequel votre formulaire s'abonnera.
    Lorsque les actions de l'utilisateur devront générer ce changement d'état, le contrôle génèrera cet évènement.

    http://msdn.microsoft.com/en-us/libr...2s(VS.80).aspx

    Le code du delegate de votre WinForm, abonné à cet évènement, sera libre d'appeler "Ouvrir_vanne" et "Fermer_vanne", car il fera partie de votre Winform.

  9. #9
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    Bonjour.

    De rien pour les conseils.

    Ce qui est un bon point, c'est que vous vous posez des questions : comment puis-je améliorer mon code et son architecture ?

    Il y a des thèses et des bouquins pour cela, mais c'est l'expérience qui vous permettra de prendre les bonnes décisions. Et aussi certains réflexes/habitudes qui font gagner du temps.

    Plus votre programme sera lourd/compliqué, plus vous remettrai en cause sa façon de le coder et de l'architecturer.

    Je vous conseille de lire les tutoriels de ce site sur l'architecture (MVC/3tiers/design pattern, etc...). Ceci vous donnera des éléments de réponse à certaines de vos questions. Et puis aussi, regardez le code des autres (open source/tuto), souvent, leurs façon de coder permet de progresser.

  10. #10
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    Bonjour.

    J'adhère à la proposition de bacelar pour les delegate/event, c'est une façon plus élégante et pratique de faire.

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Citation Envoyé par moldavi Voir le message
    Bonjour.

    J'adhère à la proposition de bacelar pour les delegate/event, c'est une façon plus élégante et pratique de faire.
    Bonjour,

    Moi aussi, c'est un peu pour ça que j'essaie de remettre en C++/CLI les quelques lignes qui sont ici

    Merci à Bacelar pour le renseignement et pour le lien sur le site de Microsoft.

    Je regarde ça de près.

    Bonne Journée

  12. #12
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    Bonjour.

    Cette article peut vous intéresser :

    http://freddyboy.developpez.com/dotnet/articles/events/

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Bonjour Moldavi, bonjour Bacelar,


    Je suis un peu obtus, je n'arrive pas à passer des exemples à mon cas.
    En plus les exemples sont en C++ ou C# et C++/CLI gueule parce qu'il manque des ^ ou des : ..

    Il y a plusieurs choses que je ne saisis pas :

    1- le delegate est bien déclaré et créé dans le code de la Form
    2- l'événement est bien créé dans le code du contrôle utilisateur

    J'essaie un truc le plus simple possible :

    Un User Control avec un seul et unique bouton (je sais, ce n'est pas très utile!!)
    Je voudrais qu'un click sur ce bouton provoque l'écriture du message "Bonjour" dans une textBox de la Form.


    J'ai créé mon Control User avec son bouton.

    Dans la Form, j'ai rajouté:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    	public delegate void MonDelegueEventHandler();
    
    	public ref class Form1 : public System::Windows::Forms::Form
    	{
    	public:
    		Form1(void)
    		{
    			InitializeComponent();
    Question: est ce bien comme cela qu'on le déclare et à cet endroit?


    Puis j'ai rajouté le contrôle:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    		void InitializeComponent(void)
    		{
    			this->Mon_Evenement += gcnew System::EventHandler(this, &Form1::Ecrire_Message);
    			this->textBox1 = (gcnew System::Windows::Forms::TextBox());
    Question: Est ce bien comme cela?

    Puis j'ai écrit la fonction pour écrire dans la textBox

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	private: void Ecrire_Message(System::Object^  sender, System::EventArgs^  e)
    		{
    			textBox1->Text = "Bonjour";
    		}
    Question: Faut il ce qu'il y a dans les parenthèses?

    Il y a encore le lien à faire entre l'évènement et le delegate par un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    event MonDelegueEventHandler ^ Mon_Evenement;
    Question : est ce comme cela et si oui où faut il le mettre?

    Le compilateur n'en veut pas

    Pouvez vous, svp, me dire si je suis presque bon ou complètement à côté de mes pompes ...

    Après il faudra que je regarde quoi faire dans le User Control

    Bonne journée

  14. #14
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Citation Envoyé par moldavi Voir le message
    Bonjour.

    Vous avez des difficultés parce que votre design n'est pas correct. Il y a plusieurs façons de modéliser les choses, en voici une :

    Le code qui gère le port série doit se trouver dans une classe :

    .....
    C'est bien pour la logique et la maintenance du code, et de plus cette classe pourra être utilisé dans un autre programme tel quelle.
    Bonjour Moldavi,

    J'avance sur deux fronts à la fois:
    1- d'un côté, je suis les conseils de Bacelar
    2- d'un autre je suis les vôtres en réorganisant la structure.

    J'ai donc créé une classe CCommunication pour gérer les communications avec le port série.

    Évidemment je voudrais que ma classe CCommunication ne soit pas exclusivement accessible de Form1 mais aussi à partir d'autres classes dans le projet.

    Comme je n'ai qu'un port série, théoriquement je n'ai pas besoin de créer une instance de la classe ...

    Et c'est là que ça coince

    Si je déclare les fonctions "static", je récupère le message d'erreur suivant:
    error C2227: la partie gauche de '->PortName' doit pointer vers un type class/struct/union/générique
    Si je ne crée pas d'instance de classe, je récupère le message d'erreur suivant:
    error C2275: 'TEST::CCommunication'*: utilisation non conforme de ce type comme expression
    Par contre si je crée une instance, cela marche nickel sauf que je ne peux utiliser mon port série qu'à partir de la classe où il a été instancié ...

    Donc je tourne en rond ...

    Voici une des fonctions :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    		public: int Ouvrir_Port (int i)
    		{
    			Port_Number = i;
    			SerialPort->  PortName = String::Concat ("COM",i);
    			try { SerialPort->Open (); }
    			catch (Exception^) {Port_Number = 0; }
    			return Port_Number;
    		}
    En créant une instance dans Form1 et en appelant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int j = cCommunication1->Ouvrir_Port (i);
    Cela marche nickel

    Mais voilà je ne veux pas instancier et je veux que ma classe soit accessible d'ailleurs !

    La réponse est probablement quelque part sur le forum, mais je n'arrive pas à la trouver

    Si vous savez comment je peux rendre les fonctions de ma classe CCommunication accessibles sans créer d'instance et sans les déclarer "static" ce serait sympa.



    Bonne journée

  15. #15
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    Bonjour.

    Vous avez plusieurs possibilités, et je vous donne deux exemples :

    -> Instanciez votre classe CCommunication dans Form1, puis passer en paramètre cet objet aux autres classes qui en ont besoin.

    -> Utilisez un singleton.

    Pour le singleton :

    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
    //--------------------------------------------------------------------------------------
    // ccommunication.h
    //--------------------------------------------------------------------------------------
    #ifndef CCOMMUNICATION_H
    #define CCOMMUNICATION_H
     
    ref class CCommunication sealed{
     
      public:
     
        static CCommunication^ GetCommunication(){ return m_cCommunication; }
     
        int Ouvrir_Port (int i){ return 0; }
     
      private:
     
        CCommunication(){}
     
        static CCommunication^ m_cCommunication = gcnew CCommunication;
    };
     
    #endif
    Ensuite pour utiliser la fonction Ouvrir_Port :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CCommunication::GetCommunication()->Ouvrir_Port(1);
    Il y a un tutorial sur ce site pour les singletons (en VB et C#). Mais l'idée est la même.

  16. #16
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Merci Moldavi pour cette très rapide réponse

    Je regarde cela ce soir dès que j'ai un peu de temps ...

  17. #17
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Bonsoir Moldavi

    Cela marche super sans difficulté

    J'avais un peu peur d'avoir des problèmes avec mon port série car j'avais construit ma classe dans un Class Component de Visual en utilisant son concepteur, donc en faisant glisser un port série de la boite à outils ...

    Après une petite analyse de ce que le concepteur a généré, j'ai tout refait moi même à l'intérieur de votre singleton et je peux communiquer via le port série sans instancier et à partir de plusieurs classes

    Maintenant je vais voir event et delegate, cela serait pas mal que mon singleton déclenche un évènement quand des data arrivent

    Bonne soirée

  18. #18
    Inactif  

    Homme Profil pro
    Ingénieur test de performance
    Inscrit en
    Décembre 2003
    Messages
    1 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur test de performance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 986
    Par défaut
    Bonsoir.

    N'oubliez pas le tag

    Pour les event/delegate, n'hésitez-pas à ouvrir une autre discussion, nous avons aussi les réponses...

  19. #19
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    243
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Janvier 2008
    Messages : 243
    Par défaut
    Merci, c'est fait et dès que je me remets aux events/delegates j'ouvre un autre fil même si j'y arrive seul; cela peut servir à d'autres.

    Bonne soirée

  20. #20
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 470
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 470
    Par défaut
    Désolé pour cet énorme retard. Je suis charrette.

    Voici un exemple de solution VS2010 contenant un projet contenant 2 User Control et un projet Winform les utilisant.

    Vous y verrez comment créer des User Control, y déclaré des events et comment les récupérer dans le formulaire les contenants.
    Fichiers attachés Fichiers attachés

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [Débutant] appeler une fonction à partir d'un répertoire
    Par miss_angel dans le forum Images
    Réponses: 2
    Dernier message: 01/11/2010, 23h39
  2. Réponses: 2
    Dernier message: 07/05/2010, 17h10
  3. Appeler une fonction à partir d'une autre fonction
    Par touta1 dans le forum Langage
    Réponses: 2
    Dernier message: 07/10/2009, 18h15
  4. Appeler une fonction à partir de son nom
    Par superpigeon dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 21/05/2008, 09h56
  5. Appel à une fonction à partir d'une chaine de caractères
    Par becks dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 19/09/2007, 12h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo