Why doesn't my cursor change to an Hourglass in my FindDialog in Delphi?
Asked Answered
C

2

6

I am simply opening my FindDialog with:

FindDialog.Execute;

In my FindDialog.OnFind event, I want to change the cursor to an hourglass for searches through large files, which may take a few seconds. So in the OnFind event I do this:

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

What happens is while searching for the text, the cursor properly changes to the hourglass (or rotating circle in Vista) and then back to the pointer when the search is completed.

However, this only happens on the main form. It does not happen on the FindDialog itself. The default cursor remains on the FindDialog during the search. While the search is happening if I move the cursor over the FindDialog it changes to the default, and if I move it off and over the main form it becomes the hourglass.

This does not seem like what is supposed to happen. Am I doing something wrong or does something special need to be done to get the cursor to be the hourglass on all forms?

For reference, I'm using Delphi 2009.

Cordeliacordelie answered 18/4, 2010 at 1:55 Comment(0)
V
5

I guess the reason for this has got sth. to do with Find Dialog being not a form but a Dialog (a Common Dialog).

You can try setting the class cursor (does not have an effect on the controls of the dialog);

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;
Volumetric answered 18/4, 2010 at 4:0 Comment(9)
@Sertac: That "almost" works. It seems that the HourGlass appears over some parts of the Find Dialog, but not all of it. Very strange! Anything that looks its an object placed on the dialog (e.g. a label, a button, an edit box) does not get the Hourglass appearing, but the form behind it does.Cordeliacordelie
Well, I guess that changes the cursor only for the dialog's "Form" and not for it's controls and that you need to set all the child windows' cursor too. I think EnumChildWindows will do the job.Lithia
Edited to propose an alternative to enumarating controls on the dialog. I don't know if it's less code or if it's more proper though...Volumetric
@Sertac: This is better. The hourglass now comes on the FindDialog and its controls. However, when the find is completed, the cursor over the controls of the FindDialog are set back to default, but the cursor over the parts of the FindDialog without a control over it still have the hourglass. Also, I now notice (didn't before) that a few controls on my main form do not change to hourglass. Maybe windows standards want the hourglass handled this way and I shouldn't be fooling around with it(???).Cordeliacordelie
@Ikessler - (1) Confirmed, added a call to SetCursor after resetting the window procedure... (2) - I dunno, I have no knowledge of an HourGlass cursor usage design guide <g>. Is it possible to duplicate with standard VCL controls?Volumetric
@Sertac: Unfortunately neither the SetCursor line nor the SendMessage line you commented out set the cursor over the FindDialog back to default. I think maybe Windows does something special with the cursor over controls, because you want to be able to press a control with a pointer even if something is running in the background.Cordeliacordelie
@Cordeliacordelie - Weird.. seems to work here. Perhaps a "SetClassLong" leftover? ... I don't think the OS does anything with the cursor behind your back. It makes sense not to change it to HourGlass if indeed you can use the cursor in anyway. But, my view is, that should be a design consideration.Volumetric
@Sertac: Thanks for letting me know it worked for you. I went back and found some code not done correctly that prevented the cursor from being set back. Now I've fixed that and it all works as you said. Thanks so much for your work to help me out here. Much appreciated. You get the accepted answer.Cordeliacordelie
Here's a follow-up many years later. Adding this code did work to set the cursor correctly, but also affected the default action of the dialog. Hitting the Enter key a second time would not do the search again, but would do nothing. So the former problem was the lesser of the two evils (the latter was infuriating), and I've now taken this code out.Cordeliacordelie
I
0

Try adding Application.ProcessMessages; after you set the cursor.

If this works, be sure to call your Mother, help an old lady cross the street, or maybe plant a tree. Otherwise, the devil will own another little piece of your soul.

Indoeuropean answered 18/4, 2010 at 3:6 Comment(1)
@Chris. I do have Application.ProcessMessages in my search for text code but I didn't show it in my example above. If I didn't have it, then the cursor wouldn't have changed to the hourglass for the main form either.Cordeliacordelie

© 2022 - 2024 — McMap. All rights reserved.