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

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

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

348 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

// setting validating type to DateTime mtbDoB->ValidatingType = DateTime::typeid;

}

protected:

~Form1()

{

if (components)

{

delete components;

}

}

private:

System::Windows::Forms::Button^ bnSubmit; System::Windows::Forms::Label^ label3; System::Windows::Forms::TextBox^ tbPassword; System::Windows::Forms::TextBox^ tbOutput; System::Windows::Forms::Label^ label2; System::Windows::Forms::MaskedTextBox^ mtbDoB; System::Windows::Forms::Label^ label1; System::Windows::Forms::TextBox^ tbName;

DateTime^ DoB;

System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code

void InitializeComponent(void)

{

this->bnSubmit = (gcnew System::Windows::Forms::Button()); this->label3 = (gcnew System::Windows::Forms::Label()); this->tbPassword = (gcnew System::Windows::Forms::TextBox()); this->tbOutput = (gcnew System::Windows::Forms::TextBox()); this->label2 = (gcnew System::Windows::Forms::Label()); this->mtbDoB = (gcnew System::Windows::Forms::MaskedTextBox()); this->label1 = (gcnew System::Windows::Forms::Label()); this->tbName = (gcnew System::Windows::Forms::TextBox()); this->SuspendLayout();

//

//bnSubmit

this->bnSubmit->Location = System::Drawing::Point(260, 36); this->bnSubmit->Margin = System::Windows::Forms::Padding(1,3,3,3);

this->bnSubmit->Name = L"bnSubmit"; this->bnSubmit->Size = System::Drawing::Size(56, 20);

this->bnSubmit->TabIndex = 10; this->bnSubmit->Text = L" Submit";

this->bnSubmit->Click +=

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

//label3

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

349

//

this->label3->AutoSize = true;

this->label3->Location = System::Drawing::Point(14, 232); this->label3->Name = L"label3";

this->label3->Size = System::Drawing::Size(56, 13); this->label3->TabIndex = 14;

this->label3->Text = L"Password:";

//

//tbPassword

this->tbPassword->CausesValidation = false; this->tbPassword->Location = System::Drawing::Point(78, 226);

this->tbPassword->MaxLength = 16; this->tbPassword->Name = L"tbPassword";

this->tbPassword->PasswordChar = '?'; this->tbPassword->Size = System::Drawing::Size(238, 20);

this->tbPassword->TabIndex = 13; this->tbPassword->UseSystemPasswordChar = true;

this->tbPassword->WordWrap = false; this->tbPassword->TextChanged +=

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

//tbOutput

//

this->tbOutput->Location = System::Drawing::Point(14, 63); this->tbOutput->Multiline = true;

this->tbOutput->Name = L"tbOutput"; this->tbOutput->ReadOnly = true; this->tbOutput->ScrollBars =

System::Windows::Forms::ScrollBars::Vertical; this->tbOutput->Size = System::Drawing::Size(302, 156); this->tbOutput->TabIndex = 12;

this->tbOutput->TabStop = false;

//

//label2

this->label2->AutoSize = true;

this->label2->Location = System::Drawing::Point(168, 15); this->label2->Name = L"label2";

this->label2->Size = System::Drawing::Size(69, 13); this->label2->TabIndex = 11;

this->label2->Text = L"Date of Birth:";

//mtbDoB

//

this->mtbDoB->AllowPromptAsInput = false; this->mtbDoB->BeepOnError = true;

this->mtbDoB->Location = System::Drawing::Point(168, 36); this->mtbDoB->Margin = System::Windows::Forms::Padding(3,3,1,3); this->mtbDoB->Mask = L"00/00/0000";

this->mtbDoB->Name = L"mtbDoB";

this->mtbDoB->Size = System::Drawing::Size(89, 20); this->mtbDoB->TabIndex = 8; this->mtbDoB->TypeValidationCompleted +=

350 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

gcnew System::Windows::Forms::TypeValidationEventHandler(this, &Form1::mtbDoB_TypeValidationCompleted);

//

//label1

this->label1->AutoSize = true;

this->label1->Location = System::Drawing::Point(14, 15); this->label1->Name = L"label1";

this->label1->Size = System::Drawing::Size(38, 13); this->label1->TabIndex = 9;

this->label1->Text = L"Name:";

//tbName

//

this->tbName->Location = System::Drawing::Point(14, 36); this->tbName->Name = L"tbName";

this->tbName->Size = System::Drawing::Size(147, 20); this->tbName->TabIndex = 7;

this->tbName->Validating +=

gcnew System::ComponentModel::CancelEventHandler(this, &Form1::tbName_Validating);

//

// Form1

//

this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(331, 261); this->Controls->Add(this->bnSubmit); this->Controls->Add(this->label3); this->Controls->Add(this->tbPassword); this->Controls->Add(this->tbOutput); this->Controls->Add(this->label2); this->Controls->Add(this->mtbDoB); this->Controls->Add(this->label1); this->Controls->Add(this->tbName);

this->Name = L"Form1";

this->Text = L"Simple entry data entry"; this->ResumeLayout(false); this->PerformLayout();

}

