delphi 在Trichedit中搜索和替换

g9icjywg  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(393)

我们正在使用XE7。我们正在尝试将搜索和替换功能构建到TRichEdit中。
我们希望它能像在 Delphi 编译器中一样工作。我们显示自己的搜索和替换对话框,我们没有使用Delphi替换对话框。
我们显示对话框,当用户单击Replace按钮时,对话框关闭,对于找到的每个示例,我们希望弹出一个消息对话框,询问用户是否要替换该示例。
当我们这样做时,用户看不到所选择的内容,并且如果他们在消息对话框中单击“是”,则不会替换任何内容。
我们的代码如下:

procedure Tviewform.select_text(fndpos:integer);
begin
   setfocus;
   asciieditor.selstart:=fndpos;
   asciieditor.sellength:=length(vwvars[curviewwin]^.finddata);
end;

procedure Tviewform.search_and_replace;
var position,endpos,fndans,cont:integer; foptions:tsearchtypes; msgques,stopall:word;
begin
  with asciieditor do
  begin
    endpos:=length(asciieditor.text)-vwvars[curviewwin]^.sstartpos;
    foptions:=[];
    stopall:=0;
    cont:=0;
    if findinfo.onbut.checked then foptions:=foptions+[stMatchCase];
    lines.beginupdate;
    fndans:=findtext(vwvars[curviewwin]^.finddata,vwvars[curviewwin]^.sstartpos,endpos,foptions);
    while (fndans<>-1) and (stopall=0) do
    begin
      select_text(fndans);
      msgques:=mainform.silang1.messagedlg('Replace with '+vwvars[curviewwin]^.replace+'?.',mtinformation,[mbyes,mbno,mbcancel],0);
      if msgques=mryes then
      begin
        asciieditor.clearselection;
        seltext:=vwvars[curviewwin]^.replace;
      end else
      begin
        if msgques=mrcancel then
        begin
          cont:=0;
          stopall:=1;
        end else cont:=1;
      end;
      asciieditor.Repaint;
      if cont=1 then
      begin
        inc(vwvars[curviewwin]^.sstartpos,length(vwvars[curviewwin]^.finddata));
        endpos:=length(asciieditor.text)-vwvars[curviewwin]^.sstartpos;
        fndans:=findtext(vwvars[curviewwin]^.finddata,vwvars[curviewwin]^.sstartpos,endpos,foptions);
      end;
    end;
    lines.endupdate;
  end;
end;
wlzqhblo

wlzqhblo1#

我发现您的程式码有许多问题:

  • 当调用select_text()MessageDlg()时,您将输入焦点从TRichEdit移开,因此请确保将TRichEdit.HideSelection设置为False(默认情况下为True),以便实际查看所选内容。
  • 您正在TRichEdit上调用BeginUpdate(),这将禁用它的屏幕重绘,包括Repaint()
  • 在设置TRichEdit.SelText之前,您不需要调用TRichEdit.ClearSelection()
  • 在每次替换后更新vwvars[curviewwin]^.sstartpos时,您需要将其重置为fndAns(当前选择的位置)加上vwvars[curviewwin]^.replace(新文本)的长度,而不是vwvars[curviewwin]^.finddata(旧文本)的长度。您没有将其移动到新文本之外,因此您在反复搜索旧文本。
  • 如果用户在MessageDlg()中选择“否”,则不会更新vwvars[curviewwin]^.sstartpos以跳过用户不希望替换的文本。
  • 当设置endpos时,length(asciieditor.text)可以改为asciieditor.gettextlen(),以提高效率。但更重要的是,您根本不应该从endpos中减去vwvars[curviewwin]^.sstartpos。这样做的话,每次替换都将从搜索中 * 跳过 * 越来越多位于TRichEdit末尾的文本。事实上,您应该只使用asciieditor的当前文本长度作为每次搜索的结束位置,因此实际上根本不需要endpos
  • 根据TRichEdit的大小及其内容,如果它启用了滚动条,则在每次找到匹配的文本时,在使用MessageDlg()提示用户之前,应向TRichEdit发送EM_SCROLLCARET消息,以防匹配的文本不在屏幕上。

话虽如此,尝试更像这样的东西:

procedure Tviewform.search_and_replace;
var
  fndAns: Integer;
  fOptions: TSearchTypes;
  msgQues: Word;

  procedure select_text;
  begin
    {AsciiEditor.}SetFocus;
    AsciiEditor.SelStart := fndAns;
    AsciiEditor.SelLength := Length(vwvars[curviewwin]^.finddata);
    AsciiEditor.Perform(EM_SCROLLCARET, 0, 0);
    AsciiEditor.Update;
  end;

begin
  fOptions := [];
  if FindInfo.OnBut.Checked then Include(fOptions, stMatchCase);
  repeat
    fndAns := AsciiEditor.FindText(vwvars[curviewwin]^.finddata, vwvars[curviewwin]^.sstartpos, AsciiEditor.GetTextLen, fOptions);
    if fndAns = -1 then Break;
    select_text;
    msgQues := MainForm.SiLang1.MessageDlg('Replace with ' + vwvars[curviewwin]^.replace + '?', mtinformation, [mbYes,mbNo,mbCancel], 0);
    if msgQues = mrYes then
    begin
      AsciiEditor.SelText := vwvars[curviewwin]^.replace;
      AsciiEditor.Update;
      Inc(fndAns, Length(vwvars[curviewwin]^.replace));
    end
    else if msgQues = mrNo then
    begin
      Inc(fndAns, Length(vwvars[curviewwin]^.finddata));
    end else
      Break;
    vwvars[curviewwin]^.sstartpos := fndAns;
  until False;
end;

相关问题