FAQ C++/CLI et VC++.NetConsultez toutes les FAQ

Nombre d'auteurs : 29, nombre de questions : 248, création le 22 février 2013 

 
OuvrirSommaireIntéraction du C++/CLI avec le framework .NetWinForms

Il faut dans un premier temps créer une nouvelle Winform :
Click droit sur le projet --> Add -- New Item --> UI --> Winforms Form.
Là, nommez-la comme bon vous semble, par exemple Form2. Visual Studio génère donc une nouvelle classe, et la winform est modifiable également à travers l'IDE.

Pour afficher cette nouvelle form, par exemple depuis un click sur un bouton de la première form, il faut inclure le Form2.h dans le fichier .h de notre première Form (Form1.h par défaut).

 
Sélectionnez

#include "Form2.h"

Ensuite dans l'événement du click sur le bouton (ou autre), il faut instancier la classe et appeler la méthode Show() sur l'objet créé.

 
Sélectionnez

Form2 ^maForm2 = gcnew Form2();
maForm2->Show();
 

Notez que la méthode Show() affiche la fenêtre simplement. On peut également utiliser ShowModal() pour qu'elle soit modale comme une boîte de dialogue.

Créé le 20 novembre 2007  par nico-pyright(c)

Lors de la réalisation d'applications, il peut être utile de montrer à l'utilisateur que le traitement demandé est en cours (et qu'il faut patienter).
Un bon moyen de réaliser ceci est de changer la forme du curseur, pendant la durée du traitement.
Pour ce faire, vous devez utiliser la Classe Cursors.

 
Sélectionnez

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
{
	// On passe le curseur en sablier
	Cursor = Cursors::WaitCursor;
	System::Threading::Thread::Sleep(4000);
	// On repasse le curseur en normal
	Cursor = Cursors::Arrow;
}
				

N'hésitez pas à vous reporter à la classe Cursors pour voir les types de curseurs disponibles et utilisables par votre application.

Créé le 9 mai 2006  par nico-pyright(c), abelman, Thomas Lebrun

Il faut tout d'abord gérer l'évènement FormClosing (depuis l'IDE ou par code).

 
Sélectionnez

this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &Form1::Form1_FormClosing);				
				

Ensuite, insérer ce petit bout de code dans notre classe, ce qui permet de détecter une tentative de fermeture de session en surchargeant la méthode de traitement des messages windows et en interceptant le message de fermeture de session.
Il ne reste plus qu'à l'annuler dans le FormClosing.

 
Sélectionnez

private : bool _systemShutdown; // a initialiser à false dans le constructeur
 
protected:virtual void WndProc(Message %m) override
{
	// Mise dans systemShutdown la présence du message fermeture Windows
	if (m.Msg == 0x11) // ou utiliser WM_QUERYENDSESSION de windows.h
		_systemShutdown = true;
	Form::WndProc(m);
}
 
private: System::Void Form1_FormClosing(System::Object^  sender, System::Windows::Forms::FormClosingEventArgs^  e) 
{
	//Si le message fermeture Windows a été envoyé, on l'annule !
	if (_systemShutdown)
	{
		e->Cancel = true; 
		_systemShutdown = false;
		MessageBox::Show("Fermeture de session windows annulée");
	}
}
				

Pour tester ce code, éxecutez le en dehors de l'IDE.

Créé le 9 mai 2006  par nico-pyright(c), swoög

On utilise le composant FolderBrowserDialog pour cela.

 
Sélectionnez

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
{
	folderBrowserDialog1->Description = "Choisissez votre répertoire";
	if (folderBrowserDialog1->ShowDialog(this) == System::Windows::Forms::DialogResult::OK)
	{
		MessageBox::Show(this, 
				"Vous aves choisi " + folderBrowserDialog1->SelectedPath,
				"Repertoire",
				MessageBoxButtons::OK,
				MessageBoxIcon::Information);
	}
}
				
Créé le 9 mai 2006  par nico-pyright(c), abelman

Le composant System::Windows::Form::OpenFileDialog permet à l'utilisateur de choisir interactivement un fichier afin d'y lire des données.
Créez une form et placez-y un bouton nommé button1, un composant RichTextBox nommé richTextBox1 et un composant OpenFileDialog nommé openFileDialog1.
Un clic sur le bouton1 permet de lire le fichier choisi et d'afficher son contenu dans le RichTextBox.

 
Sélectionnez

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
{
	// Titre
	openFileDialog1->Title = "Chargement";
	// Extension par défaut
	openFileDialog1->DefaultExt = "txt";
	// Filtre sur les fichiers
	openFileDialog1->Filter = "fichiers textes (*.txt)|*.txt|Tous les fichiers (*.*)|*.*";
	openFileDialog1->FilterIndex = 1;
	// Ouverture boite de dialogue OpenFile
	if (openFileDialog1->ShowDialog(this) == Windows::Forms::DialogResult::OK)
	{
		// On vide le TextBox
		richTextBox1->Text = String::Empty;
		// Ouverture du fichier sélectionné
		// son nom est dans openFileDialog1->FileName
		IO::StreamReader ^sr = gcnew IO::StreamReader(openFileDialog1->OpenFile(), System::Text::Encoding::Default);
		try
		{
			richTextBox1->Text = sr->ReadToEnd();
		}
		finally
		{
			if (sr!=nullptr)
				sr->Close();
		}
	}
}
				
Créé le 9 mai 2006  par nico-pyright(c), abelman

Le composant System::Windows::Form::SaveFileDialog permet à l'utilisateur de choisir interactivement un fichier afin d'y écrire des données.
Créez une form et placez-y un bouton nommé button1, un composant RichTextBox nommé richTextBox1 et un composant SaveFileDialog nommé saveFileDialog1.
Un clic sur le bouton1 permet de sauvegarder le contenu du RichTextBox vers le fichier choisi.

 
Sélectionnez

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
{
	// Demande de confirmation
	if (MessageBox::Show(this, 
			"Sauvegarder le document?",
			"Sauvegarde", 
			MessageBoxButtons::YesNo,
			MessageBoxIcon::Question) == Windows::Forms::DialogResult::No)
		return;
	// Sauvegarde du document
	saveFileDialog1->Title = "Sauvegarde";
	saveFileDialog1->DefaultExt = "txt";
	saveFileDialog1->Filter = "fichiers textes (*.txt)|*.txt|Tous les fichiers (*.*)|*.*";
	saveFileDialog1->FilterIndex = 1;
	// Ouverture boite de dialogue Enregistrer
	if (saveFileDialog1->ShowDialog(this) == Windows::Forms::DialogResult::OK)
	{
		// StreamWriter pour écrire dans le fichier sélectionné
		IO::StreamWriter ^sw = gcnew IO::StreamWriter(saveFileDialog1->OpenFile(), System::Text::Encoding::Default);
		try
		{
			for (int i=0; i<richTextBox1->Lines->Length; i++)
				sw->WriteLine(richTextBox1->Lines[i]);
		}
		finally
		{
			// Fermeture writer
			if (sw!=nullptr)
				sw->Close();
		}   
	}
}
				
Créé le 9 mai 2006  par nico-pyright(c), abelman

Afin de pouvoir communiquer à partir d'une form nouvellement ouverte vers la form créatrice vous devez passer la form créatrice à la nouvelle form.

 
Sélectionnez

//Dans Form1
public void TraitementForm1()
{
 
}
 
public void OuvertureForm2()
{
form2 ^maForm2 = gcnew form2();
maForm2->Owner = this;
maForm2->Show();
}
 
//Dans MaForm2
 
private void ButtonOk_Click(object sender, System.EventArgs e)
{
Form1 ^maForm1 = safe_cast<Form1 ^>(this->Owner);
maForm1->TraitementForm1();
}
...				
Créé le 9 mai 2006  par nico-pyright(c), dev01

Lorsqu'une winform 1 doit instancier une winform 2 qui doit connaitre la winform 1, on est obligé de faire un include de form1.h dans form2.h et inversement de form2.h dans form1.h.
Ceci amène à des références croisées qui provoquent des erreurs de compilation.

Imaginons que nous voulions faire une application qui ouvre une fenêtre qui possède un textBox et un bouton. Lors du click sur le bouton, on affiche une deuxième form qui possède elle aussi un bouton et un textBox (ça aurait pu être un label). On souhaite lors du clic sur le bouton de la deuxième form afficher la valeur saisie dans le textBox de la première form...

Voici comment on peut faire :
Dans la form1, je dépose le textBox1 et le bouton.
J'ajoute une nouvelle form, Form2 dans laquelle je mets le textbox et le bouton.

le but est de pouvoir lire la valeur saisie dans la Form1 depuis la Form2 sachant que c'est la form1 qui va créer la form2.
Donc, en toute logique, dans la form1, on va avoir à un endroit la création et l'affichage de la form2. Comme il faut que la form2 connaisse la form1, on va lui passer l'objet form1 (c'est à dire this), disons dans le constructeur :

 
Sélectionnez

Form2 ^maForm2 = gcnew Form2(this); 
maForm2->Show();

Dans la form2, on aura donc fatalement la récupération de la form1 dans le constructeur :

 
Sélectionnez

Form2(Form1 ^ laForm1) 
{ 
  Form1 ^currForm1 = laForm1; // sachant qu'en vrai, on aura currForm1 comme membre privé de la classe 
}

et au moment de récupérer la valeur, on aura un

 
Sélectionnez

textBox1->Text = currForm1->GetValeur();

GetValeur sera bien sur une méthode publique de form1 :

 
Sélectionnez

public: 
  String ^GetValeur() 
  { 
    return textBox1->Text; 
  }

Tant est si bien que dans Form1.h, on va devoir faire un

 
Sélectionnez

#include "Form2.h"

pour pouvoir instancier la form2
et dans la Form2.h, on va devoir faire un

 
Sélectionnez

#include "Form1.h"

pour pouvoir utiliser la form1.
Si vous essayez de compiler directement comme ca, il va y avoir une tripotée d'erreurs, la plus significative étant qu'il ne connait pas Form2, avec une erreur du genre dans Form1.h :

 
Sélectionnez

error C2143: erreur de syntaxe : absence de ';' avant '^'

sur la ligne Form2 ^ currForm2;

Comme on s'en doute, chaque fichier incluant l'autre, il y a des inclusions croisées qui empêchent la bonne compilation.
Pour que ceci compile, il faut plusieurs choses :

Déjà, déporter l'implémentation des méthodes des classes dans un .cpp (plus précisément, toutes celles qui utilisent des méthodes ou des attributs de Form2 pour le fichier form1.h et toutes celles qui utilisent des méthodes ou des attributs de Form1 pour form2.h).
Donc, il faut créer un fichier Form1.cpp (form2.cpp étant généré automatiquement lors de l'ajout d'une nouvelle form).
Dans mon .h, j'ai donc laissé la définition des méthodes :

 
Sélectionnez

private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e); 
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e);

