Hello World from Windows Forms, MK II.

Now that we've gotten our feet wet, it's time to try something a bit more complicated. We'll include a TextBox and a Button in this example, and also take a quick look at how we wire up events on actions like button clicks. I'm going to be skipping the explanation for code that we've already seen, and just concentrating on the new stuff. As always, scroll down for the sample download.


public ref class HelloWorldForm : public Form {

private:

Button ^button1;
TextBox ^textBox1;

Our HelloWorldForm now has two private members, button1 and textBox1. The UI elements they represent should be fairly obvious.

public:

HelloWorldForm() {

//allocate the private members

button1 = gcnew Button;

textBox1 = gcnew TextBox;

//Set up the Form

Text = "Hello Windows Forms World";

AutoScaleBaseSize = System::Drawing::Size(5, 13);

ClientSize = System::Drawing::Size(392, 117);

Here's the start of the default constructor, where all the basic setup for this form takes place. We gcnew our two private members, and we start setting up the form. I didn't go into this much last time, but what is happening here may not be totally obvious. Text, AutoScaleBaseSize, and the other members we'll see are members of HelloWorldForm's parent type, System::Windows::Forms::Form. To check out the various members of this type, head here.

Basically, we're setting up the form to have a client area size of 392x117 pixels. This is the default size, which is resizeable (based on whether or not you wish to allow this).

//Set the minimum form size to the client size + the height of the title bar

MinimumSize = System::Drawing::Size(392, (117 + SystemInformation::CaptionHeight));

//Set the default button on the Form

AcceptButton=button1;

It should be plainly obvious what the first line does. The reason we use the CaptionHeight property is that the height of the caption bar (where the program icon, maximize and close buttons, etc. are displayed) can change, depending especially on the font the user has set their default program title to. AcceptButton is the default button on a form that is pressed when the user hits the Enter key. (There's also a CancelButton, which is what is pressed when the user hits the Esc key.)

//Create the button

button1->Location = Point(256, 64);

button1->Size = System::Drawing::Size(120, 40);

button1->TabIndex = 2;

button1->Text = "Click Me!";

Here, we're simply populating our button1 with various useful attributes. The position for Location is based on the upper left-hand corner of the form (which is 0,0). In this case, our button's upper left-hand corner is 256 pixels right and 64 pixels down from that origin.

//Register the event handler

button1->Click += gcnew System::EventHandler(this, &HelloWorldForm::button1_Click);

This is probably the most interesting single line of code in this example. We're probably all aware that Windows is an event-based world. The program sits out there, and waits for user input - whether it be striking a key on the keyboard, or some form of mouse movement. So, we have to be able to wire up function calls to actions the user could perform. We call these actions events. System::Windows::Forms::Button::Click is one such event. (Actually, Click is an event that Button inherits from a common base class, System::Windows::Forms::Control.)

We can wire up a function to handle an event by using the += operator. This allows us to add multiple handlers to a single event (which can be very useful). We pass a this pointer and a pointer to the handler function to the EventHandler constructor, and add that temporary object to the Click event. Now, when the user clicks button1, the function button1_Click will be called! (The definition of this function is below.)

//Create the text box

textBox1->Text = "Hello Windows Forms World";

textBox1->TabIndex = 1;

textBox1->Size = System::Drawing::Size(360, 20);

textBox1->Location = Point(16, 24);

More property set-up, this time for our TextBox. The TabIndex property that you see here (and on button1) represents the order that the controls are focused on, with multiple presses of the Tab key. The focus starts on whatever control has TabIndex 1, and, with subsequent presses of Tab, will cycle through the different controls in order. When the last TabIndex is reached, we loop around to the first again.

//Add the controls to the form

Controls->Add(button1);

Controls->Add(textBox1);

}

Finally, we need to Add our two controls to HelloWorldForm's Controls. Up to this point, the controls have been merely classes that happened to be members of our form. When you hook them up by Adding them, they become visible, clickable objects inside the UI. This is important to remember, if you don't register your control, it simply won't be visible, and you'll be left wondering why.

protected:

void Dispose(bool disposing)

{

try {

MessageBox::Show("Disposed!");

} catch(Exception^ e) {}

Form::Dispose(disposing);

}

I wouldn't have shown you the Dispose function again, except that this time, I'm using MessageBox::Show to pop up a standard Windows dialog while I'm disposing the class, to demonstrate exactly when Dispose gets called. This is bad design, however, as you typically don't want anything in a Dispose function that doesn't need to be there.

private:

void button1_Click(Object^ sender, EventArgs^ evArgs) {

MessageBox::Show(String::Concat("Text is: '", textBox1->Text, "'"));

}

};

Here's button1_Click, the function that is wired up to our button's Click event. It also uses MessageBox::Show to pop up a Windows dialog, with the text of whatever is in our TextBox. We also close out our class here.

int main() {

Application::Run(gcnew HelloWorldForm);

return 0;

}

And, last but not least, our main function. Still not flashy, it does the same thing it did in our first example.


Whew, that was longer. Yes, it was, but it also did a whole lot more, and without too much additional code. Next time, we'll be looking at the power of Windows Forms dynamic layout.

Get the files. You can get the sample here. This contains two files, hwf2.cpp, and hwf2OS.cpp. Hwf2 is the complete code sample above, and hwf2OS.cpp is the Managed Extensions version of it. As always, if something doesn't compile properly, or you have questions, please post a comment.