Visualizzazione post con etichetta CLR. Mostra tutti i post
Visualizzazione post con etichetta CLR. Mostra tutti i post

venerdì 22 agosto 2014

Puntatori ^ a una classe in CLI

Adesso creiamo dinamicamente una istanza di una classe, prima con i puntatori tradizionali e quindi con questi "handle".
#include "stdafx.h"

using namespace System;

class Classe{
public:
	int variabile;
	Classe(int parametro){
		variabile=parametro;
	}
	void stampa(){
		Console::WriteLine(variabile);
		Console::ReadLine();
	}
};

int main(){
	Classe * miaClasse=new Classe(1234);
	miaClasse->stampa();
}
1234




#include "stdafx.h"

using namespace System;

ref class Classe{
public:
	int variabile;
	Classe(int parametro){
		variabile=parametro;
	}
	void stampa(){
		Console::WriteLine(variabile);
		Console::ReadLine();
	}
};

int main(){
	Classe ^ miaClasse = gcnew Classe(1234);
	miaClasse->stampa();
}
1234


Ecco: con questi puntatori non si usa l'operatore di deindirizzamento *, ma si usa lo stesso il -> come per i puntatori tradizionali.
Inoltre la classe deve essere dichiarata ref.

Un nuovo tipo di puntatori in CLI (managed Heap)

Puntatore.
void main(){
	int numero=123;
	int * puntatore;
	puntatore=№
	cout << numero << endl;
	cout << *puntatore << endl;
	getchar();
} 
123
123




Puntatore a una classe:
#include "iostream"
using namespace std;
class Classe{
public:
	int variabile;

	Classe(int parametro){
		variabile=parametro;
	}
	
	void scrivi(){
		cout << "scrivo" << endl;
		getchar();
	}
};

void main(){
	Classe MiaClasse(234);
	Classe * Puntatore;
	Puntatore=&MiaClasse;
	Puntatore->scrivi();
	cout << Puntatore->variabile;
	getchar();
} 
scrivo

234



Vediamo di studiare quello strano tipo di puntatori...

Innanzitutto bisogna attivare il cosiddetto CLI.
Per farlo, devo aprire un progetto CLR.
Ecco: creo un puntatore "tradizionale":
// test1 CLR.cpp : file di progetto principale.

#include "stdafx.h"

using namespace System;

int main(array<System::String ^> ^args)
{
    int numero=123;
	int * puntatore = №
	Console::WriteLine(numero);
	Console::WriteLine(*puntatore);
	Console::Read();
    return 0;
}
 
E funziona, regolarmente:
123
123


Adesso vediamo di creare quell'altro genere di puntatori...
#include "stdafx.h"

using namespace System;

int main()
{
	int numero=135;
    int ^ puntatore;
	puntatore=numero;
	Console::WriteLine(numero);
	Console::WriteLine(puntatore);
	Console::Read();
}
135
135


Sì.

Adesso confrontiamolo con il classico modo di creare un puntatore e assegnargli l'indirizzo di una variabile:
#include "stdafx.h"

using namespace System;

int main(){
	int numero=135;
    int ^ puntatore;
	puntatore=numero;

	int *puntatoreTrad;
	puntatoreTrad=№

	Console::WriteLine("Puntatore Handle");
	Console::WriteLine(numero);
	Console::WriteLine(puntatore);
	Console::WriteLine("");

	Console::WriteLine("Puntatore tradizionale");
	Console::WriteLine(numero);
	Console::WriteLine(*puntatoreTrad);
	Console::Read();
}
Puntatore Handle
135
135

Puntatore tradizionale
135
135


Sì, corrisponde perfettamente.

Adesso allochiamo dinamicamente la memoria:
#include "stdafx.h"

using namespace System;

int main(){
	int * puntatore=new int(123);

	int ^ puntatoreNuovo=gcnew int(123);

	Console::WriteLine(*puntatore);
	Console::ReadLine();
	Console::WriteLine(puntatoreNuovo);
	Console::ReadLine();
}
123

123


Sì: per allocare dinamicamente la memoria è necessario usare l'operatore gcnew.

giovedì 21 agosto 2014

System::Drawing::Size. Il form che cambia larghezza a ogni pressione sul button

Ed ecco il form che cambia larghezza alternativamente a ogni click del button:
 private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
    }
 private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    
     if(this->Size.Width<1000)
     {
      this->Size=System::Drawing::Size(1100,this->Size.Height);
     }
     else{
      this->Size=System::Drawing::Size(900,this->Size.Height);
     }
    
    }
 };

Aggiunta di un button e ridimensionamento del form

Ho inserito un button nel form.
Il codice, che viene fuori facendo doppio click sul button appena inserito, è scritto nel file Form1.h:
#pragma once

namespace MyCLRProject {

 using namespace System;
 using namespace System::ComponentModel;
 using namespace System::Collections;
 using namespace System::Windows::Forms;
 using namespace System::Data;
 using namespace System::Drawing;

