If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

Working multiple forms using Visual C++ 2008

Hi There, how are you?

I'm currently trying to work with more than one form, but I didn't succeed yet. What I need is quite simple: Once the program runs, a small form appears first asking "what would you like to do" with corresponding buttons for each option. Each button loads a new different form for a different task. So basically I need to open and close forms, also having two forms loaded at the same time (pop-up style) would be great for certain purposes.

Ok, one step at a time: My biggest problem is that I can't find a way to make the form RETURN a value when it closes.

My idea is that depending on what the user chooses at the first form, it returns an specific value. For example, Form 1 has button1, button2 and button3. If uses clicks button2, it closes and returns 2.

Sounds simple but I've been having a hell of a hard time trying to figure it out! Any ideas?

I know it may sound simple, but although I've searched already, I still haven't figured how to do it properly. I'm currently using VC++ 2008 and my project is a Windows Forms Application. Any help will be greatly appreciated!

Re: Working multiple forms using Visual C++ 2008

Ok, so here we go...

Originally Posted by fernando306

My idea is that depending on what the user chooses at the first form, it returns an specific value. For example, Form 1 has button1, button2 and button3. If uses clicks button2, it closes and returns 2.

Sounds simple but I've been having a hell of a hard time trying to figure it out! Any ideas?

Admittedly, that idea of yours, which is pretty similar to how, e.g., the MessageBox class is used, feels quite natural, but unfortunately isn't feasible: Your main form (the one created as Form1 by the IDE) must not return at all while your app is running, since closing (which is equivalent to returning from) the main form would shut down your app. (Actually that implies that something like that could be done with a non-primary form, but that's not what we're discussing here.)

A feasible approach would be to open secondary forms from inside the Click event handlers of your buttons placed on Form1. Perhaps something like this, given you have a buttonA on your Form1 that shall open an instance of an (existing) FormA class when clicked. This is the potential buttonAClick handler:

Code:

// Function header syntax based on the assumption that this is in a separate implementation .cpp file
void Form1::buttonA_Click(Object ^sender, EventArgs ^e)
{
FormA ^formA = gcnew FormA;
// Optionally put some initial data into some public FormA member variables
// Assuming FormA is meant to be modal (to be discussed later):
if (formA->ShowDialog(this) == Windows::Forms::DialogResult::OK) {
// Optionally read some user-input data out of public FormA member variables...
// ... and do whatever you want to be done when the user clicked Ok
}
}

And equivalently for buttonB and FormB, buttonC and FormC etc...

Just a rough outline, details still depending on scenario details I don't know.

HTH

Last edited by Eri523; September 27th, 2012 at 10:21 PM.

I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

Re: Working multiple forms using Visual C++ 2008

Hi Eri523! Thanks a lot for your time and consideration. Last night I played a lot with it, but this aren't very clear yet. So, before I post what coded, could you please let me know if my assumptions reading your code are correct?

Code:

//Here I must have #include "FormA.h"
// Function header syntax based on the assumption that this is in a separate implementation .cpp file
//This is function is called when the user clicks the ButtonA on Form 1
void Form1::buttonA_Click(Object ^sender, EventArgs ^e)
{
//If ButtonA was clicked, FormA must pop-up. So line bellow creates new formA object
FormA ^formA = gcnew FormA;
// Optionally put some initial data into some public FormA member variables
// Assuming FormA is meant to be modal (to be discussed later):
//Nothing happens until formA closes, so this function stays halted here meanwhile
if (formA->ShowDialog(this) == Windows::Forms::DialogResult::OK) {
//This part of the code only runs after formA has been closed so the "if" condition can be evaluated.
//If user pushes OK, any code here will execute
// Optionally read some user-input data out of public FormA member variables...
// ... and do whatever you want to be done when the user clicked Ok
}
}

Well, for last night, my objective was to pop-up another form and exchange data between them. However I've been having trouble with the "data direction". I could successfully send data from Form1 to Form2, but I did not succeed sending data from Form2 to Form1.

"Form1 sees a public class on Form2, but Form2 won't see a public class on Form1".

Here is what I did:

1) Created a new Windows Forms Project called "multiple_forms3" - THIRD ATTEMPT
2) Added a new form to the project, called "Form2", similar to the original "Form1"
3) Added #include "Form2.h" to the file stdafx.h.
4) On Form1.h, I've added the following:

It works great, but I still can't figure out a way that I could add the same functionality to the Form2. I mean, I still haven't figured out a way to make Form2 "SEE" Form1. Is there anyway to do that?