#pragma endregion

private:

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

{

if (tbName->Text->Length <= 0)

// Blank name bad!

tbName->Focus();

 

else if (*DoB == DateTime::MinValue)

// Bad date bad!

mtbDoB->Focus();

 

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

351

else

// Good!

{

 

 

// Concatinate name and date of birth and add to output

 

tbOutput->Text = String::Format("{0} - {1}\r\n{2}",

 

tbName->Text, mtbDoB->Text, tbOutput->Text);

 

tbName->Clear();

 

mtbDoB->Clear();

 

DoB = DateTime::MinValue;

}

}

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

{

//if the Password TextBox Text equals "Editable" then make

//the multiline TextBox editable and have a tab stop

if (tbPassword->Text->Equals("Editable"))

{

tbOutput->TabStop = true; tbOutput->ReadOnly = false;

}

else

{

tbOutput->TabStop = false; tbOutput->ReadOnly = true;

}

}

System::Void mtbDoB_TypeValidationCompleted(System::Object^ sender, System::Windows::Forms::TypeValidationEventArgs^ e)

{

//Check to see if the date was valid and less than or equals

//todays date. When false make the MaskedTextBox yellow

//and make DoB MinValue. otherwise set it to normal and make

//DoB the value within MaskedTextBox

if (e->IsValidInput && (*(DateTime^)e->ReturnValue) <= DateTime::Now)

{

DoB = (DateTime^)e->ReturnValue; mtbDoB->BackColor = SystemColors::Window;

}

else

{

mtbDoB->BackColor = Color::Yellow; DoB = DateTime::MinValue;

}

}

352 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

System::Void tbName_Validating(System::Object^ sender, System::ComponentModel::CancelEventArgs^ e)

{

//Check to make sure there is a name. When false make the

//TextBox yellow. Otherwise set it to normal as all is okay if (tbName->Text->Length <= 0)

tbName->BackColor = Color::Yellow;

else

tbName->BackColor = SystemColors::Window;

}

};

}

One thing to note about the code in Listing 9-11 is the use of the Control class’s Validating event. This event is triggered when a control loses focus and allows the value within the control to be validated. In the previous example, I use the Validating event to turn the control yellow when no name is entered in the control.

By the way, if you set the Cancel property to true within the CancelEventArgs argument, then the focus will remain within the current control.

Data validation is well beyond the scope of this book, but Data Entry and Validation with C# and VB .NET Windows Forms by Nick Symmonds (Apress, 2003) covers the topic in great detail. Again, the book is not written for C++/CLI, but you should be able to follow it well enough to implement its contents.

Figure 9-13 shows what TextEntry.exe looks like when you execute it.

Figure 9-13. Assorted text boxes

RichTextBox

Plain and simple, the RichTextBox control is overkill, for most cases, when you need text input. This control provides advanced formatting features, such as boldface, italics, underline, color, and different fonts. It is also possible to format paragraphs. You can assign text directly to the control using the Text property, or you can load it from a Rich Text Format (RTF) or plain text file using the LoadFile() method.

The RichTextBox control is a little tricky to use, as most of the added functionality over the TextBox control requires the handling of events or other controls, such as buttons, to implement. For example, implementing boldfacing of text within a RichTextBox requires implementing the SelectionFont property, which needs to be referenced somehow. In the following example, I do this by pressing the F1 key, but you could do it any number of other ways.

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

353

The RichTextBox control provides a number of additional properties to handle the formatting features it provides. Here are some of the more common properties:

BulletIndent is an Int32 that represents the number of pixels inserted as the indentation after a bullet. The default is 0.

