为什么在Delphi中的FindDialog中我的光标没有变成沙漏?

6

我只需使用以下代码打开我的查找对话框:

FindDialog.Execute;

在我的FindDialog.OnFind事件中,我希望在搜索大文件时将光标更改为沙漏,因为这可能需要几秒钟的时间。因此,在OnFind事件中,我这样做:

Screen.Cursor := crHourglass;
(code that searches for the text and displays it) ...
Screen.Cursor := crDefault;

在搜索文本时,光标会正确地变为沙漏(或在Vista中为旋转圆圈),当搜索完成后又会变回指针。然而,这只会在主窗体上发生。在FindDialog本身上不会发生。默认光标在搜索期间保持在FindDialog上。在搜索进行时,如果我将光标移动到FindDialog上,则其会更改为默认光标,如果我将其移动到主窗体上,它将变成沙漏。这似乎不是预期发生的事情。我做错了什么,还是需要特别处理才能使所有表单上的光标都成为沙漏?供参考,我正在使用Delphi 2009。
2个回答

4
我猜这个原因与查找对话框不是一个表单而是一个对话框(通用对话框)有关。
您可以尝试设置类光标(对话框控件没有影响);
procedure TForm1.FindDialog1Find(Sender: TObject);
begin
  SetClassLong(TFindDialog(Sender).Handle, GCL_HCURSOR, Screen.Cursors[crHourGlass]);
  try
    Screen.Cursor := crHourglass;
    try
//    (code that searches for the text and displays it) ...
    finally
      Screen.Cursor := crDefault;
    end;
  finally
    SetClassLong(TFindDialog(Sender).Handle, GCL_HCURSOR, Screen.Cursors[crDefault]);
  end;
end;



EDIT

An alternative could be to subclass the FindDialog during the search time and respond to WM_SETCURSOR messages with "SetCursor". If we prevent further processing of the message the controls on the dialog won't set their own cursors.

type
  TForm1 = class(TForm)
    FindDialog1: TFindDialog;
    ...
  private
    FSaveWndProc, FWndProc: Pointer;
    procedure FindDlgProc(var Message: TMessage);
    ...
  end;

....
procedure TForm1.FormCreate(Sender: TObject);
begin
  FWndProc := classes.MakeObjectInstance(FindDlgProc);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  classes.FreeObjectInstance(FWndProc);
end;

procedure TForm1.FindDialog1Find(Sender: TObject);
begin
  FSaveWndProc := Pointer(SetWindowLong(FindDialog1.Handle, GWL_WNDPROC,
        Longint(FWndProc)));
  try
    Screen.Cursor := crHourGlass;
    try
//    (code that searches for the text and displays it) ...
    finally
      Screen.Cursor := crDefault;
    end;
  finally
    if Assigned(FWndProc) then
      SetWindowLong(FindDialog1.Handle, GWL_WNDPROC, Longint(FSaveWndProc));
//    SendMessage(FindDialog1.Handle, WM_SETCURSOR, FindDialog1.Handle,
//        MakeLong(HTNOWHERE, WM_MOUSEMOVE));
    SetCursor(Screen.Cursors[crDefault]);
  end;
end;

procedure TForm1.FindDlgProc(var Message: TMessage);
begin
  if Message.Msg = WM_SETCURSOR then begin
    SetCursor(Screen.Cursors[crHourGlass]);
    Message.Result := 1;
    Exit;
  end;
  Message.Result := CallWindowProc(FSaveWndProc, FindDialog1.Handle,
      Message.Msg, Message.WParam, Message.LParam);
end;


好吧,我猜这只改变了对话框的“表单”的光标,而不是它的控件,你需要为所有子窗口设置光标。我认为EnumChildWindows会完成任务。 - Ken Bourassa
编辑以提出在对话框上枚举控件的替代方案。我不知道它是否代码更少或者是否更合适... - Sertac Akyuz
@Sertac:这样更好了。沙漏现在出现在FindDialog和它的控件上。但是,当查找完成后,FindDialog控件上的光标会被设置回默认值,但是没有控件的FindDialog部分仍然有沙漏。此外,我现在注意到(之前没有注意到)我的主窗体上的一些控件不会变成沙漏。也许Windows标准希望沙漏以这种方式处理,我不应该胡乱尝试(???)。 - lkessler
@Ikessler - (1) 已确认,在重置窗口过程后添加了一个SetCursor调用... (2) - 我不知道,我没有关于使用HourGlass光标的设计指南的知识<g>。是否可能使用标准VCL控件进行复制? - Sertac Akyuz
多年后的跟进。添加这段代码确实可以正确设置光标,但也会影响对话框的默认操作。第二次按Enter键将不会再次搜索,而是什么都不做。因此,前一个问题是两个问题中较小的那个(后者非常恼人),我现在已经将此代码删除。 - lkessler
显示剩余4条评论

0

在设置光标后尝试添加Application.ProcessMessages;。

如果这有效,请务必给您的母亲打电话,帮助一位老太太过马路,或者种一棵树。否则,魔鬼将拥有你灵魂的另一小部分。


@Chris。在我的搜索文本代码中,我确实有Application.ProcessMessages,但我没有在上面的示例中显示它。如果我没有它,那么主窗体的光标也不会变成沙漏形状。 - lkessler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接