 /// 
 /// Riepilogo per Form1
 /// 
 public ref class Form1 : public System::Windows::Forms::Form
 {
 public:
  Form1(void)
  {
   InitializeComponent();
   //
   //TODO: aggiungere qui il codice del costruttore.
   //
  }

 protected:
  /// 
  /// Liberare le risorse in uso.
  /// 
  ~Form1()
  {
   if (components)
   {
    delete components;
   }
  }
 private: System::Windows::Forms::Button^  button1;
 protected: 

 private:
  /// 
  /// Variabile di progettazione necessaria.
  /// 
  System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
  /// 
  /// Metodo necessario per il supporto della finestra di progettazione. Non modificare
  /// il contenuto del metodo con l'editor di codice.
  /// 
  void InitializeComponent(void)
  {
   this->button1 = (gcnew System::Windows::Forms::Button());
   this->SuspendLayout();
   // 
   // button1
   // 
   this->button1->Location = System::Drawing::Point(12, 12);
   this->button1->Name = L"button1";
   this->button1->Size = System::Drawing::Size(137, 93);
   this->button1->TabIndex = 0;
   this->button1->Text = L"button1";
   this->button1->UseVisualStyleBackColor = true;
   this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
   // 
   // Form1
   // 
   this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
   this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
   this->ClientSize = System::Drawing::Size(284, 261);
   this->Controls->Add(this->button1);
   this->Name = L"Form1";
   this->Text = L"Form1";
   this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
   this->ResumeLayout(false);

  }
#pragma endregion
 private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
    }
 private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    }
 };
}
Adesso trovo il modo di ridimensionare il form, cui va sempre fatto riferimento con this
 private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
     this->Size=System::Drawing::Size(1000,200 );
    }
 };
E funziona: alla pressione del button il form diventa largo e basso.

Progetto CLR in Visual C++

Adesso passo a progettare i form.
Non mi è molto chiaro il passaggio fra un'applicazione C++ e un'applicazione di Managed C++ e CLR.
Ho in testa una grande confusione.
Invece di impazzire, passo di palo in frasca e prendo per buona la sintassi del progetto CLR, per poi giungere in tempi successivi a riunire le cose.
A volte, anzi forse abbastanza spesso, conviene fare nell'apprendimento come fa il bambino nell'imparare a parlare.
Molto spesso, la nostra didattica inizia dall'ABC per poi andare per gradi, col risultato di fare dell'apprendimento una cosa noiosa e lenta, e poco funzionale, in quanto i concetti utili vengono imparati in un modo pesante e lento.
Conviene prima imparare come muoversi, quindi per la "grammatica" ci sarà tempo e modo di approfondire sulla base della naturale curiosità.



Ho un progetto CLS vuoto.




Quindi tramite il menu Progetto inserisco un Form, che chiamo Form1, e ottengo due files, Form1.cpp e Form1.h
Vediamo come sono composti:

Form1.cpp:
#include "Form1.h"






Form1.h:
#pragma once

namespace MyCLRProject {

 using namespace System;
 using namespace System::ComponentModel;
 using namespace System::Collections;
 using namespace System::Windows::Forms;
 using namespace System::Data;
 using namespace System::Drawing;

 /// 
 /// Riepilogo per Form1
 /// 
 public ref class Form1 : public System::Windows::Forms::Form
 {
 public:
  Form1(void)
  {
   InitializeComponent();
   //
   //TODO: aggiungere qui il codice del costruttore.
   //
  }

 protected:
  /// 
  /// Liberare le risorse in uso.
  /// 
  ~Form1()
  {
   if (components)
   {
    delete components;
   }
  }

 private:
  /// 
  /// Variabile di progettazione necessaria.
  /// 
  System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
  /// 
  /// Metodo necessario per il supporto della finestra di progettazione. Non modificare
  /// il contenuto del metodo con l'editor di codice.
  /// 
  void InitializeComponent(void)
  {
   this->SuspendLayout();
   // 
   // Form1
   // 
   this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
   this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
   this->ClientSize = System::Drawing::Size(284, 261);
   this->Name = L"Form1";
   this->Text = L"Form1";
   this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
   this->ResumeLayout(false);

  }
#pragma endregion
 private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
    }
 };
}


Bene.
Dunque il file Form1.h è il vero pezzo forte della situazione.
Ma se io faccio partire il programma ottengo un messaggio di errore:
1>------ Inizio compilazione: Progetto: MyCLRProject, Configurazione: Debug Win32 ------
1>  Form1.cpp
1>LINK : fatal error LNK1561: il punto d'ingresso deve essere definito
========== Compilazione: 0 completate, 1 non riuscite, 0 aggiornate, 0 ignorate ==========

Il punto di ingresso deve essere definito.

Nel progetto in Visual Basic ero abituato al fatto che il punto di ingresso fosse stabilito automaticamente: se non altrimenti specificato, partiva da Form1.
Invece qua bisogna definirlo specificamente.
E come si fa?

Intanto mettiamo un altro file, di tipo cpp:
#include "Form1.h"

using namespace MyCLRProject;

int main(){
 Form1 frm;
 frm.ShowDialog();
 return 0;
}
Qui il comportamento è praticamente lo stesso che sono abituato a vedere con il C++.
Data una classe Form1, viene istanziato un oggetto frm di classe Form1, e viene chiamato il suo metodo ShowDialog().
E appare il form vuoto (su una finestra di DOS).