CanRedo is a Boolean that represents whether undone operations can be reapplied.

RedoActionName is a String that represents the name of the next redo action to be applied. If the return String is empty (a zero-length String, not a null), then there are no more actions that can be redone.

RightMargin is an Int32 that represents the number of pixels from the left side of the control where the nonvisible right margin is placed.

Rtf is a String that represents the RTF-formatted data in the control. The content of the Rtf property differs from that of the Text property in that the Rtf property is in Rich Text Format, whereas the Text property is in just plain text.

Scrollbars is a RichTextScrollbars enum class that represents which (if any) scroll bars will be visible within the control. The default is RichTextScrollbars::Both, which will display both vertical and horizontal scroll bars if needed. I prefer to use ForceVertical instead because it stops the control from having to readjust itself when the content extends beyond the vertical height of the control. It now simply enables the already visible vertical scroll bar.

SelectedRtf is a String containing selected RTF-formatted text from the control. The default is a zero-length String (not null).

SelectionBullet is a Boolean that represents whether the bullet style should be applied to the current selected text or insertion point. The default is false.

SelectionColor is a System::Drawing::Color that represents the color of the selected text. If more than one color falls within the selected text, then Color::Empty is returned.

SelectionFont is a System::Drawing::Font that represents the font of the selected text. If more than one font falls within the selected text, then null is returned.

SelectionHangingIndent is an Int32 that represents the distance in pixels between the left edge of the first line of text in the selected paragraph and the left edge of subsequent lines in the same paragraph.

SelectionIndent is an Int32 that represents the distance in pixels between the left edge of the control window and the left edge of the current selected text or text added after the insertion point.

SelectionRightIndent is an Int32 that represents the distance in pixels between the right edge of the text and the right edge of the control.

SelectionTabs is an array of Int32 that represents a set of absolute tab locations in pixels.

ShowSelectionMargin is a Boolean that represents whether the selection margin on the left side of the control is expanded for easier access. Clicking the margin highlights the entire row. The default is false.

UndoActionName is a String that represents the name of the next undo action to be applied. If the return String is empty (a zero-length String, not a null), then there are no more actions that can be undone.

The RichTextBox control provides a number of additional methods as well:

Find() searches for the specified text within the control.

LoadFile() loads a text or RTF-formatted file into the control.

354 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

Redo() will redo the last undo operation done on the control.

SaveFile() saves a text or RTF-formatted file to the specified path/file location.

Undo() will undo the last operation done on the control.

The next example (see Listing 9-12) is an extremely simple and limited use of the functionality of the RichTextBox. It lacks many of the features that are available, but it is a good starting point and gives you some ideas about how to implement your own RTF editor, if you are so inclined.

In the example, pressing the F9 key loads a couple of pages from a novel I am writing. You can save the file back by pressing F10. To test out the special features of this RichTextBox, select some text with the mouse and then press one of the remaining function keys (F1–F8).

Listing 9-12. Implementing a Simple RTF Editor

#pragma once

namespace

RichText

{

 

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();

BuildLabels();

}

protected:

~Form1()

{

if (components)

{

delete components;

}

}

private:

System::Windows::Forms::RichTextBox^ rtBox;

array<System::Windows::Forms::Label^>^ labels;

System::ComponentModel::Container ^components;

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

355

#pragma region Windows Form Designer generated code

void InitializeComponent(void)

{

this->rtBox = (gcnew System::Windows::Forms::RichTextBox()); this->SuspendLayout();

//

// rtBox

//

this->rtBox->Anchor = static_cast<System::Windows::Forms::AnchorStyles> (System::Windows::Forms::AnchorStyles::Top

| System::Windows::Forms::AnchorStyles::Bottom | System::Windows::Forms::AnchorStyles::Left

| System::Windows::Forms::AnchorStyles::Right); this->rtBox->Location = System::Drawing::Point(0, 32); this->rtBox->Name = L"rtBox";

this->rtBox->RightMargin = 900; this->rtBox->ScrollBars =

System::Windows::Forms::RichTextBoxScrollBars::ForcedVertical; this->rtBox->ShowSelectionMargin = true;

this->rtBox->Size = System::Drawing::Size(950, 488); this->rtBox->TabIndex = 1;

this->rtBox->Text = L""; this->rtBox->KeyDown +=

gcnew System::Windows::Forms::KeyEventHandler(this, &Form1::rtBox_KeyDown);

//

// Form1

//

this->AutoScaleDimensions = System::Drawing::SizeF(6, 13); this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font; this->ClientSize = System::Drawing::Size(950, 520); this->Controls->Add(this->rtBox);

this->Name = L"Form1";

this->Text = L"(Very Simple Rich Text Editor)"; this->ResumeLayout(false);

}