et dans le .cpp, j'ai mis l'implémentation des méthodes :

 
Sélectionnez

include "StdAfx.h" 
#include "Form1.h" 
 
namespace testWinforms { 
 
System::Void Form1::Form1_Load(System::Object^ sender, System::EventArgs^ e) 
{ 
  currForm2 = gcnew Form2(this); 
} 
 
System::Void Form1::button1_Click(System::Object^ sender, System::EventArgs^ e) 
{ 
  currForm2->Show(); 
} 
 
}

NB : ne pas oublier le namespace, ni l'opérateur de résolution de portée. Idem dans form2.h

 
Sélectionnez

private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e);
 

et dans le Form2.cpp

 
Sélectionnez

System::Void Form2::button1_Click(System::Object^ sender, System::EventArgs^ e) 
{ 
  textBox1->Text = currForm1->GetValeur(); 
}
 

Voilà pour le premier point.

Il reste encore à faire une chose pour que ça compile, c'est faire une déclaration anticipée de Form1 dans le fichier Form2.h.
par exemple, en premier dans le namespace

 
Sélectionnez

ref class Form1;

il restera plus qu'à faire de même dans le fichier form1.h : déclarer form2 de cette facon :

 
Sélectionnez

ref class Form2;
 

Compilez maintenant, tout est ok
Téléchargez le programme d'exemple

