NEW: Class Module Replacement for Office FileSearch Object

D

David W. Fenton

Some of you may have been following the thread I started last week
about working with the FileSearch object. Once I found out that it's
been removed from Office 2007, I decided to see if I could replicate
the functionality I needed, and over the holiday weekend and this
evening, I've gradually put together a class module that replaces
almost all the functionality of the Office FileSearch object -- some
of it I couldn't replicated, or I didn't see any value in attempting
to do so.

I'd be very appreciative if people would bang on it and try to break
it, as well as look into some of the complicated issues I discuss
later on -- I need feedback on whether or not I've made the most
logical choices in attempt to replicate some of the more obscure
aspects of the FileSearch object.

Here's the summary from the class module header:

' FileSearch Object Properties and Methods
' PROPERTIES
' Application : irrelevant
' Creator : implemented
' FileName : implemented
' FileType : implemented
' FileTypes : implemented
' FileTypeSpecify : add by DWF
' FoundFiles : implemented
' LastModified : implemented
' LastModifiedSpecify : added by DWF
' LastModifiedSpecifyEnd : added by DWF
' LastModifiedSpecifyStart : added by DWF
' LookIn : implemented
' MatchAllWordForms : not implemented
' MatchTextExactly : implemented
' PropertyTests : not implemented
' SearchFolders : not implemented
' SearchPropertiesOnly : added by DWF
' SearchScopes : not implemented
' SearchSubFolders : implemented
' SearchTextOnly : added by DWF
' TextOrProperty : implemented
'
' METHODS
' Execute : implemented -- extended by DWF
' NewSearch : implemented
' RefreshScopes : not implemented

I could not implement MatchAllWordForms, unfortunately, as that
depends on functionality that is not exposed anywhere that I know
of.

I didn't feel that the SearchFolders and SearchScopes
collections collections were worth implementing, as they are aspects
of the FileSearch object as it exists that make it incredibly
complicated to work with. I also didn't implement the PropertyTests
collection as I couldn't see much utility in it. Because I didn't
implement the SearchScopes collection, there was no need to
implement the RefreshScopes method.

BTW, if you're wondering about a good reference for the Office
FileSearch object, all you need to do is open the VBAOF11.CHM (or 10
or 12) help file and search for "filesearch." It's is
pretty complete, and it's what I used to work things out. I don't
know why the VBE can't pull up that help file when you're coding for
the FileSearch Object, though.

I have more comments, observations and laments below, but if you're
curious right now, you can download it here:

http://dfenton.com/DFA/download/Access/FileSearch.zip

To work as designed, you also need to download the DSO OLE Document
Properties Reader:

http://support.microsoft.com/kb/224351 (version 2.1)