#pragma endregion

void BuildLabels()

{

array<String^>^ rtLabel = gcnew array<String^> { L"F1-Bold", L"F2-Italics", L"F3-Underline", L"F4-Normal", L"F5-Red", L"F6-Blue", L"F7-Green", L"F8-Black", L"F9-Load", L"F10-Save"

};

labels = gcnew array<System::Windows::Forms::Label^>(10);

356 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

// Build the labels

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

{

labels[i] = gcnew Label();

labels[i]->BackColor = SystemColors::ControlDark; labels[i]->BorderStyle = BorderStyle::FixedSingle; labels[i]->Location = Drawing::Point(5+(95*i), 8); labels[i]->Size = Drawing::Size(85, 16); labels[i]->Text = rtLabel[i];

labels[i]->TextAlign = ContentAlignment::MiddleCenter;

}

// Place labels on the Form Controls->AddRange(labels);

}

System::Void rtBox_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e)

{

try

{

if (rtBox->SelectionLength > 0)

{

//Change selected text style FontStyle fs;

switch (e->KeyCode)

{

case Keys::F1:

fs = FontStyle::Bold; break;

case Keys::F2:

fs = FontStyle::Italic; break;

case Keys::F3:

fs = FontStyle::Underline; break;

case Keys::F4:

fs = FontStyle::Regular; break;

//Change selected text color

case Keys::F5:

rtBox->SelectionColor = Color::Red; break;

case Keys::F6:

rtBox->SelectionColor = Color::Blue; break;

case Keys::F7:

rtBox->SelectionColor = Color::Green; break;

case Keys::F8:

rtBox->SelectionColor = Color::Black; break;

}

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

357

// Do the actual change of the selected text style

if (e->KeyCode >= Keys::F1 && e->KeyCode <= Keys::F4)

{

rtBox->SelectionFont = gcnew Drawing::Font( rtBox->SelectionFont->FontFamily, rtBox->SelectionFont->Size,

fs

);

}

}

//Load hard coded Chapter01.rtf file else if (e->KeyCode == Keys::F9)

{

rtBox->LoadFile("Chapter01.rtf");

}

//Save hard coded Chapter01.rtf file else if (e->KeyCode == Keys::F10)

{

rtBox->SaveFile("Chapter01.rtf",

RichTextBoxStreamType::RichText);

}

}

// Capture any blowups catch (Exception ^e)

{

MessageBox::Show(String::Format("Error: {0}", e->Message));

}

}

};

}

As you can see, implementing the functionality of the RichTextBox is done externally to the control itself. You need some way of updating the properties. I took the easy way out by capturing simple function keystroke events and updating the selected RichTextBox text as appropriate. You will probably want to use a combination of keystrokes, button clicks, and so on to make the editing process as easy as possible.

Another interesting bit of code in this example is the use of the Anchor property:

this->rtBox->Anchor = static_cast<System::Windows::Forms::AnchorStyles> (System::Windows::Forms::AnchorStyles::Top |

System::Windows::Forms::AnchorStyles::Bottom | System::Windows::Forms::AnchorStyles::Left | System::Windows::Forms::AnchorStyles::Right);

This property allows you to have a control anchor itself to any or all (as shown in the previous code) sides of the parent window. Thus, when the parent window is resized, so is the control. (I removed all the extra, and unneeded, code added by the code generator to make it more readable.)

Be careful when you run this program, as it is dependent on where it is executed. To make things easier, I hard-coded the program to load and save to the current working directory. When you run this program within Visual Studio 2005, the current working directory is located where your source code is. Thus, the Chapter01.rtf file is located in the same directory as the source code. If you run this program on its own out of Windows Explorer, for example, then it will not find the RTF file. In this scenario, you need to copy the file to the same directory as the executable. Obviously, if you wanted to make the program more robust, you would allow a user to specify where the RTF file is, so this dependency would not be an issue.