Créé le 20 novembre 2007  par nico-pyright(c)

Suite à une action utilisateur sur le clavier, nous devons parfois effectuer un long traitement. Et nous souhaiterions que les actions clavier ne soient pas enregistrées pendant ce traitement. Cette suspension peut être implémentée de la façon suivante :

 
Sélectionnez

private: System::Void button1_KeyUp(System::Object^  sender, System::Windows::Forms::KeyEventArgs^  e) 
{
	//Exemple après l'appui de la touche "Enter"
	if (e->KeyCode == Keys::Enter)
	{
		//Arrêter la capture d'événements clavier sur le contrôle
		this->button1->KeyUp -= gcnew KeyEventHandler(this, &Form1::button1_KeyUp);
		//Traitements longs
 
		//Reprendre la capture d'événements clavier sur le contrôle
		this->button1->KeyUp += gcnew KeyEventHandler(this, &Form1::button1_KeyUp);
    }
}
				
Créé le 9 mai 2006  par nico-pyright(c), neguib

Dans le constructeur, il suffit d'ajouter :

 
Sélectionnez

this->SetStyle(ControlStyles::SupportsTransparentBackColor, true);
this->BackColor = Color::Transparent;
				

après le InitializeComponents().

Créé le 9 mai 2006  par nico-pyright(c), Ditch

