Page 1 of 1

Creating a Find & Replace component in C++ Search through and find text Rate Topic: -----

#1 aj32  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 30
  • View blog
  • Posts: 577
  • Joined: 30-August 07

Post icon  Posted 17 March 2008 - 02:58 PM

Recently, I developed a find and replace component for one of my programs, unlike most, it does not use REGEX. What it does is simple, it will search through the text in a textbox, and highlight it. If there is more that one occourence of the word, it will highlight each individually.

=========
Requirements:
- Visual Studio
=========

To get started, create a Windows Forms Application. Open Form1.h Code View, delete all the contents inside the file, and replace them with this:
#pragma once


namespace TutorialCreatingaFindandReplacecomponent {

	using namespace System;
	using namespace System::ComponentModel;
	using namespace System::Collections;
	using namespace System::Windows::Forms;
	using namespace System::Data;
	using namespace System::Drawing;

	/// <summary>
	/// Summary for Form1
	///
	/// WARNING: If you change the name of this class, you will need to change the
	///		  'Resource File Name' property for the managed resource compiler tool
	///		  associated with all .resx files this class depends on.  Otherwise,
	///		  the designers will not be able to interact properly with localized
	///		  resources associated with this form.
	/// </summary>
	public ref class Form1 : public System::Windows::Forms::Form
	{
	public:
		Form1(void)
		{
			InitializeComponent();
			//
			//TODO: Add the constructor code here
			//
		}

	protected:
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}
	private: System::Windows::Forms::Panel^  FindReplacepanel;
	protected: 
	private: System::Windows::Forms::Button^  B2;
	private: System::Windows::Forms::Button^  B1;
	private: System::Windows::Forms::TextBox^  RT;
	private: System::Windows::Forms::CheckBox^  REPLACECHECK;
	private: System::Windows::Forms::TextBox^  FT;

	private: System::Windows::Forms::Label^  FTLABEL;

	private: System::Windows::Forms::RichTextBox^  TEXT;


			 // HERE ARE OUR GLOBAL FIND AND REPLACE VARIABLES //
	private: String^ FindLastText;
			 int FindLastIndex;
			 // END GLOBAL VARIABLES

