Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Caption Bar and Animated(custom) Cursors 1

Status
Not open for further replies.

BoMi

Programmer
Jul 20, 2006
39
RS
Hi to all :)
One thing bothers me for some time now...
I'm in process of making an application which contains, for the sake of visual impression, animated cursor. The thing is: when the mouse pointer is on a caption bar of a form, animated cursor changes itself into standard Windows' mouse pointer. I didn't try with custom cursors (so, not animated custom cursors), but I guess it's the same.
Also, my application doesn't really contains a caption bar, and borders, too. I removed it. But the problem is still the same. I used standard Windows API procedure for moving the form without a caption bar:

CODE
Code:
procedure WMNCHitTest(var Msg:TMessage); message WM_NCHITTEST;
...
procedure TForm1.WMNCHitTest(var Msg:TMessage);
  begin
  msg.result := HTCAPTION;
  end;
but you see the problem...Windows now treats the whole non client area of the form as the caption bar...
So, I need this:
1. answer to - how to make my cursor doesn't change when on caption bar
and\or
2. alternative way for moving the form without the caption bar (different then the procedure above), which will make my cursor stay the same all the time...

Thanks to anyone who even wants to spare her\his time trying to help me :)
 
Try eating the WM_SETCURSOR message:

Code:
procedure WMSetCursor(var M: TMessage); message WM_SETCURSOR;

procedure TForm1.WMSetCursor(var M: TMessage);
  begin end;

But I'm not sure eating it will not produce some "collateral damages", so to speak.

buho (A).
 
Tnx buho for trying to help me.
It seems that this does "colateral damage" - now, my cursor is Windows default (arrow) in the whole form, not only caption bar...

Any more ideas...?
I appreciate your effort...
Anyone else...?
 
Code:
procedure TForm1.WMNCHitTest(var M: TWMNCHitTest);
  begin
    M.Result := htCaption;
  end;

procedure TForm1.WMSetCursor(var M: TMessage);
  begin
    Screen.Cursor := crHelp;
  end;

Cursor will be crHelp in the whole form (client and non client area).

Still not sure about collateral damages. Check it carefully.

buho (A).
 