Parfois, nous avons besoin de distinguer si la fenêtre de l'application a été fermée par un click sur un contrôle prévu à cet effet, ou si le click a été effectué sur la petite croix en haut à droite de la fenêtre.
Pour ce faire, nous avons juste besoin de savoir que l'évènement concerné est lié à l'Application et non au contrôle Form.
Voici un exemple de code test, qui vous démontrera que seule la fermeture intempestive de l'application déclenchera le MessageBox.

 
Sélectionnez

Application::ApplicationExit += gcnew EventHandler(this, &Form1::Application_Exit);
.....
private: void Application_Exit(System::Object^  sender, System::EventArgs^  e) 
{
	MessageBox::Show("Adieu vilaine brute");
}
 
private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
{
	Application::Exit();
}
				
Créé le 9 mai 2006  par nico-pyright(c), neguib

Ce code permet de créer 10 contrôles CheckBox, de les ajouter dans une Listbox et de gérer leur évènements CheckedChanged. Il nécessite la présence d'un contrôe ListBox nommé "listBox1" et d'un bouton nommé "BTN".

 
Sélectionnez

private: System::Void BTN_Click(System::Object^  sender, System::EventArgs^  e) 
{
    CheckBox^x; 
    for( int i = 1; i <= 10; i++)
    { 
        x = gcnew CheckBox();  
        x->Name = "Macase" + Convert::ToString(i);  
        // on place les CheckBox les unes en dessous des autres  
        x->Left = 10; 
        x->Top = i * 20; 
        x->Width = 150; 
        x->Text = "Je suis la case " + Convert::ToString(i);  
        // abonner CheckedChanged à la méthode commune MesCasesCheckedChanged  
        x->CheckedChanged += gcnew EventHandler(this, &Form1::MesCasesCheckedChanged);  
        // ajouter les checkbox à la ListBox  
        this->listBox1->Controls->Add(x);  
    } 
}
 
private : void MesCasesCheckedChanged(Object^ sender, EventArgs^ e) 
{  
    CheckBox^ cbx = safe_cast<CheckBox^>(sender);  
    MessageBox::Show("L'état de " + cbx->Name + " est " + (cbx->Checked ? "coché" : "non coché"));
}				
Créé le 9 mai 2006  par HULK, neguib

L'intérêt est ici de pouvoir modifier le NotifyIcon de notre application, afin par exemple d'y faire apparaître un texte en fonction de différentes circonstances.
L'exemple implémenté se contentera de faire ici défiler dans l'objet notifyIcon1 les secondes d'un objet DateTime. La procédure est assez simple puisqu'il s'agit de travailler via un objet Bitmap pour la modification et de le convertir en Icon à assigner à la propriété notifyIcon1->Icon.
Ce qu'il ne faut absolument pas oublier c'est de détruire au fur et à mesure les icônes en mémoire.
Le code suivant ne montre que l'essentiel, il vous faut bien sûr en plus déclarer et instancier les objets Font, Brush, Color et StringFormat souhaités.

 
Sélectionnez