	private:
		/// <summary>
		/// Required designer variable.
		/// </summary>
		System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		void InitializeComponent(void)
		{
			this->FindReplacepanel = (gcnew System::Windows::Forms::Panel());
			this->B2 = (gcnew System::Windows::Forms::Button());
			this->B1 = (gcnew System::Windows::Forms::Button());
			this->RT = (gcnew System::Windows::Forms::TextBox());
			this->REPLACECHECK = (gcnew System::Windows::Forms::CheckBox());
			this->FT = (gcnew System::Windows::Forms::TextBox());
			this->FTLABEL = (gcnew System::Windows::Forms::Label());
			this->TEXT = (gcnew System::Windows::Forms::RichTextBox());
			this->FindReplacepanel->SuspendLayout();
			this->SuspendLayout();
			// 
			// FindReplacepanel
			// 
			this->FindReplacepanel->Controls->Add(this->B2);
			this->FindReplacepanel->Controls->Add(this->B1);
			this->FindReplacepanel->Controls->Add(this->RT);
			this->FindReplacepanel->Controls->Add(this->REPLACECHECK);
			this->FindReplacepanel->Controls->Add(this->FT);
			this->FindReplacepanel->Controls->Add(this->FTLABEL);
			this->FindReplacepanel->Dock = System::Windows::Forms::DockStyle::Right;
			this->FindReplacepanel->Location = System::Drawing::Point(488, 0);
			this->FindReplacepanel->Name = L"FindReplacepanel";
			this->FindReplacepanel->Size = System::Drawing::Size(200, 387);
			this->FindReplacepanel->TabIndex = 0;
			// 
			// B2
			// 
			this->B2->Location = System::Drawing::Point(113, 110);
			this->B2->Name = L"B2";
			this->B2->Size = System::Drawing::Size(75, 23);
			this->B2->TabIndex = 5;
			this->B2->Text = L"Replace All";
			this->B2->UseVisualStyleBackColor = true;
			this->B2->Visible = false;
			this->B2->Click += gcnew System::EventHandler(this, &Form1::REPLACE_ALL_BUTTON_CLICKED);
			// 
			// B1
			// 
			this->B1->Location = System::Drawing::Point(9, 110);
			this->B1->Name = L"B1";
			this->B1->Size = System::Drawing::Size(75, 23);
			this->B1->TabIndex = 4;
			this->B1->Text = L"Find";
			this->B1->UseVisualStyleBackColor = true;
			this->B1->Click += gcnew System::EventHandler(this, &Form1::FIND_OR_REPLACE_BUTTON_CLICKED);
			// 
			// RT
			// 
			this->RT->Enabled = false;
			this->RT->Location = System::Drawing::Point(9, 83);
			this->RT->Name = L"RT";
			this->RT->Size = System::Drawing::Size(179, 20);
			this->RT->TabIndex = 3;
			this->RT->Visible = false;
			// 
			// REPLACECHECK
			// 
			this->REPLACECHECK->AutoSize = true;
			this->REPLACECHECK->Location = System::Drawing::Point(9, 67);
			this->REPLACECHECK->Name = L"REPLACECHECK";
			this->REPLACECHECK->Size = System::Drawing::Size(94, 17);
			this->REPLACECHECK->TabIndex = 2;
			this->REPLACECHECK->Text = L"Replace With:";
			this->REPLACECHECK->UseVisualStyleBackColor = true;
			this->REPLACECHECK->CheckedChanged += gcnew System::EventHandler(this, &Form1::REPLACECHECK_CheckedChanged);
			// 
			// FT
			// 
			this->FT->Location = System::Drawing::Point(9, 25);
			this->FT->Name = L"FT";
			this->FT->Size = System::Drawing::Size(179, 20);
			this->FT->TabIndex = 1;
			this->FT->TextChanged += gcnew System::EventHandler(this, &Form1::TEXTChanged);
			// 
			// FTLABEL
			// 
			this->FTLABEL->AutoSize = true;
			this->FTLABEL->Location = System::Drawing::Point(6, 9);
			this->FTLABEL->Name = L"FTLABEL";
			this->FTLABEL->Size = System::Drawing::Size(59, 13);
			this->FTLABEL->TabIndex = 0;
			this->FTLABEL->Text = L"Find What:";
			// 
			// TEXT
			// 
			this->TEXT->Dock = System::Windows::Forms::DockStyle::Fill;
			this->TEXT->Location = System::Drawing::Point(0, 0);
			this->TEXT->Name = L"TEXT";
			this->TEXT->Size = System::Drawing::Size(488, 387);
			this->TEXT->TabIndex = 1;
			this->TEXT->Text = L"";
			// 
			// Form1
			// 
			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
			this->ClientSize = System::Drawing::Size(688, 387);
			this->Controls->Add(this->TEXT);
			this->Controls->Add(this->FindReplacepanel);
			this->Name = L"Form1";
			this->Text = L"</d.i.c.> Tutorial - Creating a Find & Replace Form";
			this->Load += gcnew System::EventHandler(this, &Form1::SETVARIABLES);
			this->FindReplacepanel->ResumeLayout(false);
			this->FindReplacepanel->PerformLayout();
			this->ResumeLayout(false);

		}
#pragma endregion
	private: System::Void SETVARIABLES(System::Object^  sender, System::EventArgs^  e) {
			 }

	  private: System::Void REPLACECHECK_CheckedChanged(System::Object^  sender, System::EventArgs^  e) {
			 }

	private: System::Void FIND_OR_REPLACE_BUTTON_CLICKED(System::Object^  sender, System::EventArgs^  e) {
			 }

