Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Pro Visual C++-CLI And The .NET 2.0 Platform (2006) [eng]

.pdf
Скачиваний:
46
Добавлен:
16.08.2013
Размер:
24.18 Mб
Скачать

328 C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

Listing 9-6. The Code for “Way Too Many Buttons!”

#pragma once

namespace

TooManyButtons

{

 

using

namespace System;

using

namespace System::ComponentModel;

using

namespace System::Collections;

using

namespace System::Windows::Forms;

using

namespace System::Data;

using

namespace System::Drawing;

public ref class Form1 : public System::Windows::Forms::Form

{

public:

Form1(void)

{

InitializeComponent();

}

protected:

~Form1()

{

if (components)

{

delete components;

}

}

private:

System::Windows::Forms::Button^ TooMany;

System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code

void InitializeComponent(void)

{

this->TooMany = (gcnew System::Windows::Forms::Button()); this->SuspendLayout();

//

// TooMany

//

this->TooMany->Location = System::Drawing::Point(12, 12); this->TooMany->Name = L"TooMany";

this->TooMany->Size = System::Drawing::Size(75, 23); this->TooMany->TabIndex = 1;

this->TooMany->Text = L"Click Me!"; this->TooMany->Click +=

gcnew System::EventHandler(this, &Form1::TooMany_Click);

C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

329

//

// Form1

//

this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->AutoScroll = true;

this->ClientSize = System::Drawing::Size(292, 273); this->Controls->Add(this->TooMany);

this->Name = L"Form1";

this->Text = L"Too Many Buttons"; this->ResumeLayout(false);

}

#pragma endregion

private:

System::Void TooMany_Click(System::Object^ sender, System::EventArgs^ e)

{

//Grab the location of the button that was clicked Point p = ((Button^)sender)->Location;

//Create a dynamic button

Button ^Many = gcnew Button();

Many->Location = Drawing::Point(p.X + 36, p.Y + 26); Many->Text = L"Click Me!";

Many->Click += gcnew System::EventHandler(this, &Form1::TooMany_Click);

// Add dynamic button to Form Controls->Add(Many);

}

};

}

There really isn’t much difference between adding a Label control and a Button statically, as you can see in the InitializeComponent() method. The fun code in Listing 9-6 is in the TooMany_Click() event handler method. The first thing this method does is grab the location of the button that

was clicked and place it into a Point struct so that you can manipulate it. You’ll examine System::Drawing::Point in Chapter 11. You could have grabbed the whole button but you only need its location. Next, you build a button. There’s nothing tricky here, except the button is declared within the event handler. Those of you from a traditional C++ background are probably jumping up and down, screaming “Memory leak!” Sorry to disappoint you, but this is C++/CLI and the memory will be collected when it’s no longer referenced, so this code is perfectly legal. And finally, the last step in placing the button dynamically on the Win Form is adding it.

Figure 9-8 shows what TooManyButtons.exe looks like when you execute it. Be sure to click a few of the newly created buttons.

330 C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

Figure 9-8. Way too many buttons

CheckBox

The CheckBox control is also an extension of the ButtonBase class. It’s similar to a normal Button control in many ways. The two major differences are that it looks different on the Win Form and that it retains its check state when clicked. Well, the first difference isn’t always true—there’s a property to make a CheckBox look like a Button.

The CheckBox control, if configured to do so, can have three states: checked, unchecked, and indeterminate. I’m sure you understand checked and unchecked states, but what is this indeterminate state? Visually, in this state, the check boxes are shaded. Most likely you saw this type of check box when you installed Visual Studio 2005 on your machine. Remember when you set which parts to install and some of the checkmarks were gray? When you selected the gray box, you found that some of the subparts were not checked. Basically, the indeterminate state of the parent resulted from the fact that not all the child boxes were checked.

In addition to supporting the properties provided by ButtonBase, the CheckBox control supports some properties unique to itself:

Appearance is an Appearance enum class that specifies whether the check box looks like a button or a standard check box. The default, Appearance::Normal, is a standard check box.

CheckAlign is a ContentAlignment enum class that represents the alignment of the check box within the CheckBox control. The default alignment is centered and to the left:

ContentAlignment::MiddleLeft.

Checked is a Boolean that represents whether or not the check box is checked. This property returns true if the check box is in an indeterminate state as well. The default is false.

CheckState is a CheckState enum class that represents the current state of the check box:

Checked, Unchecked, or Indeterminate. The default is CheckState::Unchecked.

ThreeState is a Boolean that specifies whether the check box can have an indeterminate state. The default is false.

In our next example (see Listing 9-7), you’ll have a little fun with the CheckBox control, in particular the Visibility property. Enter the code from the listing and have some fun.

C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

331

Listing 9-7. The Code for “You Can’t Check Me!”

#pragma once

namespace

CheckMe