private:
	/// <summary> Méthode privée timer1_Tick
	/// gestionnaire de l'évènement Tick de timer1
	/// </summary>
	System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e)
	{
		// lancer la mise à jour de notifyIcon1
		System::DateTime^ dt = System::DateTime::Now;
		this->UpdateNotiFyIcon((safe_cast<Int32^>(dt->Second))->ToString());
	}
	///<summary> Méthode privée UpdateNotiFyIcon
	/// chargée de mofifier notifyIcon1 dynamiquement
	///</summary>
	///<param name="texte">String : représente le texte à afficher
	///</param>
	void UpdateNotiFyIcon(String^ texte)
	{
		// redessiner iconBitmap
		this->UpdateBitmap(texte);
		// récupérer un icone à patir de iconBitmap
		System::Drawing::Icon^ newIcon = System::Drawing::Icon::FromHandle(this->iconBitmap->GetHicon());
		// assigner le nouvel icône de NotifyIcon1
		this->notifyIcon1->Icon = newIcon;
		// détruire en mémoire newIcon
		delete(newIcon);
	}
	///<summary>
	/// Méthode privée chargée de redessiner iconBitmap
	/// en fonction d'un texte à afficher
	///</summary>
	///<param name="texte">String : représentant le texte à afficher
	///</param>
	void UpdateBitmap(String^ texte)
	{
		Graphics^ g = Graphics::FromImage(this->iconBitmap);
		// assigner la couleur de fond
		g->Clear(this->iconBackColor);
		// dessiner le texte
		g->DrawString(texte, this->iconFont,this->iconForeBrush,14,14,this->iconStringFormat);
		// libérer l'objet Graphics
		delete(g);
	}
Créé le 27 mars 2007  par neguib, Aspic

Pour déplacer un contrôle, par exemple un PictureBox, nous avons besoin de 2 informations :

  • Le bouton gauche vient-il d'être enfoncé ?
  • La souris se déplace-t-elle en étant au dessus du PictureBox ?

Le Framework met justement à notre disposition 2 évènements nous permettant de connaître ces 2 informations :

  • MouseDown : notifie si le bouton de la souris a été enfoncé mais aussi à quel endroit;
  • MouseMove : notifie si la souris se déplace.

Il suffit donc de traiter le premier évènement afin de connaître la position d'origine du clic et dans le second évènement, nous repositionnerons le PictureBox par rapport au déplacement de la souris.

 
Sélectionnez

	/// <summary> Position de la souris lorsque le bouton a été enfoncé </summary>
	Point ^positionClick;
	/// <summary>
	/// Notifie si le bouton de la souris a été enfoncé sur le PictuBox
	/// </summary>
	private: System::Void pictureBox1_MouseDown(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e)
	{
		// Vérification si bouton gauche de la souris est bien enfoncé
		if (e->Button == System::Windows::Forms::MouseButtons::Left)
			positionClick = e->Location;
	}
	/// <summary>
	/// Notifie si le curseur se déplace au dessus du PictureBox
	/// </summary>
	private: System::Void pictureBox1_MouseMove(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e)
	{
		// Vérification si bouton gauche de la souris est bien enfoncé
		if (e->Button == System::Windows::Forms::MouseButtons::Left)
		{
			// Calcul de la nouvelle position du PictureBox
			pictureBox1->Location = Point(pictureBox1->Location.X + e->X - positionClick->X, 
					pictureBox1->Location.Y + e->Y - positionClick->Y);
		}
	}
      


A noter que ce code peut être utilisé pour les contrôles qui proposent les évènements MouseDown et MouseMove.

Créé le 27 mars 2007  par Jérôme Lambert, nico-pyright(c)

Lors du chargement d'une image dans un PictureBox avec la fonction Image::FromFile, le fichier sous-jascent se trouve en utilisation et donc non disponible jusqu'à la fermeture de l'application. Il est ainsi par exemple impossible de le supprimer.
Pour remédier à ce problème, il faut en conséquence pouvoir libérer la ressource du flux sur ce fichier.
Plusieurs solutions permettent d'atteindre cet objectif. Nous vous proposons ici celui de gérer directement le flux et notamment par l'implémentation de la méthode Image::FromStream.
L'exemple suivant charge une image via un FileStream, l'affecte à un PictureBox (appelé pictureBox1) par Image::FromStream, puis libère les ressources du flux (appelé photoStream) sur le fichier pour pouvoir le supprimer :

 
Sélectionnez

// Créer le FileStream sur le fichier monimage.jpg
FileStream ^photoStream = gcnew FileStream("C:\\monimage.jpg", FileMode::Open);
// affecter l'image à pictureBox1
pictureBox1->Image = Image::FromStream(photoStream);
// libérer les ressources
photoStream->Close();
// supprimer le fichier monimage.jpg
File::Delete("C:\\monimage.jpg");
Créé le 27 mars 2007  par doudouallemand, neguib, nico-pyright(c)

Lien : System.IO.FileStream
Lien : Image.FromStream