	private: System::Void REPLACE_ALL_BUTTON_CLICKED(System::Object^  sender, System::EventArgs^  e) {
			 }

	private: System::Void TEXTChanged(System::Object^  sender, System::EventArgs^  e) {
			 }
};
}



The code you just entered into your IDE contains the setup for the form; a rich Text Box, a Find Box, A replace Box, A find/replace button, a Replace all button, a find || Replace checkbox, and some labels.
Also, you will notice 2 global variables, they are: FindLastIndex & FindLastText, the first variable, FindLastIndex, defines the ending index of the last found word, for example, if you had your words go here, and you searched for "words", FindLastIndex would be equal to '10', the program will use this variable to determine if the word has already been highlighted or not. If it has, it will, of course, highlight the next match, if any. The second variable will store the last text in the FT (FindText) Textbox, if the text is changed the text on the find button will be changed form "Find Next" to "Find"


Now we must edit our "YOURPROJECTNAMEHERE.cpp" file to make it work with "form1.h", replace all the data in that file with this:

// Tutorial - Creating a Find and Replace component.cpp : main project file.

#include "stdafx.h"
#include "Form1.h"

using namespace TutorialCreatingaFindandReplacecomponent;

[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());
	return 0;
}



Now, we need to open up the form designer and edit the properties of textbox: TEXT (the large richTextBox), you need to change the "Hide Selection" property to "False".

We also need to add a function to set our global variables, in function SETVARIABLES add this:

FindLastIndex = 0;
				 FindLastText = "";


Next, we will add the basic switch that will control if the user is just finding text, or finding and replacing text.

Add this code under function "REPLACECHECK_CheckedChanged()":

				 if(REPLACECHECK->Checked == true)
				 {
					 RT->Enabled = true;
					 RT->Visible = true;
					 B2->Enabled = true;
					 B2->Visible = true;
					 B1->Text = "Replace";
				 }
				 else
				 {
					 RT->Enabled = false;
					 RT->Visible = false;
					 B2->Enabled = false;
					 B2->Visible = false;
					 B1->Text = "Find";
				 }



Now, if you run the program ( [Ctrl]+[F5] ) you will notice that, when you change the checkstate of the checkbox, the program will toggle between find & replace and just Find.

Next is the code that will determine if one, the user has entered data into the 'find what' textbox and, two, is the word that the user is searching for exist in the textbox:

in function "FIND_OR_REPLACE_BUTTON_CLICKED()", type in the following code:

				 if(FT->Text == "")
				 {
					 MessageBox::Show("You must enter something to search for!");
				 }
				 else if(!(TEXT->Text->Contains(FT->Text)))
				 {
					 MessageBox::Show("Sorry, cannot find " + FT->Text + " in the textbox!");
				 }
				 else
				 {
					 //SEARCH//
				 }



The first part, FT->Text == "", will check to see if the user has entered something to search for.
The second if statement, !(TEXT->Text->Contains(FT->Text)), checks to see if the text the user is searching for even exists in the textbox.

Now, we will create the component to Replace All. In the function "REPLACE_ALL_BUTTON_CLICKED()", add this code:
			 if(TEXT->Text->Contains(FT->Text))//Is the text there?//
			 {
				
				 int FST = 0;
				 while(!(FST == -1)) //while the data we are searching for still exists//
				 {
					FST = TEXT->Text->IndexOf(FT->Text, FindLastIndex);

					if(!(FindLastText == FT->Text))//Did the user change the find text?//
					{
						FindLastIndex = 0;// if s/he did, then re-start;
					}

					 
					 if(FST == -1)
					 {
						 //If we have replaced all//
						 FindLastIndex = 0;
						 break;
					 }
					 TEXT->Selectionstart = FST;//set the selection start//
					 TEXT->SelectionLength = FT->Text->Length;//select found text//
					 TEXT->SelectedText = RT->Text;//replace found text//
					 TEXT->Selectionstart = FST;//select replaced text//
					 TEXT->SelectionLength = RT->Text->Length;//...//
					 FindLastIndex = FST + RT->Text->Length;//Set the index variable//
					 FindLastText = FT->Text;//set the find text variable//
				 }
			 }
			 else //couldn't find that text//
			 {
					 MessageBox::Show("Could not find " + FT->Text);
					 FindLastIndex = 0;//Set FindLastIndex back//
			 }




