Hi,
I have a two FORM's suppose FORM1 and FORM2. I have a textbox and a button in FORM1 when that button is clicked it shows up FORM2 which i have already done. In FORM2 there are strings in a grid which can be selected by the user then all the strings which the user has selected in FORM2 gridview should be shown up in FORM1 textbox.
Here's is where the problem occurs when i want to show up FORM2 from FORM1 i have included FORM2.h in FORM1. Now when i want to send the strings from FORM2 to FORM1 i should be including FORM1.h in FORM2 right which cant be done i hope. Now how to access the FORM1 textbox text property and put the text over there.
Loading
VulpesPosted Dec 26, 2011, 5:35 AM
// Form1.h
#include "Form2.h"
namespace MyApp
{
public ref class Form1 : Form
{
// ...
internal: System::Void SetTextBox(String ^text) // add this internal method to set textbox
{
textBox1->Text = text;
}
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
Form2^ f2 = gcnew Form2(this); // pass reference to Form1 to Form2
f2->Show();
}
};
}
// Form2.h
namespace MyApp
{
ref class Form1; // forward reference to Form1
public ref class Form2 : Form
{
private: Form1^ f1;
public : Form2(Form1^ f1) // constructor accepts a parameter of type Form1
{
InitializeComponent();
this->f1 = f1;
}
// definition only for this method
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e);
};
}
// Form2.cpp
#include "StdAfx.h"
#include "Form1.h" // already includes Form2.h
// implementation of eventhandler in Form2.h which now has class definition for Form1
System::Void MyApp::Form2::button1_Click(System::Object^ sender, System::EventArgs^ e)
{
f1->SetTextBox(this->textBox1->Text); // using a textbox rather than a DGV for illustration
}
Sam HobbsPosted Dec 28, 2011, 8:12 AM
The other thread I was referring to is How to read from console window in visual studio?
Sam HobbsPosted Dec 28, 2011, 8:00 AM
Karthik AgarwalPosted Dec 28, 2011, 7:56 AM
And if it comes to my requirement
I have a textbox and a button in form1 and a gridview and a button in form2.
when the button in form1 is clicked i want to show up form2, but still form1 should also be shown at the same time. i will load strings in gridview of form2 when it is getting loaded. when the user selects the strings in the gridview and click's the button (where fomr2 should expire) then i should concatenate the strings and show up in the form1 textbox but the form1 should still be there until and unless it is closed.
Sam HobbsPosted Dec 28, 2011, 6:20 AM
Karthik, I really get the impression that you just want to ignore me. I spent time creating a reply in another thread and you ignored that too. Note that most of the code I posted is involved with doing something that your code is doing except I am showing a cleaner way of doing it.
Before I explain that, it will really help if we had clarification of what you need to do. You have two forms and you want to transfer data from the first to the second, then show the second form. You need to show the second form and keep it active while the first form is still shown, correct? What do you need done with the second form when the data is to be transferred to the first form? Should the second form continue to be shown after the data is transferred? I think that issue has not been made clear. In my code the second form is hidden, giving the appearance that the form has been closed, and then the first form takes the data from the second form. And yes, my code does do the transfer of data from the second back to the first using the FormClosing event.
Note that in Karthik's code, a static object is used for an instance of the second form. In the Karthik's code that I see, it appears that the data will be transferred from the first form to the second form only once; is that what is needed? To do it just once? I see that a new instance of the second form will be created each time the button in the first form is clicked, yet only the first one will be used.
What do you want the first form to do while the second form is being shown? Do you need both of them to be used at once? If so then note that the first form will not be able to send any more data to the second form after the first time. If that is what you need done, then it seems likely to me that it would be much easier to just show the second form modallly using ShowDialog instead of modelessly with Show.
I think Vulpes's initial suggestion did not work because it violates my suggestion that Form2 should not know about Form1.
Karthik AgarwalPosted Dec 27, 2011, 11:33 PM
Sam HobbsPosted Dec 27, 2011, 4:42 PM
I did say that I am unclear about the requirement. I intended to look at this more. I have already spent time on this; much more time than you have spent looking at what I have provided for you.
If my code does not help you then please explain why so I can understand what you need. You can easily create a VS 2008 project from my code.
Karthik AgarwalPosted Dec 27, 2011, 8:30 AM
Sam HobbsPosted Dec 27, 2011, 8:23 AM
The FormClosing does not transfer data. I think most of the code that actually transfers the data is just the few lines that I did post already; the code for making a property in Form2. I am surprised that you are having difficulty; perhaps I totally misunderstand the requirements. If I understand then the solution is very easy.
My code does a little extra. As I said, it creates only one instance of Form2 and simply shows and hides it. Most of the code that I added to the generated code in my project is for doing that.
I have had another one of those nights when I cannot get to sleep. It is past 5 AM in the morning for me and I have not been to sleep yet. So I probably will not look at this or be able to reply for a while.
Karthik AgarwalPosted Dec 27, 2011, 6:45 AM
VulpesPosted Dec 27, 2011, 6:34 AM
If you have time, I'd still try the 'custom event' approach which is an easier and more OO approach than forms maintaining mutual references to each other, particularly in C++/CLI.
I think Sam's solution also uses an event - in his case the built-in FormClosing event - to trigger the transfer of the text to Form1.
Karthik AgarwalPosted Dec 27, 2011, 5:33 AM
VulpesPosted Dec 27, 2011, 5:08 AM
Karthik AgarwalPosted Dec 27, 2011, 12:46 AM
//form1.h
#include "form2.h"
public ref class form1 : public System::Windows::Forms::Form
{
private:
static form2 ^ dlg;
private: System::Void SID_btn_Click(System::Object^ sender, System::EventArgs^ e) {
dlg = gcnew form2(this);
if(dlg->btn_open)
{
dlg->btn_open = false;
dlg->Sid_text_dataGridView->ColumnCount = 1;
for(int k = 0; k < (NewLanguageData->All_SID_List->Count - 1); k++)
{ dlg->Sid_text_dataGridView->Rows->Add(NewLanguageData->All_SID_List[k]);
}
dlg->Show();
}
}
}
//form2.h
namespace gfx_viewer_win32
{
ref class fomr1;//forward reference as you said
void add_sids(String ^ str, form1 ^ f1);//function
public:
static String ^ str;
static bool btn_open = true;
form1 ^ f1;
public:
form2(form1 ^ f1)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
this->f1 = f1;
}
private: System::Void Add_Sid_btn_Click(System::Object^ sender, System::EventArgs^ e)
{
add_sids(str, f1);//function call
}
}
//form2.cpp
#include "StdAfx.h"
#include "form1.h"
using namespace gfx_viewer_win32;
void form2::add_sids(String ^ s, form1 ^ f1)
{
f1->SetTextBox(s);
}
Sam HobbsPosted Dec 26, 2011, 3:41 PM
String^ get() {return textBox1->Text;};
void set(String ^value) {textBox1->Text = value;};
}
Sam HobbsPosted Dec 26, 2011, 3:08 PM
In this sample, Form2 has two functions; SetText and GetText. Note that Form2 does not "know" about Form1. Do they do what you need? The following are in Form2:
textBox1->Text = s;
}
String^ GetText() {
return textBox1->Text;
}
Form2 is just the form, as created by VS, with a textbox added and the functions shown above added. Everything else is done in Form1. Form1 calls GetText and SetText.
VulpesPosted Dec 26, 2011, 11:35 AM
// Form1.h
#include "Form2.h"
namespace MyApp
{
public ref class Form1 : Form
{
// ...
private:
System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
Form2^ f2 = gcnew Form2(); // no need to pass any references
f2->StringTransfer += gcnew StringTransferHandler(this, &Form1::Form1_StringTransfer); // wire up eventhandler
f2->Show();
}
// add this handler
void Form1_StringTransfer(String^ str)
{
textBox1->Text = str;
}
};
}
// Form2.h
namespace MyApp
{
public delegate void StringTransferHandler(String^ str); // delegate needed for event
public ref class Form2 : Form
{
public:
event StringTransferHandler^ StringTransfer; // declare event
private:
System::Void Add_Sid_btn_Click(System::Object^ sender, System::EventArgs^ e)
{
gfx_viewer_win32::gfx_sid_text_grid_view::add_sids(str); // pass the string to the function
}
void add_sid(String ^ str)
{
StringTransfer(str); // fire the event
}
};
}
VulpesPosted Dec 26, 2011, 9:56 AM
then it definitely knows about all the members of the Form1 class and all the members of the Form2 class.
Also by including the forward reference to Form1 in Form2, then this enables you to define the member variable f1 of type Form1 and pass it in via Form2's constructor. Form2.cpp therefore knows about f1 as well.
So, I don't understand why it's not working. My 'model' of it works fine and it's something I've done hundreds of times before.
I also don't understand how your modification can work as f1 is a parameter of type FORM2 rather than FORM1:
Karthik AgarwalPosted Dec 26, 2011, 9:24 AM
// the name needs to be fully qualified with the namespace and class name
If i change it this way it's working. If i do as you said it is saying that f1 is not defined, i think that is because form2.cpp doesn't know about form2.h right?
VulpesPosted Dec 26, 2011, 9:18 AM
// the name needs to be fully qualified with the namespace and class name
Karthik AgarwalPosted Dec 26, 2011, 8:46 AM
Karthik AgarwalPosted Dec 26, 2011, 7:50 AM
//form2.h
private: System::Void Add_Sid_btn_Click(System::Object^ sender, System::EventArgs^ e) {
//processed the string
gfx_viewer_win32::gfx_sid_text_grid_view::add_sids(str); // passing the string to the funciton
}
//form2.cpp
void add_sid(String ^ s)
{
f1->SetTextBox(s);
}
but this is showing up some compilation errors as follows:
error C2227: left of '->SetTextBox' must point to class/struct/union/generic type
error C2065: 'f1' : undeclared identifier
What should i do in order to get this compiled.
I think the second error says that f1 instance itself is not declared.
Karthik AgarwalPosted Dec 26, 2011, 7:01 AM
VulpesPosted Dec 26, 2011, 6:09 AM
As you're fighting the way that Visual Studio does things (i.e. putting all the code in the header files), I tend to prefer the latter approach myself as it causes least disruption.
Karthik AgarwalPosted Dec 26, 2011, 6:00 AM
Karthik AgarwalPosted Dec 26, 2011, 3:59 AM
Sam HobbsPosted Dec 25, 2011, 4:05 AM
You did not specify whether form2 is being shown modally (using ShowDialog) or modelessly (using Show). I assume it is modeless (ShowDialog) since this problem would be easier.
Form2 should not access form1's textbox. That is not good design.
A better design would be for the data to exist in a document; a class designed for just the data. Then both forms could put data in the document and get data from it. A good design is one in which the UI is the UI but not the container of the data.
In Visual C++ there is something called the Microsoft Foundation Classes (MFC). It emphasizes a Document/View Architecture. In the opinion of many developers, the Document/View Architecture is over-emphasized. It is good in that MFC applications are initially created with an application, a document and a view. MFC applications typically have a separate class for the main window, but that is not relevant here. Typically the header file for the application class would be included first, then the document, then the view. So the application (header file) would not know about the document and view. The document (header file) would not know about the view. The view would do what it needs to do to put data into the document and get data from the document. It is all quite complicated; it is possible for the application to put data into the document or the view and you are already getting bored with this. The important thing is that the MFC classes have an extensive framework for the communication requirements you are exploring. In MFC, the document would just call a function when the data changes and then MFC would internally give each view (form/window) a chance to update using the new data.
The MFC Document/View Architecture is more complicated than what you need, but the foundation has value. In the .Net world there is the DAL, BLL and UI, which is (at least somewhat) an evolution of what has been done in the past. Your requirements (I hope you do not mind me saying) are quite humble in comparison but I hope these points help inspire a solution.
VulpesPosted Dec 24, 2011, 5:37 AM
What you have to do here is to:
1. Include a forward reference to Form1 in form2.h. You can then pass a reference to Form1 into Form2's constructor and save it in a member variable of Form2.
2. Move the implementation of any eventhandlers or other methods which access members of Form1 out of form2.h and into form2.cpp. Just leave the definitions of these methods behind in form2.h.
3. Change form2.cpp so that it includes form1.h rather than form2.h. There is no need to include the latter because the former already includes it. The method implementations for Form2 will then have access to Form1's members and the application should compile.
Depending on what you're doing, you could also consider firing an event from Form2 which Form1 subscribes to (as it already has a reference to Form2). When the event is triggered, the eventhandler (in Form1) can then transfer the strings.
Karthik AgarwalPosted Dec 23, 2011, 4:47 AM