{

 

using

namespace System;

using

namespace System::ComponentModel;

using

namespace System::Collections;

using

namespace System::Windows::Forms;

using

namespace System::Data;

using

namespace System::Drawing;

public ref class Form1 : public System::Windows::Forms::Form

{

public:

Form1(void)

{

InitializeComponent();

}

protected:

~Form1()

{

if (components)

{

delete components;

}

}

private:

System::Windows::Forms::CheckBox^ BottomCheck; System::Windows::Forms::CheckBox^ checkBox2; System::Windows::Forms::CheckBox^ checkBox1; System::Windows::Forms::CheckBox^ TopCheck;

System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code

void InitializeComponent(void)

{

this->BottomCheck = (gcnew System::Windows::Forms::CheckBox()); this->checkBox2 = (gcnew System::Windows::Forms::CheckBox()); this->checkBox1 = (gcnew System::Windows::Forms::CheckBox()); this->TopCheck = (gcnew System::Windows::Forms::CheckBox()); this->SuspendLayout();

//

// BottomCheck

332 C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

//

this->BottomCheck->AutoSize = true; this->BottomCheck->Enabled = false;

this->BottomCheck->Location = System::Drawing::Point(52, 167); this->BottomCheck->Name = L"BottomCheck"; this->BottomCheck->Size = System::Drawing::Size(127, 17); this->BottomCheck->TabIndex = 4;

this->BottomCheck->TabStop = false; this->BottomCheck->Text = L"You Can\'t Check Me!"; this->BottomCheck->Visible = false; this->BottomCheck->Enter +=

gcnew System::EventHandler(this, &Form1::BottomCheck_Enter); this->BottomCheck->MouseEnter +=

gcnew System::EventHandler(this, &Form1::BottomCheck_Enter);

//

//checkBox2

this->checkBox2->AutoSize = true;

this->checkBox2->Location = System::Drawing::Point(52, 130); this->checkBox2->Name = L"checkBox2";

this->checkBox2->Size = System::Drawing::Size(106, 17); this->checkBox2->TabIndex = 5;

this->checkBox2->Text = L"Don\'t Forget ME!";

//checkBox1

//

this->checkBox1->AutoSize = true; this->checkBox1->Checked = true; this->checkBox1->CheckState =

System::Windows::Forms::CheckState::Indeterminate; this->checkBox1->Location = System::Drawing::Point(52, 90); this->checkBox1->Name = L"checkBox1";

this->checkBox1->Size = System::Drawing::Size(133, 17); this->checkBox1->TabIndex = 2;

this->checkBox1->Text = L"Check Me! Check Me!"; this->checkBox1->ThreeState = true;

//

// TopCheck

//

this->TopCheck->AutoSize = true;

this->TopCheck->Location = System::Drawing::Point(52, 49); this->TopCheck->Name = L"TopCheck";

this->TopCheck->Size = System::Drawing::Size(127, 17); this->TopCheck->TabIndex = 3;

this->TopCheck->TabStop = false; this->TopCheck->Text = L"You Can\'t Check Me!"; this->TopCheck->Enter +=

gcnew System::EventHandler(this, &Form1::TopCheck_Enter); this->TopCheck->MouseEnter +=

gcnew System::EventHandler(this, &Form1::TopCheck_Enter);

C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

333

//

// Form1

//

this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(242, 273); this->Controls->Add(this->BottomCheck); this->Controls->Add(this->checkBox2); this->Controls->Add(this->checkBox1); this->Controls->Add(this->TopCheck);

this->Name = L"Form1"; this->Text = L"Can\'t Check Me"; this->ResumeLayout(false); this->PerformLayout();

}

#pragma endregion

private:

System::Void TopCheck_Enter(System::Object^ sender, System::EventArgs^ e)

{

// Hide Top checkbox and display bottom TopCheck->Enabled = false; TopCheck->Visible = false; BottomCheck->Enabled = true; BottomCheck->Visible = true;

}

private:

System::Void BottomCheck_Enter(System::Object^ sender, System::EventArgs^ e)

{

// Hide Bottom checkbox and display top BottomCheck->Enabled = false; BottomCheck->Visible = false; TopCheck->Enabled = true; TopCheck->Visible = true;

}

};

}

You may have noticed that I threw in the indeterminate state in the first/second/first... (whichever) check box, just so you can see what it looks like.

An important thing to take from this example is that it shows you can delegate the same event handler to more than one event. Doing this in the Visual Studio 2005 Properties view requires that you use the drop-down list to select the event handler that you want to re-delegate.

The example also shows how to enable/disable and show/hide both in the Properties view and at runtime.

Figure 9-9 shows what CheckMe.exe looks like when you execute it. Who says programmers don’t have a sense of humor!

334 C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

Figure 9-9. You can’t check me!

RadioButton

From a coding perspective, there isn’t much to say about the RadioButton control other than you code it in exactly the same way you code a CheckBox control. The only difference between the RadioButton and CheckBox controls is that with the RadioButton you lose the CheckState property and its associated CheckStateChanged event.

The RadioButton control works a little differently than the CheckBox control. Only one RadioButton can be checked at a time within a given container, which at this point is the Win Form. (You will see that you can have multiple containers placed on a Win Form later in this chapter in the section “The GroupBox Control.”) If you have ever played with a car radio, you should understand exactly how a

RadioButton works.