Another very important thing is: I need to write a program that is "3 in 1", so a first form must appear asking which one of the three options must be opened. A sort of "Program Menu". So according to the chosen option, the current form closes and a new one, that is the real program, opens. How can I manage to CLOSE the first form and open another one?

I sense that the answer is on the .cpp file:

Code:

#include "stdafx.h"
#include "Form1.h"
using namespace multiple_forms3;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Enabling Windows XP visual effects before any controls are created
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Create the main window and run it
Application::Run(gcnew Form1());
/*
My intention is to make the Form1 return a certain value (But How?), so we can have
an "if" condition right here that would open a new Form according to the value returned by Form1.
*/
return 0;
}

Is there any how to "force" a Form to return a value? Would that be the correct approach for what I'm trying to accomplish?

I'm sorry I'm so confused about the "flow" of the program. I've been programming for microcontrollers for years and they always run on closed loops, it's very different, so I'm still struggling a bit to understand how this kind of windows program flows.

Re: Working multiple forms using Visual C++ 2008

The annotations you added to my code snippet from post #2 are mostly correct. Some remarks, however...

Originally Posted by fernando306

Code:

//Here I must have #include "FormA.h"

Correct. And if this is in a separate implementation file, i.e. Form1.cpp, you'd need to #include "Form1.h" as well.

Code:

// Assuming FormA is meant to be modal (to be discussed later):
//Nothing happens until formA closes, so this function stays halted here meanwhile
if (formA->ShowDialog(this) == Windows::Forms::DialogResult::OK) {
//This part of the code only runs after formA has been closed so the "if" condition can be evaluated.
//If user pushes OK, any code here will execute
// Optionally read some user-input data out of public FormA member variables...
// ... and do whatever you want to be done when the user clicked Ok
}

Yes, but only if formA actually is shown modally, i.e. by calling ShowDialog() on it rather than Show(). "Nothing happens until formA closes, so this function stays halted here meanwhile" is just what "modal" means. And only modal forms can return a value to their caller via ShowDialog() (Show() is of return type void, i.e. it doesn't return anything).

[...] However I've been having trouble with the "data direction". I could successfully send data from Form1 to Form2, but I did not succeed sending data from Form2 to Form1.

"Form1 sees a public class on Form2, but Form2 won't see a public class on Form1".

To keep things simple you should strive for a design with only one active part in the data exchange between the two forms in such a scenario. That usually would be the "caller" form, here the Form1 instance. Not anything you may want to do can actually be done that way, though.

The key to resolve this issue is the this you pass as the parameter in formA->ShowDialog(this). It represents the calling form, and from the viewpoint of formA it will turn up again as the value of its Owner property. The property is of type Form ^ and you'll probably want to access members of Form1 that you defined yourself rather than inheriting them from System::Windows::Forms::Form, so in order to do so you'll need to cast it to Form1 ^. (I'd recommend a safe_cast for this purpose. It's computationally expensive, but you'll most likely not do that in performance-sensitive parts of your code, so its advantages will probably outweigh its drawbacks.)

Here is what I did:

1) Created a new Windows Forms Project called "multiple_forms3" - THIRD ATTEMPT

That's not uncommon, actually. Even experienced developers like me sometimes do that, particularly when experimenting with new techniques. And as long as it's about small toy projects, it doesn't really hurt anyway...

3) Added #include "Form2.h" to the file stdafx.h.

That works, but you shouldn't do it. Better place these #includes in the source files that need to access the entities declared/defined inside the .h file. Stdafx.h is meant to include common stuff that is used in wide parts of large projects. Touching its contents at all in small projects hardly gains you anything and has the disadvantage of hiding the actual includes from your eyes, thereby diminishing your sense of what your source files actually do access.

4) On Form1.h, I've added the following:

[...]

As already mentioned above, modeless (which means non-modal) forms don't return anything from their Show() call. So if you want something to be returned that way, you'll need modal forms. OTOH there's hardly ever a reason to make a modal form variable a member of the calling form class (which does make perfect sense in some scenarios for modeless forms). In most cases it's most adequate to make modal forms local variables of the functions showing them.

5) On Form2.h, I've added the following:

[...]

That's basically what property accessors do and not actually a bad idea. However, if that's what you actually want, it's probably better to actually implement it as a property to make your design clearer. OTOH, accessing it as a plain data field (member variable) would be more efficient and simpler (though not actuallly really ".NETish").

Another very important thing is: I need to write a program that is "3 in 1", so a first form must appear asking which one of the three options must be opened. A sort of "Program Menu". So according to the chosen option, the current form closes and a new one, that is the real program, opens. How can I manage to CLOSE the first form and open another one?