I have added notes to the code to show you what the program is doing, so you can better understand how it works.

Now if you run the program, and you have entered the code(s) properly, you will be able to use the replace all button to replace text in the textbox.
Now we will add the Find & the Find And Replace Functions, this will be using most of the commands in the previous code. In function "FIND_OR_REPLACE_BUTTON_CLICKED()", replace the note //SEARCH//, with:

					if(REPLACECHECK->Checked == true) // if: we are replacing something//
					{

							if(TEXT->Text->Contains(FT->Text))//is what the user is searching for here?//
							{
							if(!(FindLastText == FT->Text)) //if the user changed the text in the find box...//
							{
								FindLastIndex = 0;//change FindLastIndex to 0//

							}
							 int FST = TEXT->Text->IndexOf(FT->Text, FindLastIndex);

							 if(FST == -1)//Text Not found anymore //
							 {
								 FindLastIndex = 0;
								 FST = TEXT->Text->IndexOf(FT->Text, FindLastIndex);
							 }

							 TEXT->Selectionstart = FST;//select text//
							 TEXT->SelectionLength = FT->Text->Length;//...//
							 TEXT->SelectedText = RT->Text;//Replace Text//
							 TEXT->Selectionstart = FST;//select replaced text//
							 TEXT->SelectionLength = RT->Text->Length;//...//
							 FindLastIndex = FST + FT->Text->Length;//Set FindLastIndex //
							 FindLastText = FT->Text;//Set FindLastText//
						 }
						 else//Sorry, couldn't find that//
						 {
							 MessageBox::Show("Could not find " + FT->Text);
							 FindLastIndex = 0;
						 }
						
						
						 if(FindLastIndex == 0)//is this the first time we have searched for something?
						 {
							 B1->Text = "Replace"; // yes; change the text to Replace //
						 }
						 else
						 {
							 B1->Text = "Replace Next"; //No; change the text to Replace Next//
						 }
					}
					 else // we are finding something//
					{
				if(TEXT->Text->Contains(FT->Text)) //is what the user is searching for here?//
				{
					if(!(FindLastText == FT->Text)) //if the user changed the text in the find box...//
					{
						FindLastIndex = 0;//change FindLastIndex to 0//

					}

					 int FST = TEXT->Text->IndexOf(FT->Text, FindLastIndex);

					 if(FST == -1)//Text Not found anymore //
					 {
						 FindLastIndex = 0;
						 FST = TEXT->Text->IndexOf(FT->Text, FindLastIndex);
					 }

					 TEXT->Selectionstart = FST; //select text//
					 TEXT->SelectionLength = FT->Text->Length;//...//
					 FindLastIndex = FST + FT->Text->Length;//Set FindLastIndex//
					 FindLastText = FT->Text;//Set FindLastText//
				 }
				 else //Sorry, couldn't find that//
				 {
					 MessageBox::Show("Could not find " + FT->Text);
					 FindLastIndex = 0;
				 }
				
				
				 if(FindLastIndex == 0) //is this the first time we have searched for something?
				 {
					 B1->Text = "Find"; // yes; change the text to Find //
				 }
				 else
				 {
					 B1->Text = "Find Next"; //No; change the text to Find Next//
				 }
			 
					}


				 



I have also included comments to explain what the program is doing.

If all went well, we will have a simple find & replace program running!

I hope you find this tutorial useful, and thanks for reading it!

-AJ32 :)

Is This A Good Question/Topic? 0
  • +

Page 1 of 1