【问题标题】:Why doesn't my cursor change to an Hourglass in my FindDialog in Delphi?为什么我的光标在 Delphi 的 FindDialog 中没有变为沙漏?
【发布时间】:2022-01-29 01:13:01
【问题描述】:

我只是打开我的 FindDialog:

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。

【问题讨论】:

    标签: delphi mouse-cursor hourglass finddialog


    【解决方案1】:

    我想这其中的原因是什么。与查找对话框不是表单而是对话框(通用对话框)有关。

    您可以尝试设置类光标(对对话框的控件没有影响);

    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;
    



    编辑

    另一种方法是在搜索期间对 FindDialog 进行子类化,并使用“SetCursor”响应 WM_SETCURSOR 消息。如果我们阻止对消息的进一步处理,对话框上的控件将不会设置自己的光标。

    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;
    

    【讨论】:

    • @Sertac:“几乎”有效。似乎 HourGlass 出现在 Find Dialog 的某些部分上,但不是全部。很奇怪!任何看起来像是放置在对话框上的对象(例如标签、按钮、编辑框)都不会显示沙漏,但它后面的表单会显示。
    • 好吧,我猜这只会改变对话框的“表单”的光标,而不是它的控件,而且您还需要设置所有子窗口的光标。我认为 EnumChildWindows 会完成这项工作。
    • 已编辑以提出一种替代方法来枚举对话框上的控件。我不知道是代码少了还是更合适了……
    • @Sertac:这样更好。沙漏现在出现在 FindDialog 及其控件上。但是,当查找完成时,FindDialog 控件上的光标将恢复为默认值,但 FindDialog 上没有控件的部分上的光标仍然有沙漏。另外,我现在注意到(以前没有)我的主窗体上的一些控件不会变成沙漏。也许 Windows 标准希望以这种方式处理沙漏,我不应该胡闹(???)。
    • @Ikessler - (1) 确认,在重置窗口过程后添加了对 SetCursor 的调用... (2) - 我不知道,我不知道 HourGlass 光标使用设计指南 .是否可以使用标准 VCL 控件进行复制?
    【解决方案2】:

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

    如果可行,请务必打电话给您的母亲,帮助一位老妇人过马路,或者种植一棵树。否则,恶魔将拥有你灵魂的另一小块。

    【讨论】:

    • @Chris。我在搜索文本代码时确实有 Application.ProcessMessages,但我没有在上面的示例中显示它。如果我没有它,那么光标也不会变为主窗体的沙漏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 2012-11-09
    • 1970-01-01
    相关资源
    最近更新 更多