Closing the start-up form without actually shutting down the application can be done but would unnecessarily pretty much complicate things in your scenario as I understand it. And yes, that would involve modifying the main() function, but that's actually required in rather few cases. In my own Windows Forms apps, I have ever touched the IDE-generated main() perhaps three or so times, out of some dozens of apps.

In your scenario it's probably much more straightforward to leave the main form open and simply make it invisible.

In fact, the questions you ask aren't really of the uncommon kind. There have been a bunch of more or less related threads in the past, discussing interaction and data exchange between forms. Unfortunately the forum search feature, which would greatly simplify finding the related threads, still seems to be broken. But chances are that any thread with the word "forms" in its title is somewhat related. I even remember one thread discussing a scenario that seems to be quite similar to yours, with a start-up form intended to be used as a start-up menu for a game.

Last edited by Eri523; October 2nd, 2012 at 07:09 PM.

I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

Re: Working multiple forms using Visual C++ 2008

Hello Eri523!

Thank you so much! Your answers helped a lot, especially this one:

To keep things simple you should strive for a design with only one active part in the data excange between the two forms in such a scenario. That usually would be the "caller" form, here the Form1 instance. Not anything you may want to do can actually be done that way, though.

The key to resolve this issue is the this you pass as the parameter in formA->ShowDialog(this). It represents the calling form, and from the viewpoint of formA it will turn up again as the value of its Owner property. The property is of type Form ^ and you'll probably want to access members of Form1 that you defined yourself rather than inheriting them from System::Windows::Forms::Form, so in order to do so you'll need to cast it to Form1 ^. (I'd recommend a safe_cast for this purpose. It's computationally expensive, but you'll most likely not do that in performance-sensitive parts of your code, so its advantages will probably outweigh its drawbacks.)

I'm teaching myself VC++ and your certainly saved me of a lot of frustration and headaches!

Re: Working multiple forms using Visual C++ 2008

A related question
I have a modeless dialog (called FileStack) which has to pass a processed list of files to Form1 for display. To be thread safe can I call Form1 directly from a modeless form (is this direct access legal? Don't get any "cross thread" exceptions so I think it's Ok) or do I need to put a call on the message queue of Form1? Only way I have found to do this is:

Re: Working multiple forms using Visual C++ 2008

The code snippets you posted look unsuspicious, however, of course, they don't really reveal much.

As a rule of thumb I think it can be assumed that as long as you remain within the System and System::Windows::Forms namespaces with your activities, you're at least mostly safe from multithreading issues. Note, however, that there's at least one item I know of, offered in the Forms Designer's toolbox, that does not belong to this domain: the BackgroundWorker, which resides inside the System::ComponentModel namespace and, by its nature, may rise mutithreading issues.

Actually, multithreading in a form-to-form interaction scenario would be rather counterproductive in most cases anyway, since any GUI activity needs to pe performed within the main/GUI thread exclusively. Failure to observe this rule is what leads to these cross-thread activity exceptions, and there's no sign of it in what you posted.

What you need to be cautious of, though, is provoking an infinite event recursion, like it can be, obviously, caused by modifying a text box' contents from inside the TextChanged handler of the very same text box. (You can do things like this, but you need to be really careful to make sure you only cause finite recursion.) But this sort of bug has the advantage of usually manifesting itself rather immediately, unlike multitreading issues, wich, under adverse conditions, may lurk for months or even longer and then sneak up behind you...

I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

Re: Working multiple forms using Visual C++ 2008

How did you know I am using backgroundWorker? and you are not wrong about the difficulties however:-

My tree view has pre-defined root nodes. My method sorts file names into the root nodes according to type. Another method then builds a composite image and passes it back to Form1 for display/save. I use a backgroundWorker to display the image files because it takes a few seconds to display each image when I select a file so scrolling through the list of files is otherwise too slow. I put the file processing in the background worker and display the resulting bitmaps from b/w completed event. If the selected file has changed in this time it then starts over. Is there a way of achieving this without using threads?

BTW I used a method of accessing Form1 which uses a "this" pointer passed from form1 during instantiation. I later changed the form1 access method to the "correct"(???) method using the Parent/ParentForm property and it stopped working in bizarre way!
The original calling method which works:-

Re: Working multiple forms using Visual C++ 2008

Originally Posted by RogerD

How did you know I am using backgroundWorker? [...]

I didn't. ... I just mentioned some common gotchas pertaining to multithreading, and involvement of the BackgroundWorker in a Windows Forms multithreading scenario is quite natural, as it has been specifcally designed for that.

My tree view has pre-defined root nodes. My method sorts file names into the root nodes according to type. Another method then builds a composite image and passes it back to Form1 for display/save. I use a backgroundWorker to display the image files because it takes a few seconds to display each image when I select a file so scrolling through the list of files is otherwise too slow. I put the file processing in the background worker and display the resulting bitmaps from b/w completed event. If the selected file has changed in this time it then starts over. Is there a way of achieving this without using threads?

That definitely sounds like one of the scenarios that multithreading was made for. And using the BackgroundWorker's events basically is safe, because calls to the event handlers are marshalled to the GUI thread internally by that class. However, there are some hidden gotchas still remaining. One of the major ones is object handles passed between the threads and than accesing the respecive object (or objects directly or indirecly referenced by it) concurrently from both sides of the inter-thread border. This kind of object passing specifically includes the parameter passed to BackgroundWorker::RunWorkerAsync(Object ^) and any parameters passed to methods called from the worker thread that lead to invocation of the event handlers on the host thread side (even though the calls themselves are safely marshalled internally!). IMO one of the safest ways to overcome problems of this kind is the use of "fire and forget" objects for message passing between threads. The basic idea behind that is allocating and settig up the object on the sender side, but then never accessing it again from there after it has been passed. And the easiest way to ensure that is to simply not keep a handle to the object on the sender side.

I already have written about that in an earlier thread, but, uh, that forum search... (while (!ForumSearch->IsRepaired()) ;)

BTW I used a method of accessing Form1 which uses a "this" pointer passed from form1 during instantiation. I later changed the form1 access method to the "correct"(???) method using the Parent/ParentForm property and it stopped working in bizarre way!
The original calling method which works:-

[...]

Using "Owner" instead of parent/parentform seems to work but I am not very clear about what the difference in these three properties.

Passing this from the owner form as a c'tor parameter to the owned form is an idiom that's definitely safe, but passing this to Show() (or ShowDialog()) is what much more matches the original .NET Framework design. As has been mentioned and as you've seen, this parameter turns up again as the Owner property of the owned form. AFAICT the ParentForm and Parent properties are there just because Form is derived from ContainerConrol and Control, respecively, and are of no actual practical use in a form.

I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

I was out of touch for a while and when I came back noticed the site had had a face lift but was dismayed to find the find broken! I thought it was because I am using a new PC in a new house/country but see from your comment that's not it. Should I be telling somebody about it and whom?
Thanks for the help.
RD.

Re: Working multiple forms using Visual C++ 2008

Except that I'd still use the Owner property for this (certainly not the only way of doing it, but it is proven to be reliable to me), the snippet looks uncritical. ... except when the function gets called in the context of a worker thread. The String object itself is immutable and as such perfectly thread-safe, but querying the form's caption is not: Although it doesn't modify the observable state of the form, it belongs to the GUI manipulation category: It internally results in a WM_GETTEXT message being sent to the underlying native window object.

Therefore, when called in a worker thread context, the property getter must be Invoke()d, like this:

I didn't actually test the snippet, but not applying any cast to Owner is not a typo: Owner is of type Form ^, and we're using a property that Form1 inherits from that base class, so no cast is required. (This difference doesn't look spectacular in this example, but it may be big-time helpful if Form1.h isn't accessible from here.)

Originally Posted by RogerD

I was out of touch for a while and when I came back noticed the site had had a face lift but was dismayed to find the find broken! I thought it was because I am using a new PC in a new house/country but see from your comment that's not it. Should I be telling somebody about it and whom?

There's a huge thread about the forum software update in the Feedback section, and the search issue is one of the major ones discussed there. Of course you may report there, but you probably wouldn't be telling anyone anything new (it may add some pressure, though). IIRC there also have been workaroundssuggested for the search issue, but I never was successful applying them (I may simply have done it wrong, though).

Last edited by Eri523; October 10th, 2012 at 05:00 PM.

I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

Re: Working multiple forms using Visual C++ 2008

So then welcome to CodeGuru, but if you've not yet made a choice of programming language, the CodeGuru forum section you posted in is a relatively poor choice: The C++/CLI discussed here, which is quite different from the "real" (AKA native) C++, is a niche programming language used rather rarely, and not quite first pick for beginners.

For starters you can have a look at the book FAQ. Some of them are suitible for beginners, but don't ask me about details; I'm rather uninformed about current beginner's books myself.

* The Perfect Platform for Game Developers: Android
Developing rich, high performance Android games from the ground up is a daunting task. Intel has provided Android developers with a number of tools that can be leveraged by Android game developers.

* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.