Listing 9-8 shows a neat little trick that the GUI design tool can’t do—it shows how to create an array of radio buttons. Having unique names for what amounts to a single entity with multiple values seems a little silly in most cases, and at worst the code goes on forever. I think developing a set of radio buttons, as shown in Listing 9-8, makes good sense.

Listing 9-8. The Code for an Array of Radio Buttons

#pragma once

namespace

ArrayOfRadios

{

 

using

namespace System;

using

namespace System::ComponentModel;

using

namespace System::Collections;

using

namespace System::Windows::Forms;

using

namespace System::Data;

using

namespace System::Drawing;

public ref class Form1 : public System::Windows::Forms::Form

{

public:

Form1(void)

{

InitializeComponent();

C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

335

array<String^>^ rbText = gcnew array<String^> { L"Can", L"You", L"Click", L"More", L"Than", L"One"

};

radios = gcnew array<RadioButton^>(6); label = gcnew Label();

for (int i = 0; i < radios->Length; i++)

{

int j = 50*i;

radios[i] = gcnew RadioButton();

radios[i]->BackColor = Color::FromArgb(255,j+5,j+5,j+5); radios[i]->ForeColor = Color::FromArgb(255,250-j,250-j,250-j); radios[i]->Location = Drawing::Point(90, 10+(40*i)); radios[i]->TabIndex = i;

radios[i]->TabStop = true; radios[i]->Text = rbText[i]; radios[i]->CheckedChanged +=

gcnew EventHandler(this, &Form1::radioCheckedChanged);

}

Controls->AddRange(radios);

label->Location = Drawing::Point(90, 10+(40*radios->Length)); Controls->Add(label);

}

protected:

~Form1()

{

if (components)

{

delete components;

}

}

private:

array<RadioButton^>^ radios; Label ^label;

System::ComponentModel::Container ^components; #pragma region Windows Form Designer generated code

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(292, 273);

this->Name = L"Form1";

this->Text = L"An Array Of Radios"; this->ResumeLayout(false);

}

336 C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

#pragma endregion

private:

void radioCheckedChanged(Object ^sender, EventArgs ^e)

{

RadioButton ^rb = (RadioButton^)sender;

if (rb->Checked == true) label->Text = rb->Text;

}

};

}

The code in Listing 9-8 is pretty straightforward. (This example doesn’t include the design tool– specific code as it was written by hand.) First, you create an array of RadioButton controls, and then you populate the array. I also threw in a Label control to show how to extract the currently checked

RadioButton control.

You should notice a couple of things going on in this listing. First, only one event handler method is needed, as the sender parameter will tell you which RadioButton sent the event. Second, you need to check for a true Checked value because the CheckedChanged event is also triggered on the unchecking event, which also always occurs when a different RadioButton is checked. And the final thing you might want to notice is that you can use the AddRange() method instead of the Add() method to add controls to the form because there is a ready-made array using this method, as the array of RadioButtons is also an array of controls.

I also play with colors a bit, but you look at colors in detail in Chapter 11, so I will hold off the explanation until then.

Figure 9-10 shows what ArrayOfRadios.exe looks like when you execute it.

Figure 9-10. An array of radio buttons

The GroupBox Control

The GroupBox control does basically what its name suggests: It groups controls into a box. Not only does the GroupBox group controls visually, but it also binds the controls so that they act as a group.

The GroupBox control is predominately used for RadioButton controls, but that isn’t a requirement. The requirement is that everything it groups is a control. Grouping random control types is usually done just for cosmetic reasons. Grouping RadioButton controls, on the other hand, provides

C H A P T E R 9 B A S I C W I N D O W S F O R M S A P P L I C A T I O N S

337

the RadioButton control with additional functionality. Instead of being able to select only a single RadioButton on the form, you now can select a unique RadioButton for each GroupBox.

The next example (see Listing 9-9) shows how it is now possible to select more than one RadioButton—in this case, one of the RadioButton controls attached to the form and one from each of the GroupBoxes. Notice I use three arrays of RadioButtons. If you were to create a unique RadioButton each time instead of the array, as is the case for the generated GUI-designed code, you would then be declaring and implementing 12 different RadioButtons. I think this is a good example of why knowing how to code Win Forms by hand improves the code.

Listing 9-9. The Code for Grouping RadioButtons

#pragma once

namespace

GroupingRadios

{

 

using

namespace System;

using

namespace System::ComponentModel;

using

namespace System::Collections;

using

namespace System::Windows::Forms;

using

namespace System::Data;

using

namespace System::Drawing;

public ref class Form1 : public System::Windows::Forms::Form

{

public:

Form1(void)

{

InitializeComponent();

BuildRadios();

}

protected:

~Form1()

{

if (components)

{

delete components;

}

}

private:

System::Windows::Forms::GroupBox^ groupBox2; System::Windows::Forms::GroupBox^ groupBox1;

array<System::Windows::Forms::RadioButton^>^ radio1; array<System::Windows::Forms::RadioButton^>^ radio2; array<System::Windows::Forms::RadioButton^>^ radio3;

System::ComponentModel::Container ^components;