Cette erreur survient lorsqu'on essaie de déclarer un délégate, en s'inspirant sur la syntaxe C#.
Si on part de cette syntaxe, on aura tendance à arriver à :

 
Sélectionnez
delegate void MonDelegateHandler(String ^chaine);
void methodeX () 
{
	MonDelegateHandler ^monDelegate = gcnew MonDelegateHandler(&Form1::MethodeDuDelegate);
}
void MethodeDuDelegate(String ^ chaine)
{
}

Ceci est incorrect et produit l'erreur C3352.
La construction correcte est la suivante :

 
Sélectionnez
MonDelegateHandler ^monDelegate = gcnew MonDelegateHandler(this, &Form1::MethodeDuDelegate);
Créé le 20 novembre 2007  par nico-pyright(c)

Il peut arriver qu'on doive mettre à jour un contrôle, comme une barre de progression ou un textbox, lors d'un traitement de longue durée.
Ce traitement doit bien sûr être mis dans un thread pour éviter de bloquer l'application.
Cependant, on ne peut pas directement mettre à jour les contrôles depuis un thread, il faut passer par une méthode particulière. On utilisera un delegate et la méthode invoke.

Voici un exemple pour une barre de progression. Je déclare un délegate et une méthode qui s'occupe de faire avancer ma barre de progression :

 
Sélectionnez
	delegate void ProgressBarDelegateHandler();
	ProgressBarDelegateHandler ^ProgressBarDelegate;
	void MyUpdateProgressBar()
	{
		progressBar1->PerformStep();
	}

Dans le form_load ou dans le constructeur, on instancie le delegate :

 
Sélectionnez
ProgressBarDelegate = gcnew ProgressBarDelegateHandler(this, &Form1::MyUpdateProgressBar);

Et par exemple sur le click d'un bouton, on initialise la barre de progression et on démarre le thread qui ici, ne fait pas grand chose à part attendre une seconde à chaque itération :

 
Sélectionnez
	System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) 
	{
		this->progressBar1->Minimum = 0;
		this->progressBar1->Maximum = 10;
		this->progressBar1->Value = 0;
		this->progressBar1->Step = 1;
 
		Threading::Thread ^t = gcnew Threading::Thread(gcnew Threading::ThreadStart(this, &Form1::ExecuteLongTraitement));
		t->Start();
	}
 
	void ExecuteLongTraitement()
	{
		for (int i = 0; i < 10 ; i++)
		{
			System::Threading::Thread::Sleep(1000);
			this->Invoke(ProgressBarDelegate);
		}
	}
Créé le 9 juillet 2007  par nico-pyright(c)

Il suffit tout simplement de mettre à true la propriété TopMost de la fenêtre :

 
Sélectionnez
this->TopMost = true;
Créé le 9 octobre 2008  par Jérôme Lambert

L'objet application offre la possibilité de s'abonner à l'évènement ThreadException permettant d'être notifié lorsqu'un thread génère une exception non interceptée. Etant donné que la fenêtre est gérée par un thread, vous pourrez ainsi éviter tout "plantage" de votre application ou d'effectuer un traitement adapté avant la fermeture de votre application.

 
Sélectionnez
static void Application_ThreadException(Object ^sender, System::Threading::ThreadExceptionEventArgs ^e)
{
	System::Windows::Forms::MessageBox::Show("L'exeption générée est : " + e->Exception->Message);
}
 
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
	// Enabling Windows XP visual effects before any controls are created
	Application::EnableVisualStyles();
	Application::SetCompatibleTextRenderingDefault(false); 
 
	Application::ThreadException += gcnew System::Threading::ThreadExceptionEventHandler(Application_ThreadException);
 
	// Create the main window and run it
	Application::Run(gcnew Form1());
	return 0;
}
Créé le 4 septembre 2007  par Jérôme Lambert, nico-pyright(c)

La classe Graphics possède une méthode MeasureString permettant de connaître la taille exacte d'une chaîne de caractères en fonction de la Font utilisée :

 
Sélectionnez
System::Drawing::Graphics ^g = textBox1->CreateGraphics();
System::Drawing::SizeF ^objSizeF = g->MeasureString(textBox1->Text, textBox1->Font);
MessageBox::Show(String::Format("Votre texte '{0}' a une longueur de {1} pixels.", textBox1->Text, objSizeF->Width));
Créé le 9 octobre 2008  par Jérôme Lambert, nico-pyright(c)

Lien : System.Graphics.MeasureString

