这个是pas文件,窗体文件和全部代码请到http://wolfsoft.nugoo.com上下载.
unit DBlocate;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls, Buttons, db, ExtCtrls;
//dbtables, dbctrls;
type
TDBLocateMatchType = (mtExactMatch, mtPartialMatchStart, mtPartialMatchAny);
TDBFieldSortType = (fsSortByFieldNo, fsSortByFieldName);
TDBDefaultButtonType = (dbFindFirst, dbFindNext);
TDBFieldSelection = (fsAllFields, fsVisibleFields);
TDBLocateDlg = class;
TDBOnInitLocateDlgEvent = procedure(Dialog: TDBLocateDlg) of object;
TDBLocateSelectFieldEvent = procedure(Dialog: TDBLocateDlg; SearchField: string) of object;
TDBCustomDialog = class(TComponent)
protected
public
function Execute: Boolean; virtual; abstract;
function GetPrimaryDataSet: TDataSet; virtual; abstract;
end;
TDBCustomDialogClass = class of TDBCustomDialog;
TDBLocateDlg = class(TForm)
SearchTypeGroup: TGroupBox;
CaseSensitiveCheckBox: TCheckBox;
ExactMatchBtn: TRadioButton;
PartialMatchStartBtn: TRadioButton;
PartialMatchAnyBtn: TRadioButton;
Panel1: TPanel;
FieldValueGroup: TGroupBox;
SearchValue: TEdit;
FirstButton: TButton;
NextButton: TButton;
FieldsGroup: TGroupBox;
FieldNameComboBox: TComboBox;
BtnClose: TButton;
procedure FindFirst(Sender: TObject);
procedure FindNextBtnClick(Sender: TObject);
procedure BitBtn1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FieldNameComboBoxChange(Sender: TObject);
procedure FieldNameComboBoxEnter(Sender: TObject);
procedure FieldNameComboBoxExit(Sender: TObject);
procedure FieldNameComboBoxKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormShow(Sender: TObject);
private
function GetFieldNameFromTitle(fieldTitle: string): string;
public
DataSet: TDataSet;
CancelBtn: TButton;
DlgComponent: TComponent;
function FindMatch(FromBeginning: boolean): boolean;
constructor Create(AOwner: TComponent); override;
end;
TDBLocateDialog = class(TDBCustomDialog)
private
FCaption: string;
FDataField: string;
FDataLink: TDataLink;
FFieldValue: string;
FMatchType: TDBLocatematchType;
FCaseSensitive: boolean;
FSortFields: TDBFieldSortType;
FDefaultButton: TDBDefaultButtonType;
FFieldSelection: TDBFieldSelection;
FShowMessages: boolean;
FOnInitDialog: TDBOnInitLocateDlgEvent;
FOnSelectField: TDBLocateSelectFieldEvent;
procedure SetDataSource(value: TDataSource);
function GetDataSource: TDataSource;
protected
procedure DoInitDialog; virtual; { called by locate dialog form }
public
Form: TDBLocateDlg; {Used by TDBLocateDlg }
Patch: Variant;
function GetPrimaryDataSet: TDataSet; override;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function Execute: boolean; override; { shows dialog }
function FindPrior: boolean;
function FindNext: boolean;
function FindFirst: boolean;
property FieldValue: string read FFieldValue write FFieldValue;
published
property Caption: string read FCaption write FCaption;
property DataSource: TDataSource read GetDataSource write SetDataSource;
property SearchField: string read FDataField write FDataField;
property MatchType: TDBLocateMatchType read FMatchType write FMatchType;
property CaseSensitive: boolean read FCaseSensitive write FCaseSensitive;
property SortFields: TDBFieldSortType read FSortFields write FSortFields;
property DefaultButton: TDBDefaultButtonType read FDefaultButton write FDefaultButton;
property FieldSelection: TDBFieldSelection read FFieldSelection write FFieldSelection;
property ShowMessages: boolean read FShowMessages write FShowMessages;
property OnInitDialog: TDBOnInitLocateDlgEvent read FOnInitDialog write FOnInitDialog;
property OnSelectField: TDBLocateSelectFieldEvent read FOnSelectField write FOnSelectField;
end;
function ccFindMatch(FromBeginning: boolean;
DataSet: TDataSet;
searchField: string;
searchValue: string;
matchType: TDBLocateMatchType;
caseSens: boolean): boolean;
procedure Register;
var
DBLocateDlg: TDBLocateDlg;
implementation
uses comctrls, typInfo;
{$R *.DFM}
function ccEqualStr(s1, s2: string): boolean;
begin
result := uppercase(s1) = uppercase(s2);
end;
function strReplaceChar(str: string; removeChar, replaceChar: char): string;
var
tempstr: string;
APos, endStringPos: integer;
begin
APos := 1;
repeat
tempStr := copy(str, APos, length(str) + 1 - APos);
endStringPos := Pos(removeChar, tempStr) + (APos - 1);
if EndStringPos >= APos then
begin
Delete(Str, EndStringPos, 1);
Insert(ReplaceChar, Str, EndStringPos);
APos := EndStringPos + 1;
end
else
break;
until False;
result := str;
end;
procedure strBreakApart(s: string; delimeter: string; parts: TStrings);
var
curpos: integer;
curStr: string;
begin
parts.clear;
curStr := s;
repeat
curPos := pos(delimeter, curStr);
if (curPos > 0) then
begin
parts.add(copy(curStr, 1, curPos - 1));
curStr := copy(curStr, curPos + 1, length(curStr) - (curPos));
end
else
parts.add(curStr);
until curPos = 0;
end;
function ccStrToFloat(const S: string): boolean;
var
Buffer: array[0..63] of char;
Temp: Extended;
begin
result := True;
if length(s) = 0 then exit;
result := TextToFloat(StrPLCopy(Buffer, S, Sizeof(Buffer) - 1), Temp, fvExtended);
end;
function ccisNonPhysicalField(thisField: TField): boolean;
begin
result := thisfield.calculated or thisfield.lookup;
end;
function ccGetControlType(DataSet: TComponent): TStrings;
var
PropInfo: PPropInfo;
begin
Result := nil;
if DataSet = nil then exit;
PropInfo := Typinfo.GetPropInfo(DataSet.ClassInfo, 'ControlType'); { Delphi 5}
if PropInfo <> nil then
result := TStrings(GetOrdProp(DataSet, PropInfo));
end;
function ccIsClass(ClassType: TClass; const Name: string): Boolean;
begin
Result := True;
while ClassType <> nil do
begin
if ccEqualStr(ClassType.ClassName, Name) then Exit;
ClassType := ClassType.ClassParent;
end;
Result := False;
end;
function ccisNonBDEField(thisField: TField): boolean;
begin
result := thisfield.calculated or thisfield.lookup;
if (not result) and (thisField.dataset <> nil) then
result := not ccIsClass(thisField.dataset.classType, 'TBDEDataSet');
end;
function ccIsRichEditField(Field: TField; ExamineData: boolean): boolean;
var
i: integer;
controlType: TStrings;
BlobStream: TStream;
Buffer: packed array[1..5] of char;
begin
result := False;
if (Field = nil) then exit;
if not (Field is TBlobField) then exit;
controlType := ccGetControlType(Field.Dataset);
if ControlType <> nil then
for i := 0 to ControlType.count - 1 do
begin { Delphi 5}
if pos(Field.FieldName + ';RichEdit', ControlType) = 1 then
begin
result := True;
exit;
end
end;
if not ExamineData then exit;
BlobStream := Field.DataSet.CreateBlobStream(Field, bmRead);
try
Buffer := ' ';
BlobStream.Read(Buffer, 5);
result := Buffer = '{/rtf'
finally
BlobStream.Free;
end;
end;
function Match(val1: string; val2: string;
matchType: TDBLocateMatchType;
caseSens: boolean): boolean;
var
matchPos: integer;
begin
if not caseSens then val1 := AnsiUppercase(val1);
if MatchType = mtExactMatch then
begin
if length(val1) <> length(val2) then
result := False
else
begin
if length(val1) = 0 then
result := True
else
begin
matchPos := Pos(val2, val1);
result := (matchPos = 1);
end
end
end
else if matchType = mtPartialMatchStart then
begin
matchPos := Pos(val2, val1);
result := (matchPos = 1);
end
else if MatchType = mtPartialMatchAny then
begin
matchPos := Pos(val2, val1);
result := (matchPos <> 0);
end
else
result := False;
end;
function MemoMatch(field: TField;
memoBuffer: PChar; val1: Pchar;
matchType: TDBLocateMatchType;
caseSens: boolean;
RichEditControl: TRichEdit): boolean;
var
matchPos: Integer;
s: string;
begin
if RichEditControl <> nil then
begin
RichEditControl.PlainText := False;
RichEditControl.Lines.Assign(Field);
RichEditControl.PlainText := True;
s := RichEditControl.Text;
end
else
s := field.asstring;
if not caseSens then s := AnsiUpperCase(s);
if MatchType = mtExactMatch then
begin
{$WARNINGS Off}
if strlen(val1) <> length(s) then
result := False
{$WARNINGS On}
else
begin
matchPos := AnsiPos(StrPas(val1), s);
result := (matchPos = 1);
end
end
else if matchType = mtPartialMatchStart then
begin
matchPos := AnsiPos(StrPas(val1), s);
result := (matchPos = 1);
end
else if MatchType = mtPartialMatchAny then
begin
matchPos := AnsiPos(StrPas(val1), s);
result := (matchPos <> 0);
end
else
result := False;
end;
{
function ValueAsString(field: TField; buffer: PChar): string;
type
WordPtr = ^Word;
IntegerPtr = ^Integer;
LongPtr = ^LongInt;
FloatPtr = ^Double;
TDateTimeRec = record
case TFieldType of
ftDate: (Date: Longint);
ftTime: (Time: Longint);
ftDateTime: (DateTime: TDateTime);
end;
DateTimePtr = ^TDateTimeRec;
var
DateTimeData: TDateTimeRec;
floatValue: Double;
TimeStamp: TTimeStamp;
begin
result := '';
case field.DataType of
ftString:
begin
if (field is TStringField) then
if TStringField(field).transliterate then
begin
Field.DataSet.Translate(Buffer, Buffer, False);
end;
result := strPas(buffer);
end;
ftSmallInt, ftWord: result := inttostr(WordPtr(buffer)^);
ftInteger: result := inttostr(LongPtr(buffer)^);
ftAutoInc: result := inttostr(LongPtr(buffer)^);
ftFloat, ftBCD, ftCurrency:
begin
floatValue := FloatPtr(buffer)^;
result := floattostr(floatValue);
end;
ftBoolean:
begin
if buffer[0] <> char(0) then
result := '是'
else
result := '否';
end;
ftDateTime:
begin
DateTimeData := DateTimePtr(buffer)^;
result := DateToStr(TimeStampToDateTime(MSecsToTimeStamp(FloatPtr(Buffer)^)));
end;
ftDate:
begin
DateTimeData := DateTimePtr(buffer)^;
TimeStamp.Time := 0;
TimeStamp.Date := DateTimeData.Date;
result := DateToStr(TimeStampToDateTime(TimeStamp));
end;
ftTime:
begin
DateTimeData := DateTimePtr(buffer)^;
result := TimeToStr(DateTimeData.Time / MSecsPerDay);
end;
else
;
end
end;
}
function ccFindMatch(FromBeginning: boolean;
DataSet: TDataSet;
searchField: string;
searchValue: string;
matchType: TDBLocateMatchType;
caseSens: boolean): boolean;
var
FindText, TableFieldValue: string;
MatchFound: boolean;
cfindText, recBuffer, buffer, memobuffer: PChar;
Bookmark: TBookmark;
curfield: TField;
stopOnMismatch: boolean;
TempRichEdit: TRichEdit;
isEof: Boolean;
function IndexCaseSensitive(Tbl: TDataSet): boolean;
begin
result := False;
end;
{ Make sure indexed field is in field map}
function ValidIndexField: boolean;
var
parts: TStrings;
begin
result := False;
parts := TStringList.create;
parts.Free;
end;
procedure ApplyMatch;
begin
dataset.updatecursorpos;
dataset.resync([rmExact, rmCenter]); { Always call resync }
MatchFound := True;
end;
function FloatingType(field: TField): boolean;
begin
result := field.DataType in [ftFloat, ftBCD, ftCurrency];
end;
function GetNextFieldValue(Forward: boolean; var FieldValue: string): boolean;
begin
FieldValue := '';
begin
Result := not DataSet.eof;
if Result then
begin
Dataset.Next;
isEof := DataSet.eof;
FieldValue := curField.Text;
end
end
end;
begin
Result := False;
if Dataset.Eof then Exit;
DataSet.checkBrowseMode;
curField := DataSet.findField(searchField);
if curField = nil then
begin
MessageDlg('Field ' + searchField + ' not found.', mtWarning, [mbok], 0);
exit;
end;
DataSet.updateCursorPos;
if not caseSens then
FindText := AnsiUppercase(SearchValue)
else
FindText := SearchValue;
stopOnMismatch := False;
buffer := nil;
recBuffer := nil;
cfindText := nil;
memoBuffer := nil;
bookmark := nil;
tempRichEdit := nil;
try
GetMem(buffer, 32767);
GetMem(recBuffer, 256);
Bookmark := Dataset.GetBookmark;
if FromBeginning then
begin
DataSet.First; { do before allocating blob }
DataSet.updateCursorPos;
end;
Screen.cursor := crHourGlass;
if FromBeginning then
begin
if (matchType = mtExactMatch) and FloatingType(curField) and (FindText <> '') then
begin
if ccStrToFloat(FindText) and (curField.asFloat = StrToFloat(FindText)) then
begin
ApplyMatch;
exit;
end
end
else if Match(curField.Text, FindText, matchType, caseSens) then
begin
ApplyMatch;
exit;
end;
DataSet.updateCursorPos;
end;
MatchFound := False;
Dataset.DisableControls;
isEof := False;
while GetNextFieldValue(True, TableFieldValue) and (not isEof) do
begin
if (matchType = mtExactMatch) and FloatingType(curField) and (FindText <> '') then
begin
if ccStrToFloat(FindText) and (TableFieldValue <> '') and
(StrToFloat(TableFieldValue) = StrToFloat(FindText)) then
begin
ApplyMatch;
exit;
end
end
else if Match(TableFieldValue, FindText, matchType, caseSens) then
begin
ApplyMatch;
break;
end
else if StopOnMismatch then
break;
end
finally
Dataset.EnableControls;
FreeMem(recBuffer, 256);
FreeMem(buffer, 32767);
if curField.dataType = ftMemo then
begin
FreeMem(cFindText, 256);
FreeMem(memoBuffer, 32767);
end;
Screen.cursor := crDefault;
if (not MatchFound) then dataSet.gotoBookmark(bookmark);
dataSet.FreeBookmark(bookmark);
tempRichEdit.Free;
result := MatchFound;
end;
end;
constructor TDBLocateDlg.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
CancelBtn := TButton.Create(Self);
CancelBtn.TabOrder := 5;
CancelBtn.Width := (screen.pixelsperinch * 72) div 96;
CancelBtn.visible := True;
CancelBtn.Top := NextButton.Top;
CancelBtn.Left := FieldsGroup.Left + FieldsGroup.Width - CancelBtn.Width - 1;
CancelBtn.Height := (screen.pixelsperinch * 27) div 96;
end;
function TDBLocateDlg.GetFieldNameFromTitle(fieldTitle: string): string;
var
i: integer;
begin
result := '';
with DataSet do
begin
{ Give priority to non-calculated fields of the same name, if they exist }
for i := 0 to fieldCount - 1 do
begin
if ccisNonPhysicalField(fields) then continue;
if strReplaceChar(fields.displayLabel, '~', ' ') = strReplaceChar(fieldTitle, '~', ' ') then
begin
result := fields.FieldName;
exit;
end
end;
for i := 0 to fieldCount - 1 do
begin
if not ccisNonPhysicalField(fields) then continue;
if strReplaceChar(fields.displayLabel, '~', ' ') = strReplaceChar(fieldTitle, '~', ' ') then
begin
result := fields.FieldName;
exit;
end
end
end;
end;
function TDBLocateDlg.FindMatch(FromBeginning: boolean): boolean;
var
MatchType: TDBLocateMatchType;
curFieldName: string;
begin
result := false;
if ExactMatchBtn.Checked then
MatchType := mtExactmatch
else if PartialMatchStartBtn.Checked then
MatchType := mtPartialMatchStart
else
MatchType := mtPartialMatchAny;
curFieldName := getfieldNameFromTitle(FieldNameComboBox.text);
if curFieldName = '' then exit;
result := ccFindMatch(FromBeginning, DataSet, curFieldName,
searchValue.text, matchType, CaseSensitiveCheckbox.State <> cbUnchecked);
end;
procedure TDBLocateDlg.FindFirst(Sender: TObject);
begin
if not FindMatch(True) then
begin
MessageDlg('无匹配记录', mtInformation, [mbok], 0);
end
else
ModalResult := mrOK;
end;
procedure TDBLocateDlg.FindNextBtnClick(Sender: TObject);
begin
if not FindMatch(False) then
begin
MessageDlg('查找完毕,无更多匹配记录', mtInformation, [mbok], 0);
end
else
ModalResult := mrOK;
end;
procedure TDBLocateDlg.BitBtn1KeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (key = VK_ESCAPE) then
ModalResult := mrCancel;
end;
function TDBLocateDialog.Execute: boolean;
var
field: TField;
i: integer;
begin
result := True;
with TDBLocateDlg.create(Application) do
try
if (DataSource = nil) or (DataSource.dataSet = nil) or
(not DataSource.dataSet.active) then
begin
//MessageDlg('DataSource does not reference an active DataSet', mtError, [mbok], 0);
exit;
end;
DlgComponent := Self;
field := DataSource.DataSet.findField(SearchField);
FieldNameComboBox.items.clear;
if SortFields = fsSortByFieldNo then
FieldNameComboBox.sorted := False;
if DefaultButton = dbFindFirst then
begin
FirstButton.Default := True;
NextButton.Default := False;
end
else
begin
FirstButton.Default := False;
NextButton.Default := True;
end;
with DataSource.DataSet do
begin
for i := 0 to fieldCount - 1 do
begin
if (fields.dataType = ftBlob) or (fields.dataType = ftGraphic) or
(fields.dataType = ftVarBytes) or (fields.dataType = ftBytes) then
continue;
if (FFieldSelection = fsAllFields) or (fields.visible) then
FieldNameComboBox.items.add(strReplaceChar(fields.DisplayLabel, '~', ' '));
end
end;
if field <> nil then
begin
SearchValue.Text := fieldValue;
FieldNameCombobox.itemIndex :=
FieldNameComboBox.items.indexOf(strReplaceChar(Field.displayLabel, '~', ' '));
end
else
SearchValue.text := '';
DataSet := dataSource.DataSet;
caseSensitiveCheckBox.checked := caseSensitive;
case matchType of
mtExactMatch: ExactMatchBtn.checked := True;
mtPartialMatchStart: PartialMatchStartBtn.checked := True;
mtPartialMatchAny: PartialMatchAnyBtn.checked := True;
end;
Caption := self.Caption;
Result := ShowModal = IDOK;
{ Use user selections from dialog to update this component }
if ExactMatchBtn.Checked then
MatchType := mtExactmatch
else if PartialMatchStartBtn.Checked then
MatchType := mtPartialMatchStart
else
MatchType := mtPartialMatchAny;
caseSensitive := caseSensitiveCheckBox.checked;
fieldValue := SearchValue.Text;
SearchField := getfieldNameFromTitle(FieldNameComboBox.text);
finally
Free;
end
end;
constructor TDBLocateDialog.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
MatchType := mtPartialMatchStart;
caseSensitive := False;
SortFields := fsSortByFieldName;
Caption := '内容查找';
FDefaultButton := dbFindNext;
FFieldSelection := fsAllFields;
FDataLink := TDataLink.create;
FShowMessages := True;
end;
destructor TDBLocateDialog.Destroy;
begin
FDataLink.free;
inherited destroy;
end;
procedure TDBLocateDialog.SetDataSource(value: TDataSource);
begin
FDataLink.dataSource := value;
end;
function TDBLocateDialog.getDataSource: TDataSource;
begin
Result := FdataLink.dataSource;
end;
function TDBLocateDialog.FindPrior: boolean;
begin
result := False;
end;
function TDBLocateDialog.FindFirst: boolean;
begin
result := False;
if (dataSource = nil) or (datasource.dataset = nil) or (not datasource.dataset.active) then
begin
MessageDlg('DataSource does not refer to an active table!', mtWarning, [mbok], 0);
exit;
end;
if FieldValue = '' then
begin
DefaultButton := dbFindFirst;
result := execute;
end
else
begin
result := ccFindMatch(True, DataSource.DataSet, SearchField, FieldValue,
matchType, caseSensitive);
if (not result) and FShowMessages then
MessageDlg('查找完毕,无匹配记录', mtInformation, [mbok], 0);
end
end;
function TDBLocateDialog.FindNext: boolean;
begin
result := False;
if (dataSource = nil) or (datasource.dataset = nil) or (not datasource.dataset.active) then
begin
//MessageDlg('DataSource does not refer to an active table!', mtWarning, [mbok], 0);
exit;
end;
if FieldValue = '' then
begin
DefaultButton := dbFindNext;
result := execute;
end
else
begin
result := ccFindMatch(False, DataSource.DataSet, SearchField, FieldValue,
matchType, caseSensitive);
if (not result) and FShowMessages then
MessageDlg('查找完毕,无更多匹配记录', mtInformation, [mbok], 0);
end
end;
procedure TDBLocateDlg.FieldNameComboBoxChange(Sender: TObject);
begin
SearchValue.Text := '';
if not FieldNameComboBox.DroppedDown then SearchValue.setFocus;
if DlgComponent = nil then exit;
if Assigned(TDBLocateDialog(DlgComponent).FOnSelectField) then
TDBLocateDialog(DlgComponent).FOnSelectField(self, FieldNameComboBox.text);
end;
procedure TDBLocateDlg.FieldNameComboBoxEnter(Sender: TObject);
begin
NextButton.default := False;
end;
procedure TDBLocateDlg.FieldNameComboBoxExit(Sender: TObject);
begin
NextButton.default := True;
end;
procedure TDBLocateDlg.FieldNameComboBoxKeyDown(Sender: TObject;
var Key: Word; Shift: TShiftState);
begin
if (Key = VK_Return) and FieldNameComboBox.DroppedDown then
begin
FieldNameComboBox.DroppedDown := False;
SearchValue.setFocus;
end
end;
procedure TDBLocateDlg.FormShow(Sender: TObject);
var
Dlg: TDBLocateDialog;
begin
Dlg := DlgComponent as TDBLocateDialog;
Dlg.Form := self;
Dlg.DoInitDialog;
end;
procedure TDBLocateDialog.DoInitDialog;
begin
if Assigned(FOnInitDialog) then OnInitDialog(Form);
end;
function TDBLocateDialog.GetPrimaryDataSet: TDataSet;
begin
result := nil;
if DataSource <> nil then
result := DataSource.DataSet;
end;
procedure Register;
begin
RegisterComponents('WolfSoft', [TDBLocateDialog]);
end;
end.