and register the DSOFile.dll. The class module should be able to be
used for plain text searches without needing to install and register
this DLL (I used late binding so that if it's not registered, it
doesn't cause fatal errors for non-property-based searches).

COMMENTS
========

I implemented two of the Office enumerations, for MsoLastModified
and for MsoFileType. Both raise significant questions as to what
they mean and how they should be used, but I implemented them for
consistency with the FileSearch Object.

MsoLastModified
===============
I don't know how to interpret the meaning of the constants, which
have these names:

msoLastModifiedAnyTime
msoLastModifiedLastMonth
msoLastModifiedLastWeek
msoLastModifiedThisMonth
msoLastModifiedThisWeek
msoLastModifiedToday
msoLastModifiedYesterday

(I also added msoLastModifiedSpecify since it was crucial to
implement additional functionality that I wanted to add)

AnyTime, Today and Yesterday are quite clear, of course. But it's
not clear to me hnow LastMonth, LastWeek, ThisMonth and ThisWeek
should be interpreted. I interpreted them respectively as:

msoLastModifiedLastMonth
: Between DateAdd("m", -2, Date And DateAdd("m", -1, Date
msoLastModifiedLastWeek
: Between DateAdd("ww", -2, Date And DateAdd("ww", -1, Date
msoLastModifiedThisMonth
: Between DateAdd("m", -1, Date And Date()
msoLastModifiedThisWeek
: Between DateAdd("ww", -1, Date And Date()

Another interpretation for the months would be that the current
month would be May, and the previous month would be April, and
likewise with week (current week beginning on Monday, May 25th, and
last week being the week beginning Monday, May 18th).

I don't know which makes more sense at all.

The logic behind it is in the class module's LastModified Property
Let and anyone could easily alter the definitions there to suit
their needs. MS hasn't implemented it consistently in any of the
places I looked, which included the WinXP search companion, Windows
Desktop Search and the Office FileSearch UI -- each one has
different choices and they aren't consistent with the choices
defined for the Office FileSearch object. I didn't test what the
results were, because I didn't have files with appropriate dates to
check on. I figured it's the kind of thing you'll either not use at
all (in which case it doesn't matter how I implement it), or it's
something you'll use but probably want to adjust the interpretation
for your own users. In other words, no matter what I implemented,
it's probably not going to get used in the exact form I did it if
it's used at all.

Anyway, in the sample database, I implemented a combo box of the
enumeration types, while also allowing the user to type in a
specific date. If you enter anything into the combo box other than
one of the predefined choices, the combo box's AfterUpdate event
assumes you want intended to type a specific date, and checks to see
if it's valid. If not, it prompts you to enter a valid date. Once
the valid date is entered, the TO textbox is enabled so you can
enter a range.

MsoFileType
===========
This is an enumeration of all the MS Office file types. It is
documented here:

http://msdn.microsoft.com/es-es/library/microsoft.office.core.msofile
type(VS.80).aspx

(I don't know why I ended up with the Spanish version)

I used that as a guide, but didn't follow it exactly. I also added
the OpenXML document extensions (e.g., xlsx, docx, etc.). For anyone
who uses it, note that the .FileType property handles only the file
types defined in the enumeration, which are:

msoFileTypeAllFiles
msoFileTypeBinders
msoFileTypeCalendarItem
msoFileTypeContactItem
msoFileTypeDatabases
msoFileTypeDataConnectionFiles
msoFileTypeDesignerFiles
msoFileTypeDocumentImagingFiles
msoFileTypeExcelWorkbooks
msoFileTypeJournalItem
msoFileTypeMailItem
msoFileTypeNoteItem
msoFileTypeOfficeFiles
msoFileTypeOutlookItems
msoFileTypePhotoDrawFiles
msoFileTypePowerPointPresentations
msoFileTypeProjectFiles
msoFileTypePublisherFiles
msoFileTypeTaskItem
msoFileTypeTemplates
msoFileTypeVisioFiles
msoFileTypeWebPages
msoFileTypeWordDocuments

I added a custom type:

msoFileTypeUserSpecified

so that the class module had a mechanism for handling other file
types. The .FileTypeSpecify property takes a single extension or a
comma-delimited list of extensions. The extension can be passed with
or without the wildcard character (everything before the . is
ignored). So you could assign "doc" or "*.doc" to the property and
it would have the same result, and likewise, "doc, csv, txt" or
"*.doc, *.csv, *.txt".

As I said, I interpreted the meaning of these constants more broadly
than the documentation said. For instance, there was no Excel
Spreadsheet choice that defined xls, xlt, etc. as the valid file
types, but only the ExcelWorkbooks constant. So I defined that as
being these extensions: xls, xlt, wbk, xlsx, xlsm, xltx, xltm, xlsb,
xlam (I don't know if there is an OpenXML wbk format -- I can't find
wbkx in Google, except as radio station call letters!).

Note also that for now, I've commented out all the extensions for
template files except for the msoFileTypeTemplates file type.

If in an application you need to provide a selection of file types
beyond the Office file types, it would be better to utilize only the
..FileTypeSpecify property since you could, for instance, provide a
multiselect listbox that would allow the selection of multiple file
types and then simply pass a comma-delimited list to the property. I
implemented the enumeration of Office documents in order to be
consistent with the Office FileSearch object but this somewhat
restricts the use of the .FileType property of the class module.
However, it does insure that the interface is completely consistent
in that regard with the FileSearch object -- as a replacement for
it, it will work fine.

But in general, I suspect that it will be more convenient to use the
..FileTypeSpecify property and use a table of file types to populate
a list box (or combo box) for the user to choose from.

Search File Properties
======================
In order to provide the ability to search OLE document properties, I
utilized an unsupported Microsoft ActiveX DLL, the DSO OLE Document
Properties Reader:

http://support.microsoft.com/kb/224351 (version 2.1)

As I said above, I wrote the class module with late binding so that
if it's not registered, it shouldn't be fatal. Without it, the
property searching doesn't work.

The implementation of this was very complicated, as I had to convert
VB6 code to figure out how it works, and it turned out that the
collection that the object returns (if you browse it with the object
viewer, it's the DSOFile.OleDocumentProperties.SummaryProperties
collection) is not loopable (as opposed to the
DSOFile.OleDocumentProperties.CustomProperties collection, which
worked just fine). I had to hard code each property retrieval one at
a time and that resulted in some *very* ugly code. Here's the code
for checking date properties:

Private Function SearchPropertiesDate(dteSearch As Date, _
Optional strPropertyName As String) As Boolean
Dim bolSingleProperty As Boolean
Dim bolTemp As Boolean
Dim dteLastSaved As Date

bolSingleProperty = (Len(strProperty) > 0)
If bolSingleProperty Then
Select Case strProperty
Case "DateLastSaved"
GoTo DateLastSaved
Case "DateCreated"
GoTo DateCreated
Case "DateLastPrinted"
GoTo DateLastPrinted
End Select
End If
If dteSearch = 0 Then GoTo exitRoutine
DateLastSaved:
bolTemp=InStr(DSOFileDoc.SummaryProperties.DateLastSaved,dteSearch)
If bolTemp Or bolSingleProperty Then GoTo exitRoutine
DateCreated:
bolTemp=InStr(DSOFileDoc.SummaryProperties.DateCreated, dteSearch)
If bolTemp Or bolSingleProperty Then GoTo exitRoutine
DateLastPrinted:
bolTemp=InStr(DSOFileDoc.SummaryProperties.DateLastPrinted,
dteSearch) If bolTemp Or bolSingleProperty Then GoTo exitRoutine

exitRoutine:
SearchPropertiesDate = bolTemp
End Function

Let me explain that code.

First, when searching all the properties, I wanted it to short
circuit -- that is, as soon as the first property matched the
criteria, I wanted to return True and exit. This is why it has all
those tests and "oTo exitRoutine" jumps -- it's simply that there's
no utility in knowing that two properties matched the same search
string.

Second, I also wanted to be able to provide the capability of
searching for specific properties. The only way I could think to do
that was with GoTos, which is why it's so incredibly ugly!

But it's all caused by the lack of looping through the collection.
The code sample that came with the download of the DLL also didn't
walk through the SummaryProperties collection, so I doubt that it's
possible. If someone can figure it out, I'd gladly rework that code
to make it less stupid! For now, it does work, though.

Search Results May Not Be Identical to FileSearch Object
=========================================================
I've tried to be as flexible and commonsensical as possible in my
implementation of the searching, but there's a major interaction
between the logic of the class module's searching functionality and
UI. Let me explain.

The main guts of the search process is in a subroutine called
SearchFileForText. In it, first the files are searched for text,
then for last update (through the Access FileDateTime() function),
and then for the OLE properties. Whether or not SearchFileForText
returns true depends on two things:

1. the results of the three searches.

2. the appropriate combination of those three results.

Now, because there was no way for me to have a text search ignore
properties embedded in the header of the document, I made a decision
to allow a choice only between searching Properties Only or Both
Properties and Text. This is the way the FileSearch object actually
implements it so far as I can tell (the UI in Office has never given
you the choice of searching text only, just both or properties
only), so I would tend to think it's not doing anything special
about reading only certain parts of the OLE stream.

I've tried to implement things in a way that makes sense and that
behaves sensibly, but you all know how that goes -- when you're
heads down programming on a project, you lose sight of the bigger
picture.

I hope that some of you will test it out and find bugs and maybe
figure out how to make it work better or more efficiently.
 
D

David W. Fenton


I just uploaded a new update. It refactors the central search
method, SearchFileForText, as well as the logic determining whether
to return a document as a match. It shouldn't behave any
differently, but it should be a lot easier to understand.

I have another update coming later today that will incorporate the
ability to choose what type of text match (match all, match any,
match exact).

I'm also considering whether I might incorporate Regular Expressions
into the full-text search. Right now, it's set up using InStr() and
searching word by word from the criteria, but RegEx might make it
quite easy to do more complex searches.

Thoughts anyone?
 
D

David W. Fenton

I just uploaded a new update.

I just uploaded yet another update. This one implements a new
MatchTextType property with this enumeration:

Public Enum osfMatchTextType
osfMatchTextTypeMatchAll = 1
osfMatchTextTypeMatchExact = 2
osfMatchTextTypeMatchAny = 3
End Enum

This overlaps with the MatchTextExactly property that is there for
consistency with the Office FileSearch Object. But this
implementation is more flexible.

The example form features an example of how to implement it, and the
searches all work with it.

Back to real work! :)
 
L

Lars Brownies

David,

Cool how you made this!

Some minor things I noticed:
1. If you accidentally type a non existing folder, it would be nice to get a
"Folder doesn't exist" warning.
2. If I search 'named' test in D:\My Documents with underlying folders
checked, it doesn't find D:\My Documents\MyFolder\Test.doc
3. If I 'search for:' test in a folder with video-files, I get the error: 14
during execution, unsufficient character space. If I then choose 'cancel'
the mousepointer remains an hourglass
I don't have the DSOfile.dll installed yet, so this might have to do with
that. Since some people aren't allowed to install dll's at work, it would be
nice to be able to exclude its functionality easily. Maybe that's already
possible, but it seems you can't search text in files only. It's always
binded to searching through the properties.

Lars
 
D

David W. Fenton

Cool how you made this!

I went overboard on it, but it will make implementing it in my new
client's app really easy.
Some minor things I noticed:
1. If you accidentally type a non existing folder, it would be
nice to get a "Folder doesn't exist" warning.

That's UI issue, not an issue about the class module. The form in
the demo database is not intended as a recommended implementation of
the UI for the class module, only something that demonstrates what
the class module can do. I just went ahead and implemented it in the
demo. I made the FSO property of the class module public, and then
coded the textbox's BeforeUpdate event thus:

Private Sub txtSearchFolder_BeforeUpdate(Cancel As Integer)
If Not clsFileSearch.FSO.FolderExists(Me!txtSearchFolder) Then
MsgBox "That folder does not exist.", vbExclamation, _
"Folder doesn't exist!"
Cancel = True
Me!txtSearchFolder.Undo
End If
End Sub
2. If I search 'named' test in D:\My Documents with underlying
folders checked, it doesn't find D:\My Documents\MyFolder\Test.doc

This was a tricky one. I'm using Dir() to test, and if the top-level
folder doesn't have a match, it was short-circuiting out and not
searching the subfolders, because this is what it was doing:

strFileMatch = Dir(strSearchFolder & "\" & strFileName)
If Len(strFileMatch) = 0 Then
Exit Sub
End If

So, I replaced that with this:

If Len(strFileMatch) = 0 And Not bolSearchSubFolders Then
Exit Sub
ElseIf Len(strFileMatch) = 0 Then
GoTo SearchSubFolders
End If

What happens is that if there's no match and you're not searching
subfolders, you quit, but if you *are* searching them, you skip over
the code that adds the filename to the collection of files to search
and goes straight to checking the subfolders. Otherwise, it falls
right through this If/Then to add the filename to the collection of
files to check because Len(strFileMatch) is >0 so that neither of
the tests passes.

That was a tricky one!

And exactly why I need other people looking at it and testing it.

Thanks!
3. If I 'search for:' test in a folder with video-files, I get the
error: 14 during execution, unsufficient character space. If I
then choose 'cancel' the mousepointer remains an hourglass

I haven't a clue. Where is it erroring out? Are you using one of the
versions I uploaded that had the error handling turned off? The fact
that the hourglass remains turned on means nothing at all -- just
hit Ctrl-G and type DoCmd.Hourglass = False. It's just part of the
aftermath of an unhandled error that doesn't exist properly and turn
the hourglass off.
I don't have the DSOfile.dll installed yet, so this might have to
do with that. Since some people aren't allowed to install dll's at
work, it would be nice to be able to exclude its functionality
easily. Maybe that's already possible, but it seems you can't
search text in files only. It's always binded to searching through
the properties.

That's a good idea. I've implemented a TextOnly Boolean property
that causes the property search to be skipped. It still searches the
properties, of course, since the properties are part of the text
(this is why I didn't implement it before, because there could not
be any difference between TextOnly and TextOrProperties), but in
order to allow the class module to be used without installing the
DSOFile DLL, I think it's a good idea. You just have to be sure you
understand that there is actually never going to be any difference
between the the results returned with either setting.

So, I've uploaded the new version to the same location:

http://dfenton.com/DFA/download/Access/FileSearch.zip

Please, folks! Download it and try it out!
 
L

Lars Brownies

David W. Fenton said:
I haven't a clue. Where is it erroring out? Are you using one of the
versions I uploaded that had the error handling turned off? The fact
that the hourglass remains turned on means nothing at all -- just
hit Ctrl-G and type DoCmd.Hourglass = False. It's just part of the
aftermath of an unhandled error that doesn't exist properly and turn
the hourglass off.

I used the latest version. The code stops in Private Sub cmdSearch_Click()
on
intFoundFilesCount = .Execute()

I did some other testing by file searching for text only in folders with
pictures, as this could happen accidentaly. But Access hangs when I do this.
If I will implement it, I think I will restrict the 'search for' option to
specific file types, excluding *.jpd, *.mpg, etc.
That's a good idea. I've implemented a TextOnly Boolean property
that causes the property search to be skipped. It still searches the
properties, of course, since the properties are part of the text
(this is why I didn't implement it before, because there could not
be any difference between TextOnly and TextOrProperties), but in
order to allow the class module to be used without installing the
DSOFile DLL, I think it's a good idea. You just have to be sure you
understand that there is actually never going to be any difference
between the the results returned with either setting.

So, I've uploaded the new version to the same location:

http://dfenton.com/DFA/download/Access/FileSearch.zip

Please, folks! Download it and try it out!

Thanks! I don't quite understand why others haven't responded.

Lars
 
D

David W. Fenton

I used the latest version. The code stops in Private Sub
cmdSearch_Click() on
intFoundFilesCount = .Execute()

I did some other testing by file searching for text only in
folders with pictures, as this could happen accidentaly. But
Access hangs when I do this. If I will implement it, I think I
will restrict the 'search for' option to specific file types,
excluding *.jpd, *.mpg, etc.

Questioh:

Where are you typing these file extensions? In the File Type
dropdown, or in the Named field? I just tested those two extensions
and if I type them into the Named field ("jpd mpg"), I get nothing.
If I type them into the File Type dropdown ("jpd, mpg"), I get
nothing. But if I type "*.jpd, *.mpg" into the File Type dropdown, I
get matches.

I will have to audit the code there. There's obvious a logic
problem, as all three of those should return files that have either
of those extensions.

I would suggest you turn off all the error checking by changing all
On Error GoTo errHandler to 'On Error GoTo errHandler, then do the
same thing to produce the error. That will tell you exactly which
line of code is producing the error.

Oh, yes, you also want to make sure that on the General tab of the
VBE Options dialog, be sure to choose for the Error Trapping option
group BREAK IN CLASS MODULE. If you don't do this, you won't see the
actual class module code that is producing the error that's
happening because you're calling the .Execute method of the class
module.

The default for this is BREAK ON UNHANDLED ERRORS, which I believe
is totally the wrong setting, because it leads right to this kind of
problem.

Once you find out what line of code is actually producing the error,
I can then try to figure it out.
 
L

Lars Brownies

David W. Fenton said:
Questioh:

Where are you typing these file extensions? In the File Type
dropdown, or in the Named field? I just tested those two extensions
and if I type them into the Named field ("jpd mpg"), I get nothing.
If I type them into the File Type dropdown ("jpd, mpg"), I get
nothing. But if I type "*.jpd, *.mpg" into the File Type dropdown, I
get matches.

That "jpd" was a typo and should have been "jpg".
I'm not typing in file extensions. This is what I did:
1. I selected a folder with 154 jpg files, with a total of 189 MB.
2. I entered "test" in the field "Search for" and entered "Text only" in the
field "Search in".

I tested again and it appears that Access doesn't hang, but the whole search
process just takes about 15 minutes, which is understandable but long. At
first I got the impression it hung but I've waited the process to finish,
wich it does.

If I search for text in the filenames in that same folder, it's done
instantly.

If users want to search for text in a file and they select a folder
including subfolders, there could be a large folder with "jpg" files. I
wouldn't want them to end up in a half hour search, or I would want to warn
them about the length of the search time. On the other hand, I don't know if
user deliberately want to search for text within "jpg" or "mpg" files, so
excluding some file types when searching within files would be an option.

A minor issue in the UI form is the following: If you enter a wrong
foldername, you get the warning "folder doesn't exists". The entered
foldername is then highlighted and if you hit the delete button, the text is
removed. However, if you then want to move to another field by tabbing, it
gives the error: "Types don't match", breaking on the line:

If Not clsFileSearch.FSO.FolderExists(Me!txtSearchFolder) Then

Another minor UI issue is that if you entered a value in 'Search for', the
'Search in' field is not yet available. You can't pick a value in it with
the mouse, so you are forced to move to it by tab first.

It might be good to put the enable/disable code for the 'Search in' field in
the 'Search for' field's change event and test on every keystroke if there's
a value or not.

Lars
 
D

David W. Fenton

That "jpd" was a typo and should have been "jpg".

Ah. I was assuming it was some filetype unknown to me.
I'm not typing in file extensions. This is what I did:
1. I selected a folder with 154 jpg files, with a total of 189 MB.
2. I entered "test" in the field "Search for" and entered "Text
only" in the field "Search in".

I tested again and it appears that Access doesn't hang, but the
whole search process just takes about 15 minutes, which is
understandable but long. At first I got the impression it hung but
I've waited the process to finish, wich it does.

Well, why would you search JPGs for text? They are binary files, and
so far as I know, don't have any text in them at all. Well, there's
the JFIF at the beginning, defining the compression type, and often
a creator application string (two I saw were Applemark and something
else I forget). But I don't know why you'd search for text in files
that don't have text in them.
If I search for text in the filenames in that same folder, it's
done instantly.

Yes, because it's searching orders of magnitude less data, as well
as using completely different methods to do so. For filenames, it
does a Dir() on the folder and filespec and then calls Dir() in a
loop and checks each filename in turn (using InStr()) until Dir()
returns a zero-length string.

The text search opens each file, copies the entire data into a
string variable and then does the InStr() on that variable. So, for
each filespec matched, you're comparing an InStr() on strings of 255
characters or less (file/path names have to be shorter than that,
though I don't remember the exact length limitation) against InStr()
performed on strings that are 10s of KBs in length (if not longer).
100 filenames is 100 checks of 255-max characters, or at most,
255,000 compared characters. 100 JPGs are likely to be closer to
25,000,000 characters (assuming an average of 25KBs per file, which
is not necessarily realistic). That's 255K vs. 25MBs of data
searched. That it would take 10 or 100 times longer should not be
surprising!
If users want to search for text in a file and they select a
folder including subfolders, there could be a large folder with
"jpg" files. I wouldn't want them to end up in a half hour search,
or I would want to warn them about the length of the search time.
On the other hand, I don't know if user deliberately want to
search for text within "jpg" or "mpg" files, so excluding some
file types when searching within files would be an option.

This is a UI implementation issue, I think. Perhaps the class module
could use an exclusion list for extensions, but I'm not sure I would
ever use it.
A minor issue in the UI form is the following: If you enter a
wrong foldername, you get the warning "folder doesn't exists". The
entered foldername is then highlighted and if you hit the delete
button, the text is removed. However, if you then want to move to
another field by tabbing, it gives the error: "Types don't match",
breaking on the line:

If Not clsFileSearch.FSO.FolderExists(Me!txtSearchFolder) Then

Yes, because the folder textbox is Null. I've added this line at the
beginning of txtSearchFolder's BeforeUpdate event:

If IsNull(Me!txtSearchFolder) Then Exit Sub

But that's not a flaw in the class module -- it's just a flaw of my
knocked-together sample UI, which I didn't promise was perfect!
While I'd like my demo to be robust, I'm much more concerned with
finding flaws in the actual class module than with the demo search
form.
Another minor UI issue is that if you entered a value in 'Search
for', the 'Search in' field is not yet available. You can't pick a
value in it with the mouse, so you are forced to move to it by tab
first.

This seems completely natural interaction with the UI to me, to be
honest.
It might be good to put the enable/disable code for the 'Search
in' field in the 'Search for' field's change event and test on
every keystroke if there's a value or not.

If you're implementing it in your own app, you can do that.

I just did something similar in a client app yesterday. I offer a
"Simple Search" that searches a predefined folder for Word
documents. The only field the user fills out is the Search For
field, i.e., the sought-after string. I did implement an OnChange
event that enables the Search button when the first character is
typed. However, it doesn't work if you paste text into the textbox
from the clipboard. I haven't figured out what event to use for
that.

But again, these are UI issues, not problems with the actual class
module. That you're concentrating on these things suggests to me
that the class module itself is working fairly robustly (with the
exception of the problem I mentioned in my last post about not
properly search "jpg mpg" in the filename and file type. I have too
much client work to do to work on that for now. I will try to get to
it by the weekend.

Thanks again for all your feedback! I wish more people were
interested.
 
L

Lars Brownies

Well, why would you search JPGs for text?

Not deliberately, but there could be folders that contain both text/doc
files and jpg files. Also when you search a great amount of underlying
folders, you may not know that those folders hold jpg files.
This seems completely natural interaction with the UI to me, to be
honest.

I have a different opinion. Users are forced to first leave field A. IMO,
when field A holds some kind of value, users should be able to select a
value in field B.
field, i.e., the sought-after string. I did implement an OnChange
event that enables the Search button when the first character is
typed. However, it doesn't work if you paste text into the textbox
from the clipboard. I haven't figured out what event to use for
that.

It's the right event. You can use the field's text property, which gets
updated at every change:

if len(YourField.text)>0 then
btnSearch.enabled = True
else
btnSearch.enabled = False
endif
But again, these are UI issues, not problems with the actual class
module. That you're concentrating on these things suggests to me
that the class module itself is working fairly robustly (with the

True.

Lars
 
D

David W. Fenton

Not deliberately, but there could be folders that contain both
text/doc files and jpg files. Also when you search a great amount
of underlying folders, you may not know that those folders hold
jpg files.

That is, of course, a UI issue, not one that should be addressed in
the class module itself. The class module should allow you to search
anything and not nag you with "advice" or warnings. But the UI of a
particular implementation of the class module might restrict the
searchable file types. My implementation has no such restrictions,
because I want to allow flexibility.
I have a different opinion. Users are forced to first leave field
A. IMO, when field A holds some kind of value, users should be
able to select a value in field B.

Again, this is a UI implementation issue. You could choose to do it
differently than I did in the demo. It has nothing at all to do with
the class module itself, which, despite the one problem with
extensions that I haven't yet had time to investigate, seems to be
working well.
It's the right event. You can use the field's text property, which
gets updated at every change:

if len(YourField.text)>0 then
btnSearch.enabled = True
else
btnSearch.enabled = False
endif

Yes, but I don't want to run the event on every typed character,
because that can lead to screen flicker.

I didn't actually intend the demo form to be bullet-proof. I'm
implementing it in a client app right now and doing it completely
differently in terms of which parts of the UI are available when
(and some of them from the demo aren't even being included).
 
D

David W. Fenton


By the way, I want to express my deep gratitude to you for taking
the time to work with my demo and give me feedback. It is invaluable
to me in many ways.

I just wish we could convince others to do the same.

I'm in the process of creating a web page for it with the
explanations all in one place (excerpted from my posts here). When I
finish that I'll post again and maybe that will attract some more
testers.
 
L

Lars Brownies

You're welcome. And thank you for sharing your work!

One reason that others haven't tested it, may be that a most readers aren't
familiar with using classes. I wasn't and didn't know it was actually pretty
easy to implement.

Btw: I use A2003 and I have several forms using the cange events in the way
I described, and I've never seen any screen flickering.

Lars
 
D

David W. Fenton

Btw: I use A2003 and I have several forms using the cange events
in the way I described, and I've never seen any screen flickering.

Perhaps it's something I encountered in older versions.

I don't like using it because the principle bothers me. Perhaps one
could use a module-level variable to deal with it, I guess, and set
it in the OnEnter event in order to avoid running the code for every
keystroke.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top