Reputation: 801
I am starting out with C++\Cli so be gentle ;-)
It seems my issue is not uncommon, but I have not been able to find a solution that works for me, i.e. that I am able to implement.
I create an object "Genome" in say Form1_Load(), which I then want to provide with data in a child Form3 that is displayed via a tool strip menu. The object is provided with default system data in the constructor. This default data needs to be send to the child form as starting values in the input fields. After the user has accepted or modified this data, the object needs to be modified accordingly, after which the child form is closed.
My feeling is that this could be done by sending a pointer / handle to the object to the child form, making the data accessible.
Two issues: 1) basic, and 2) less basic.
1) The ToolstripMenuItem_Click action does not see the object created in Form1_Load.
2) I cannot seem to figure out how to pass (a handle) to the object with the ToolStripMenuItem_click event such that the object data is accessible in the child form.
Here's some code, I've stripped out as much as I can, I hope not too much (data hiding still to do):
Genome.h
ref class Genome
{
public:
int nTFA; // nr of Transcription Factor genes
int nFDE; // nr of Function cell Death genes
List<char>^ cString; // chromosome string
List<Gene^>^ cStruct; // structure consisting of a List with Gene objects
// methods
void loadIniGen(String^ iniFile); // load genome values from .ini file
Genome(void);
};
Genome.cpp (methods and lots of vars left out):
// constructor
Genome::Genome(void)
{
nTFA = 20; // nr of Transcription Factor genes
cString = gcnew List<char>();
cStruct = gcnew List<Gene^>();
}
// methods
Form1.h
#pragma endregion
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e)
{
Genome^ myGenome = gcnew Genome(); // instantiate genome object
}
private: System::Void genomeToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e)
{
Form3^ genomeForm = gcnew Form3(myGenome); // pass genome object to Form3 for data input
genomeForm->Text = "Genome settings";
genomeForm->StartPosition = FormStartPosition::CenterParent;
genomeForm->ShowDialog(); // modal
}
Thanks, Jan
Let's add the errors:
1) Gives this: error C2065: 'myGenome' : undeclared identifier
2) Gives this: error C3673: 'GenomeV2::Form3' : class does not have a copy-constructor (when I create the myGenome object in the ToolStrip action for testing)
To clarify, Form3 is designed, but has no functionality yet. Summary:
namespace GenomeV2 {
public ref class Form3 : public System::Windows::Forms::Form
{
public:
Form3(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~Form3()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::GroupBox^ groupBox1;
etc.
#pragma region Windows Form Designer generated code
etc.
#pragma endregion
private: System::Void Form3_Load(System::Object^ sender, System::EventArgs^ e)
{
numericUpDown1->Minimum = 10; // TFA nr of Transcription Factor genes
numericUpDown1->Maximum = 100;
etc.
}
Upvotes: 0
Views: 3112
Reputation: 801
Well, I've got it to work. Wheter it is the proper way, or if it can be improved, let me know!
1) Making myGenome
visible
I've put the variable declaration of Genome^ myGenome;
in the Form1
public declaration so it is visible to all actions, and then I create the object in the Form1_Load
event with myGenome = gcnew Genome();
This can later be changed to a List with Genome objects etc.
2) Passing data between forms back and forth
As advised by David I pass the (now visible) myGenome
object to Form3
when instantiating genomeForm with Form3^ genomeForm = gcnew Form3(myGenome);
. In the Form3
declaration I create a bGenome
object as a copy to take the data passed to the form. This is done in the constructor of Form3
(see code below). This bGenome
object contains a copy of the data of the myGenome
object of Form1, that I can use to populate the numericUpDown fields of Form3
, i.e. data transfer from Form1
to Form3
.
When all data is reviewed and modified where required, the form is closed with OK. At that moment, the data entered in the numericUpDown fields is copied back to the bGenome
object.
Since Form3
is #included
in Form1
(Form1
is not #included
in Form3
to avoid a circular reference), Form1
has access to bGenome
and the data of bGenome
can be copied back to myGenome
, closing the loop: data transfer from Form3
back to Form1
.
Note: I realise that Form1
could also read out the numericUpDown fields of Form3
as it has access, but I think it is cleaner to leave those in Form3
and only feed back one complete modified object bGenome
that can then be copied to myGenome
in one statement.
The object myGenome
was used to populate the input fields to the user and the (revised) input is fed back to myGenome
.
Code, all non-essentials stripped out.
Form1.h
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Genome^ myGenome;
etc.
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e)
{
myGenome = gcnew Genome(); // instantiate genome object
}
etc.
private: System::Void genomeToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e)
{
Form3^ genomeForm = gcnew Form3(myGenome); // pass genome object to Form3 for data input
genomeForm->ShowDialog(); // modal
myGenome->nTFA = genomeForm->bGenome->nTFA; // feed data from Form3 back to myGenome
textBox1->Text = myGenome->nTFA.ToString();
}
Form3.h
public ref class Form3 : public System::Windows::Forms::Form
{
public:
Genome^ bGenome;
public:
Form3(Genome^ aGenome)
{
InitializeComponent();
bGenome = gcnew Genome();
bGenome = aGenome;
}
etc.
private: System::Void Form3_Load(System::Object^ sender, System::EventArgs^ e)
{
numericUpDown1->Minimum = 10; // TFA nr of Transcription Factor genes
etc.
numericUpDown1->Value = bGenome->nTFA; // show the current Genome data in the input field
}
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
bGenome->nTFA = Convert::ToInt32(numericUpDown1->Value); // copy the (modified) input data back into the Genome object
etc.
this->DialogResult = System::Windows::Forms::DialogResult::OK;
this->Close();
}
I would like to be able to do away with the local copies (aGenome
and bGenome
) and access myGenome
directly from Form3
, so if there is a way to do that, let me know. I have a feeling this could be done by passing Form1
to Form3
and #include
Form1
in the .cpp version of Form3
(to avoid the circular ref.), but haven't tried that.
Upvotes: 0
Reputation: 27864
Error C2065: You need to store the myGenome
object somewhere that other methods can see it. Right now, it's a local variable within the Form1_Load
method. Make it a class field, and other methods within that object can see it.
ref class Genome
{
public:
Genome^ myGenome;
};
Error C3673: If you haven't already, add a constructor to Form3
that takes a Genome^
. Once that is done, and you've made the above change to the storage of myGenome
, then this line should compile.
"After the user has accepted or modified this data, the object needs to be modified accordingly, after which the child form is closed." You're passing the object itself, the child form will modify it directly. You shouldn't need to do any manipulation of myGenome
in genomeToolStripMenuItem_Click
after ShowDialog
returns.
Upvotes: 1