|            
4.4.2查找对话框部件  
    查找对话框部件为应用程序提供查找对话框, 用户可使用查找对话框在文本文件中查找字符串。 
    可用Execult方法显示查找对话框,如图4.8。应用程序要查找的字符放到FindText属性中。Options 属性可决定查找对话框中有哪些选项。例如, 用户可选择是否显示匹配检查框。Options的常用选项如表4.2所示。 
    如果用户在对话框中输入字符并选择FindNext按钮,对话框将发生OnFind事件。  
    表4.2 查找对话框的Options属性的取值及含义 
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 
    取值           含义 
    ─────────────────────────────────────── 
    frDown 如果是真值,对话框中出现Down按钮,查找方向向下。如果是假 
    值,Up按钮将被选中,查找方向向上,frDown 值可在设计或运行 
    时设置。 
    frDisableUpDown 如果是真值,Up和Down按钮将变灰,用户不能进行选取;如果是 
    假值,用户可以选择其中之一。 
    frFindNext 如果是真值,应用程序查找在FindNext属性中的字符串。 
    frMatchCase 如果是真值,匹配检查框被选中。设计、运行时均可设置。 
    frWholeWord 如果是真值,整字匹配检查框被选中,设计、运行时均可设置。 
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  
    在OnFind事件中可使用Options属性来决定以何种方式查找。Find方法响应查找对话框的OnFind事件。  
     procedure TEditform.Find(Sender: TObject); 
    begin 
    with Sender as TFindDialog do 
    if not SearchMemo(Memo1, FindText, Options) then 
    ShowMessage('Cannot find "' + FindText + '".'); 
    end; 
     其中SearchMemo函数是Search单元中定义的,SearchMemo可在TEdit,TMemo,以及其它TCustomEdit派生类中查找指定的字符串。查找从控件的脱字号(^)开始, 查找方式由Options决定。如果向后查找从控件的StlStart处开始,如果向前查找则从控件的SelEnd处查找。 
    如果在控件中找到相匹配的字符串,则字符串被选中,函数返回真值。如无匹配的字符串,函数返回假值。 
    特别注意的是TEdit,TMemo中有一个HideSeletion属性,它决定当焦点从该控制转移至其它控制时,被选中的字符是否保持被选中的状态。如果是真值,则只有获得焦点才能保持被选中状态。查找时,焦点在查找对话框上,因此要想了解查找情况,必须将HideSeletion设成假值。控制的缺省值为真值。 
    SearchMemo代码如下:  
    unit Search; 
    interface 
    uses WinProcs, SysUtils, StdCtrls, Dialogs; 
    const 
    WordDelimiters: set of Char = [#0..#255] - ['a'..'z','A'..'Z','1'..'9','0'];  
    function SearchMemo(Memo: TCustomEdit; 
    const SearchString: String; 
    Options: TFindOptions): Boolean;  
    function SearchBuf(Buf: PChar; BufLen: Integer; 
    SelStart, SelLength: Integer; 
    SearchString: String; 
    Options: TFindOptions): PChar;  
    implementation  
    function SearchMemo(Memo: TCustomEdit; 
    const SearchString: String; 
    Options: TFindOptions): Boolean; 
    var 
    Buffer, P: PChar; 
    Size: Word; 
    begin 
    Result := False; 
    if (Length(SearchString) = 0) then Exit; 
    Size := Memo.GetTextLen; 
    if (Size = 0) then Exit; 
    Buffer := StrAlloc(Size + 1); 
    try 
    Memo.GetTextBuf(Buffer, Size + 1); 
    P := SearchBuf(Buffer, Size, Memo.SelStart, 
    Memo.SelLength,SearchString, Options); 
    if P <> nil then 
    begin 
    Memo.SelStart := P - Buffer; 
    Memo.SelLength := Length(SearchString); 
    Result := True; 
    end; 
    finally 
    StrDispose(Buffer); 
    end; 
    end;  
    function SearchBuf(Buf: PChar; BufLen: Integer; 
    SelStart, SelLength: Integer; 
    SearchString: String; 
    Options: TFindOptions): PChar; 
    var 
    SearchCount, I: Integer; 
    C: Char; 
    Direction: Shortint; 
    CharMap: array [Char] of Char;  
    function FindNextWordStart(var BufPtr: PChar): Boolean; 
    begin { (True XOR N) is equivalent to 
    (not N) } 
    Result := False; { (False XOR N) is equivalent 
    to (N) } 
    { When Direction is forward (1), skip non 
    delimiters, then skip delimiters. } 
    { When Direction is backward (-1), skip delims, then 
    skip non delims } 
    while (SearchCount > 0) and 
    ((Direction = 1) xor (BufPtr^ in 
    WordDelimiters)) do 
    begin 
    Inc(BufPtr, Direction); 
    Dec(SearchCount); 
    end; 
    while (SearchCount > 0) and 
    ((Direction = -1) xor (BufPtr^ in 
    WordDelimiters)) do 
    begin 
    Inc(BufPtr, Direction); 
    Dec(SearchCount); 
    end; 
    Result := SearchCount > 0; 
    if Direction = -1 then 
    begin { back up one char, to leave ptr on first non 
    delim } 
    Dec(BufPtr, Direction); 
    Inc(SearchCount); 
    end; 
    end;  
    begin 
    Result := nil; 
    if BufLen <= 0="" then="" exit;="">=>
    if frDown in Options then 
    begin 
    Direction := 1; 
    Inc(SelStart, SelLength); { start search past end of 
    selection } 
    SearchCount := BufLen - SelStart - Length(SearchString); 
    if SearchCount < 0="" then="" exit;="">
    if Longint(SelStart) + SearchCount > BufLen then 
    Exit; 
    end 
    else 
    begin 
    Direction := -1; 
    Dec(SelStart, Length(SearchString)); 
    SearchCount := SelStart; 
    end; 
    if (SelStart < 0)="" or="" (selstart=""> BufLen) then Exit; 
    Result := @Buf[SelStart];  
    { Using a Char map array is faster than calling 
    AnsiUpper on every character } 
    for C := Low(CharMap) to High(CharMap) do 
    CharMap[C] := C;  
    if not (frMatchCase in Options) then 
    begin 
    AnsiUpperBuff(PChar(@CharMap), sizeof(CharMap)); 
    AnsiUpperBuff(@SearchString[1], 
    Length(SearchString)); 
    end;  
    while SearchCount > 0 do 
    begin 
    if frWholeWord in Options then 
    if not FindNextWordStart(Result) then Break; 
    I := 0; 
    while (CharMap[Result[I]] = SearchString[I+1]) do 
    begin 
    Inc(I); 
    if I >= Length(SearchString) then 
    begin 
    if (not (frWholeWord in Options)) or 
    (SearchCount = 0) or 
    (Result[I] in WordDelimiters) then 
    Exit; 
    Break; 
    end; 
    end; 
    Inc(Result, Direction); 
    Dec(SearchCount); 
    end; 
    Result := nil; 
    end;  
    end.       [1] [2]  下一页  
 |