|
|
![]() |
|
||
|
|
|||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Projects Pure VB: Create a Find and Replace Dialog Step 2: Building the Find/Replace Form |
|
| Posted: | Monday August 05, 2002 |
| Updated: | Monday December 26, 2011 |
| Applies to: | VB4-32, VB5, VB6 |
| Developed with: | Original: VB3/Win 3.1. Updated: VB6/Windows XP |
| OS restrictions: | None |
| Author: | VBnet - Randy Birch |
| Other project pages: | Step 1: Create the Find / Replace Dialog project |
| Prerequisites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Project and code created from Step 1: Create the Find / Replace Dialog project | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Once again, the layout form below shows the names of the respective controls you must add to the actual Find/Replace form, and their relative positions on that form. Controls in gold are required, but that do not have any code attached in this demo - that functionality is left for you to implement. The second cropped form below is provided for your convenience, and can be loaded to your working form's Picture property to provide a rough layout guide. This page contains only the code for the form shown below. The file and calling form created in Step 1 are also required for the complete demo.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| BAS Code | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| None. The project used the bas module created in Step 1. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Form Code: dlgReplace - the Find / Replace form | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Due
to the complexity of this form, some controls use names other than the VB
default controls names. I recommend you add the image above to the
dialog's Picture property to assist in code layout, since the code to
position the controls, as coded, moves the controls to fixed (absolute)
positions. Note as well the project is coded for small fonts so large
font users will need to adjust the code in order for
the controls to line up correctly. This step was taken simply to minimize the UI
code shown in order to concentrate on the actual Find/Replace code in the
dialog. The find/replace dialog's form should contain the following controls, each named as indicated. Note some controls are part of control arrays, so for correct functionality ensure their index property is set as shown. The 'red' items below are required on the form in order for the repositioning code to work, but they do not have supporting code - that is your project.
Save this form as dlgReplace, and add the following code to the form: |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 'var holding a reference to
'the textbox being searched
Dim ctlTarget As Control
'LengthOf variables...
'search string
Dim LOSearch As Long
'replace string
Dim LOReplace As Long
'the text passed
'for search/replace
Dim LOWorkText As Long
'the instance of the
'search string found
Dim LOInstance As Long
'couple of form-level variables
'to track current word positions.
Dim pStop As Long
Dim pStart As Long
Private Sub Form_Load()
Dim success As Boolean
cboDir.ListIndex = 0
optSearch(0).Value = True
cboSearch.Text = ""
cboReplace.Text = ""
With frd
If Len(.sSearchText) > 0 Then
cboSearch.Text = .sSearchText
End If
.nCurrPos = IIf(ctlTarget.SelStart = 0, 1, ctlTarget.SelStart)
.nCursorPos = .nCurrPos
'When using the InStr function with
'the compare parameter, a value of 0
'indicates a binary search (AKA case ,
'sensitive while a value of 1 indicates
'case-insensitive.
'Since the form is appearing from an
'unloaded state, and the "Match Case"
'checkbox value is not set via properties
'or code, the expression below always
'starts with a case-insensitive search.
'(Check.value = 0, which is true (-1), the
'ABS() of which is 1, or case insensitive)
.bMatchCase = Abs(chkMatchCase.Value = 0)
'before going further, determine if
'there's reason to actually search!
Call FindReplaceInit
cboReplace.Text = .sReplaceText
End With
End Sub
Private Sub Form_Unload(Cancel As Integer)
'reset vars
FindReset
'we want to be sure to also
'release the variables associated
'with this form
Set dlgReplace = Nothing
End Sub
Private Sub Form_KeyPress(KeyAscii As Integer)
'let Escape cancel the dialog
If KeyAscii = 27 Then Unload Me
End Sub
Private Sub cmdCancel_Click()
Unload Me
End Sub
Private Sub cmdFind_Click()
With frd
Select Case .bCountOnly
Case False
.sSearchText = cboSearch.Text
LOReplace = Len(.sReplaceText)
LOSearch = Len(.sSearchText)
'attempt to find a match
If .nCurrPos > 0 Then
If pStop >= .nCurrPos Then .nCurrPos = pStop
'pass the above, find an instance,
'and set the remaining variables
If Not vFindInstance(.nCurrPos, pStop) Then
MsgBox "The specified region has " & _
"been searched. Matches found: " & _
.nNumFound, vbInformation, _
"Find/Replace"
'reset the vars
FindReset
cboSearch.SetFocus
End If
End If
Case True
.bCountOnly = True
.sSearchText = cboSearch.Text
Call CountSearch
MsgBox .nNumFound & " matches found for ' " & _
.sSearchText & " '", _
vbInformation, "Find/Replace"
FindReset
End Select
End With
End Sub
Private Sub cmdReplace_Click(Index As Integer)
Dim success As Long
'we're about to replace text!
frd.bInReplaceMode = True
'a couple of initial steps
frd.sSearchText = cboSearch.Text
frd.sReplaceText = cboReplace.Text
LOReplace = Len(frd.sReplaceText)
LOSearch = Len(frd.sSearchText)
Select Case Index
Case 0
'if the Find dialog is currently
'showing, the button caption will
'contain "Replace...". If so and
'clicked, just change to the Replace
'dialog format.
If cmdReplace(0).Caption = " Replace..." Then
cmdReplace(0).Caption = "Replace"
'don't have to pass the
'optional values as they've
'already been set!!!
SetupInit swReplaceText
Else
'making sure there is text
'in the buffer, attempt to
'find a match
If frd.nCurrPos > 0 Then
'look for the first instance
'of the search word
If vFindInstance(frd.nCurrPos, pStop) Then
'must be one, so change it
Call vChangeInstance(pStart, _
pStop, _
LOInstance, _
LOSearch, _
LOReplace, _
LOWorkText)
'a little error prevention
If pStop >= frd.nCurrPos Then frd.nCurrPos = pStop
'See if another instance exists.
'If not, the 'done' message will
'be shown
success = vFindInstance(frd.nCurrPos, pStop)
End If 'vFindInstance
'when success is false, there
'are/were no (more) instances
If Not success Then
MsgBox "The document has been searched. " & _
frd.nNumFound & " matches found; " & _
frd.nNumReplaced & " changes made.", _
vbInformation Or vbOKOnly, "Find/Replace"
'reset the vars
FindReset
End If 'success
End If 'frd.nCurrPos
End If 'cmdReplace(0).Caption
Case 1:
Screen.MousePointer = vbHourglass
ChangeAll
Screen.MousePointer = vbDefault
MsgBox "The document has been searched. " & _
frd.nNumReplaced & " changes made.", _
vbInformation Or vbOKOnly, "Find/Replace"
End Select
frd.bInReplaceMode = False
End Sub
Private Sub cboReplace_Change()
cmdReplace(0).Enabled = Len(cboReplace.Text) > 0
cmdReplace(1).Enabled = Len(cboReplace.Text) > 0
End Sub
Private Sub cboSearch_Change()
cmdFind.Enabled = Len(cboSearch.Text) > 0
End Sub
Private Sub chkMatchCase_Click()
'Using the InStr function, a value of 0
'indicates a binary search (aka match case),
'while a value of 1 indicates case-insensitive.
'This is easily set via a checkbox by the
'expression below.
'Setting bMatchCase here, rather on
'initializing the search, allows
'the case-sensitivity to be toggled
'while a search is in progress.
'This equation seem backwards but
'its setting bMatchCase to the same
'values represented by the InStr
'constants vbBinaryCompare and vbTextCompare.
'When chkMatchCase.value = 1 (checked)
'the expression (chkMatchCase.Value = 0)
'evaluates to False. Abs(False) is 0,
'and since 0 is the same value as the
'InStr constant vbBinaryCompare, a
'case sensitive search is performed.
'
'When chkMatchCase.value = 0 (unchecked)
'the expression (chkMatchCase.Value = 0)
'evaluates to True. Abs(True) is 1,
'and 1 is the same value as the
'InStr constant vbTextCompare, thus a
'case insensitive search is performed.
frd.bMatchCase = Abs(chkMatchCase.Value = 0)
End Sub
Private Sub chkCountOnly_Click()
frd.bCountOnly = chkCountOnly.Value = 1
cboReplace.Enabled = frd.bCountOnly = False
cmdReplace(0).Enabled = (frd.bCountOnly = False) And (Len(cboReplace) > 0)
cmdReplace(0).Enabled = cmdReplace(0).Caption = " Replace..."
cmdReplace(1).Enabled = (frd.bCountOnly = False) And (Len(cboReplace) > 0)
If frd.bCountOnly Then
'reset the counter to 0 because
'the routine always starts counting
'from the beginning
frd.nNumFound = 0
cmdFind.Caption = "Count"
Else
cmdFind.Caption = "Find &Next"
End If
End Sub
Private Function vFindInstance(currPos As Long, _
pStop As Long) As Boolean
With frd
If currPos = 0 Then currPos = 1
'if there is an in-string match...
If InStr(currPos, _
.sWorkText, _
.sSearchText, _
.bMatchCase) > 0 Then
'sWorkText constantly changes depending
'on action replace results, so needs to
'be referenced each call
LOWorkText = Len(.sWorkText)
'find the postitions of the instance
pStart = InStr(currPos, _
.sWorkText, _
.sSearchText, _
.bMatchCase)
pStop = pStart + Len(.sSearchText)
'highlight the text located text
ctlTarget.SelStart = pStart - 1
ctlTarget.SelLength = Len(.sSearchText)
'increment FRD.nNumFound and return true
If Not .bInReplaceMode Then
.nNumFound = .nNumFound + 1
vFindInstance = .nNumFound > 0
Else
vFindInstance = True
End If 'If Not FRD.bInReplaceMode
Exit Function
End If 'If InStr
vFindInstance = False
End With
End Function
Private Function vChangeInstance(pStart, _
pStop, _
LOInstance, _
LOSearch, _
LOReplace, _
LOWorkText) As Long
With frd
If InStr(.nCurrPos, _
.sWorkText, _
.sSearchText, _
.bMatchCase) > 0 Then
.nNumFound = .nNumFound + 1
If LOInstance = LOReplace Then
'if the LOInstance = LOreplace (same size),
'then do simple replace; the text
'length won't change here
ctlTarget.SelText = .sReplaceText
.nCurrPos = ctlTarget.SelStart + LOReplace
.sWorkText = ctlTarget.Text
.nNumReplaced = frd.nNumReplaced + 1
Else
'else the search and replace
'strings are different lengths,
'so replace and calculate the
'new end-of-cursor position
.nCurrPos = ((ctlTarget.SelStart + _
ctlTarget.SelLength) - LOSearch) _
+ LOReplace
ctlTarget.SelText = .sReplaceText
LOWorkText = LOWorkText + LOReplace
.sWorkText = ctlTarget.Text
.nNumReplaced = .nNumReplaced + 1
End If
vChangeInstance = .nNumReplaced > 0
Else
vChangeInstance = False
End If
End With
End Function
Private Sub FindReplaceInit()
'save the current textbox to
'a working variable
With frd
.sWorkText = ctlTarget.Text
'determine if there is at least
'1 instance before starting
If InStr(1, .sWorkText, .sSearchText, .bMatchCase) > 0 Then
'yep, so assign the search string
'and current cursor position
.nCurrPos = IIf(.bStartAtTop, 1, .nCursorPos)
End If
End With
End Sub
Private Function ChangeAll() As Long
Dim currPos As Long
Dim strSize As Long
With frd
currPos = InStr(1, .sWorkText, .sSearchText, .bMatchCase)
strSize = Len(.sWorkText)
.nNumReplaced = 0
'do the actual work
'starting with the current cursor position
'found above (the first match found in
'the textbox), change and find the next etc...
Do Until (currPos >= strSize) Or (currPos = 0)
Call ChangeNext(.sWorkText, currPos, strSize)
Loop
'Done. If changes were made,
'assign the new text to the textbox
If .nNumReplaced Then ctlTarget.Text = .sWorkText
ChangeAll = frd.nNumReplaced
End With
End Function
Private Function ChangeNext(msg As String, _
currPos As Long, _
strSize As Long) As String
'function called repeatedly by
'ChangeAll that locates each
'matching string in turn
Dim l As String
Dim r As String
'is there one?
If InStr(currPos, msg, frd.sSearchText, frd.bMatchCase) > 0 Then
'length of (LO) text
LOReplace = Len(frd.sReplaceText)
LOSearch = Len(frd.sSearchText)
LOWorkText = Len(msg)
'positions of instance
pStart = InStr(currPos, msg, frd.sSearchText, frd.bMatchCase)
pStop = pStart + Len(frd.sSearchText)
'end of instance (length of instance)
LOInstance = pStop - pStart
'if the search and replace strings
'are the same size, just do simple
'mid$ insert
If LOInstance = LOReplace Then
Mid$(msg, pStart) = frd.sReplaceText
currPos = pStop
frd.nNumReplaced = frd.nNumReplaced + 1
Else
'have to else split up the
'string to perform an insert
'l = string up to instance
'r = string after instance
l = Left$(msg, pStart - 1)
r = Mid$(msg, pStop, LOWorkText)
msg = l & frd.sReplaceText & r
currPos = Len(l) + LOReplace + 1
strSize = strSize + LOReplace
frd.nNumReplaced = frd.nNumReplaced + 1
End If
Else
currPos = strSize
End If
ChangeNext = msg
End Function
Private Sub FindReset()
'reset the search type variables
'so as not to confuse the next call
With frd
.nCurrPos = 1
.bCountOnly = chkCountOnly.Value = 1
.nCursorPos = 0
.bMatchCase = Abs(chkMatchCase.Value = 0)
.bStartAtTop = True
.nNumFound = 0
.nNumReplaced = 0
End With
pStop = 0
End Sub
Private Function CountSearch() As Long
With frd
'save the current textbox to
'a working variable
.sWorkText = ctlTarget.Text
'determine if there is at least
'one instance before starting
.nCurrPos = InStr(1, .sWorkText, .sSearchText, .bMatchCase)
If .nCurrPos > 0 Then
'only returns Boolean true or false;
'count is kept in FRD.nNumFound
Do While IsInstance(.nCurrPos)
Loop
End If
CountSearch = .nNumFound
End With
End Function
Public Sub SetupInit(bReplaceDialog As Boolean, _
Optional ctl As Control, _
Optional frmParent As Form)
'optional to allow this routine
'to be called from the Replace...
'button
If ctlTarget Is Nothing Then
Set ctlTarget = ctl
End If
'if bReplaceDialog is True, show as
'a Replace dialog by revealing
'appropriate controls
If bReplaceDialog Then
cmdReplace(0).Caption = "Replace"
cmdReplace(1).Visible = True
chkCountOnly.Top = 1950
chkMatchCase.Top = 1680
chkFindWhole.Top = 1410
cmdHelp.Top = 1950
cboDir.Top = 960
Frame1.Top = 860
Label1(2).Top = 1020
Label1(1).Visible = True
Label1(2).Visible = True
cboReplace.Visible = True
dlgReplace.Height = 2820
Me.Caption = "Replace Text"
Else
'hide controls not required
'for a Find
cmdReplace(0).Caption = " Replace..."
cmdReplace(0).Enabled = True
cmdReplace(1).Visible = True
Label1(1).Visible = False
Label1(2).Visible = True
cboReplace.Visible = False
Frame1.Top = 495
cboDir.Top = 525
cmdHelp.Top = 1530
Label1(2).Top = 590
chkFindWhole.Top = 945
chkMatchCase.Top = chkFindWhole.Top + 30 + chkFindWhole.Height
chkCountOnly.Top = chkMatchCase.Top + 30 + (chkMatchCase.Height)
dlgReplace.Height = 2460
Me.Caption = "Find Text"
End If
'once the form is correctly sized,
'it can be centered.
If Not frmParent Is Nothing Then
CentreFormInParent Me, frmParent
End If
End Sub
Private Function IsInstance(currPos As Long) As Boolean
'given the tracked cursor position,
'determines if, within the work text,
'an instance of the string occurs
Dim pos As Long
'is there an instance of the
'search word?
pos = InStr(currPos, _
frd.sWorkText, _
frd.sSearchText, _
frd.bMatchCase)
'if so,
If pos Then
'increment the currPos start
'counter to the position following
'the match
currPos = pos + Len(frd.sSearchText)
'increment counter and return true
frd.nNumFound = frd.nNumFound + 1
IsInstance = True
Exit Function
Else
IsInstance = False
End If
End Function |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comments | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Change the filename specified in Form1's Load sub (the calling form) to any valid text file on your machine, then save the project and run. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|||||
|
|||||
|
|
|||||
|
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |
![]() |