Oh, sorry, I checked help file on WM_SETCURSOR, but I overlooked this: "The DefWindowProc function also uses this message to set the cursor to an arrow if it is not in the client area, or to the registered class cursor if it is in the client area."
So, I need to change my cursor, as you pointed out.
Thank you very much for help, but (there's always 'but' :-( ) when I change my cursor the way you showed me (even if I try with example you showed above), when I compile the app, my .ani cursor stays animated only as long as I don't minimize or resize my form, or even move my cursor out of a form (ok, sometimes I need to do one of the things mentioned at least two times to my ani cursor fall apart). So, after that, cursor becomes standard Windows arrow again...and never changes back...
I hope you will be so kind to try to help me a little bit more...
Here's a piece of code that do this, tell me, please, if there is something wrong

Code:
type
  TForm1 = class(TForm)
  private
    { Private declarations }
    procedure WMSetCursor(var M: TMessage); message WM_SETCURSOR;
  public
    { Public declarations }

  end;
  const
  crRotStar=10;
var
  Form1: TForm1;

implementation

{$R *.dfm}
{$R AniCur.RES}
 procedure TForm1.WMSetCursor(var M: TMessage);
 var
  AniStream: TResourceStream;
  begin
  AniStream:= TResourceStream.Create(HINSTANCE, 'MyAC', 'ANICURSOR');
  try
    AniStream.SaveToFile('RotStar.ani');
    Screen.Cursors[crRotStar] := LoadCursorFromFile('RotStar.ani');
    screen.Cursor := crRotStar;
  finally
    DeleteFile('RotStar.ani');
    AniStream.Free;
  end;
  end;
Is this, what I just explain, maybe a "collateral damage"?
Do you, maybe, know the way to solve this problem?
By the way I use Delphi 6, and, maybe, this is problem with my Delphi?
Thank you again for everything you've done for me so far.
 
I have no experience on animated cursors, so I can't say. Have you googled the 'net?

What I can see is that your code is highly inneficient: load the cursor in the Form on OnCreate event and limit your message handler to "Screen.Cursor := crRotStar". BTW, normal cursors can be loaded form the resource directly, no need of saving them in a file... animated cursors are different in this sense?

buho (A).
 
Try using:

Code:
procedure TForm1.WMSetCursor(var M: TMessage);
  begin
    SetCursor(Screen.Cursors[crRotStar]);
  end;

It worked for me, but I've not tested it a lot.

And you are right: no way to load the ani cursor directly from the resource: they are some bugs blocking any possible path (tried for two hours and gave up).

This is my testbed, my be it help:

Code:
unit ACFMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TFACMain = class(TForm)
    btnClose: TButton;
    btnMinimize: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure btnMinimizeClick(Sender: TObject);
  private
    { Private declarations }
    procedure WMNCHitTest(var M : TMessage); message WM_NCHITTEST;
    procedure WMSetCursor(var M : TMessage); message WM_SETCURSOR;
  public
    { Public declarations }
  end;

var
  FACMain: TFACMain;

implementation

{$R *.dfm}

(* 
-----------------
ANI RESOURCE FILE
-----------------
ANI_1 ANITYPE CURST.ANI
ANI_2 ANITYPE CURSS.ANI
ANI_3 ANITYPE CURSTAR.ANI
*)

const
  crANI_1 = 20;

{---------------------------}
procedure TFACMain.FormCreate(Sender: TObject);
  {-----------------}
  procedure LoadByTemp;
    const
      TmpName = '$$$.$$$';
    var
      AniStream: TResourceStream;
    begin
      AniStream := TResourceStream.Create(HINSTANCE, 'ANI_1', 'ANITYPE');
      AniStream.SaveToFile(TmpName);
      Screen.Cursors[crANI_1] := LoadCursorFromFile(TmpName);
      screen.Cursor := crANI_1;
      DeleteFile(TMPName);
      AniStream.Free;
    end;
  {-----------------}
  procedure KillCaption;
    begin
      SetWindowLong(Handle, GWL_STYLE,
                    GetWindowLong(Handle, GWL_STYLE) and not WS_CAPTION);
      Height := ClientHeight;
    end;
  {-----------------}
  begin
    LoadByTemp;
    KillCaption;
  end;

{---------------------------}
procedure TFACMain.btnCloseClick(Sender: TObject);
  begin
    Close;
  end;

{---------------------------}
procedure TFACMain.btnMinimizeClick(Sender: TObject);
  begin
    Application.Minimize;
  end;

{---------------------------}
procedure TFACMain.WMNCHitTest(var M : TMessage);
  begin
    inherited;
    M.Result := htCaption;
  end;

{---------------------------}
procedure TFACMain.WMSetCursor(var M : TMessage);
  begin
    // Screen.Cursor := crANI_1;   OLD LINE
    SetCursor(Screen.Cursors[crANI_1]);
  end;

end.

buho (A).
 
Tnx buho a lot. I haven't tested it much but it seems it works nicely.
Now, just a few answers on your previous questions...

I googled the net and nothing there about this particular stuff. I always check the net first and then post the question here.
Well, I'm a beginner OOP programmer, so I can make inefficient pieces of code, and that's why I like your comment on this, I need to improve myself. In my application ani cursor is loaded in Form OnCreate event and that above is an excerpt from my testing app (not good, I know). It's just one of the few little app I wrote trying to implement your first solution. I tried all possible combinations which should work.
And, finally, I also tried, but it seems this is the only way to load an ani cursor. I think, but not sure, that's the case with all types of let say animations, like .swf, .avi etc.

Thank you buho again for your time and effort :) you helped me a lot...
 
Yup. Loading from a file is, apparently, the only way to load an ANI cursor in Delphi.

1) I've tried defining the resource as ANICURSOR and using LoadImage (Windows official way). LoadImage failed.

2) I've tried defining the resource as RCDATA and using FindResource and LoadResource. It loads, but TScreen can't use it.

3) I've tried defining the resource as CURSOR. The Borland resource compilers do not compile. The Windows resource compiler compile and LoadImage load it, but again TScreen can't use it.

"2)" and "3)" needs some more research; I'm not sure if TScreen fails trying to use the cursor or Windows itself fails. If it is TScreen, may be some workaround is possible, if it is Windows failing all is lost.

The only thing I've not tried is defining the resource as CURSOR and renaming the ANI files to CUR. Having files with the wrong extension laying around in the project is too high a price to solve this particular issue.

Note: I'm using D6 (with all patches) in W2K Advanced Server.

buho (A).
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top