On pourra utiliser la reflexion pour savoir si un type est de type Form.

 
Sélectionnez
List<Form ^> ^ ListerForms()
{
	List<Form ^> ^ resultat = gcnew List<Form ^> ();
	Reflection::Assembly ^a = System::Reflection::Assembly::GetAssembly(GetType());
	for each (Type ^t in a->GetTypes())
	{
		if (Form::typeid->IsAssignableFrom(t))
		{
			Form ^f = (Form ^)Activator::CreateInstance(t);
			resultat->Add(f);
		}
	}
	return resultat;
}
Créé le 9 octobre 2008  par nico-pyright(c), Aspic

il faut mettre en préambule l'attribut KeyPreview de la form à true, pour dire que la form doit traiter tous les événements clavier en premier et ensuite surcharger le KeyDown de la form.
Exemple pour faire un raccourci CTRL+M :

 
Sélectionnez
System::Void Form1_KeyDown(System::Object^  sender, System::Windows::Forms::KeyEventArgs^  e) 
{
    if (e->Control && e->KeyCode == Keys::M)
    {
        MessageBox::Show("Control + M");
    }
}
Créé le 9 octobre 2008  par nico-pyright(c)

Il est facile de fermer un formulaire en fondu. Il suffit de jouer sur l'opacité de la form :

 
Sélectionnez
for (double dblOpacity = 1; dblOpacity > 0; dblOpacity += -0.05)
{
	Opacity = dblOpacity;
	//laisse le formulaire se recolorer
	Refresh();
	//crée un délai
	System::Threading::Thread::Sleep(50);
}
Close();
Créé le 9 octobre 2008  par nico-pyright(c), jpjp507

Le binding bidirectionnel consiste à "associer" une propriété de classe à un controle de Formulaire.
Par exemple, j'ai un textbox sur ma form qui est associé à une chaine (String) dans ma classe. Toute modification de ce textbox entraine automatiquement une modification de ma chaine. Inversement, toute modification de cette chaine en code, implique une répercution visuelle sur la valeur du textbox.

Le principe est d'utiliser l'interface INotifyPropertyChanged. L'appel de l'événement PropertyChanged permet d'informer que la valeur a changé et automatiquement répercuter ce changement.

Tout d'abord, la form doit implémenter INotifyPropertyChanged

 
Sélectionnez
public ref class Form1 : public System::Windows::Forms::Form, INotifyPropertyChanged

Ceci implique de définir l'événement suivant

 
Sélectionnez
virtual event PropertyChangedEventHandler ^PropertyChanged;

Il nous faut ensuite une propriété de type String. C'est cette propriété qui sera bindée à notre TextBox :

 
Sélectionnez
private: 
  String ^_chaine; 
public: 
  property String ^Chaine 
  { 
    String ^ get() { return _chaine; } 
    void set(String ^value)  
    {  
      if (value != _chaine) 
      { 
        _chaine = value; 
        NotifyPropertyChanged("Chaine"); 
      } 
    } 
  }

On note l'appel à la méthode NotifyPropertyChanged pour indiquer une changement de valeur.

 
Sélectionnez
private: 
  void NotifyPropertyChanged(String ^info) 
  { 
    PropertyChanged(this, gcnew PropertyChangedEventArgs(info)); 
  }

La méthode NotifyPropertyChanged appelle l'événement PropertyChanged pour signaler le changement afin qu'il soit répercuté à tous les endroits où le binding est effectué.

Ne pas oublier de définir le binding, au plus tot, dans le form_load par exemple :

 
Sélectionnez
textBox1->DataBindings->Add("Text", this, "Chaine");
Créé le 9 octobre 2008  par nico-pyright(c)

Pour faire ceci, il faut déjà disposer d'un projet Console. Pour changer son projet en un projet console, il faut ouvrir les propriétés du projet, dans Linker -> System, il faut régler le subsystem à Console.
Ensuite il faut appeler :

 
Sélectionnez
AttachConsole( ATTACH_PARENT_PROCESS );

Pour le permettre, il faudra inclure windows.h :

 
Sélectionnez
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

De manière classique, on pourra afficher une form ainsi :

 
Sélectionnez
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault( false );
Application::Run(gcnew testConsoleWinform::Form1());

Tout appel à Console::WriteLine sera désormais écrit dans la console.

Créé le 9 octobre 2008  par nico-pyright(c)
  

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 © 2006-2007 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.