Link to home
Start Free TrialLog in
Avatar of skatan187
skatan187

asked on

mouse cursor as file-bitmap

I want to replace my mouse cursor with a bitmap-file
(so..loadfromfile) . At this moment I use Timage wich
I move with onmousemove: (example. onmousemove over image3)
cimage.left:=(x + image3.left) - (cimage.width div 2); cimage.top:=(y + image3.top) - (cimage.height div 2);

But.. since I have to move over alot components , and some components don't even have the onmousemove event... I think it's better to replace the mouse-cursor..

But.. hOW?
-external BITmap file..
-larger then 32*32 p's
Avatar of Madshi
Madshi

If you want Windows to handle all this cursor stuff for you, you'll have to convert the bitmap to an icon (look at winAPI "CreateCursor"). Then - I guess - you can just put the handle of the created cursor into TControl.Cursor. Please look at the example that you find in the documentation of TControl.Cursor.

Regards, Madshi.
Avatar of skatan187

ASKER

Is it possible to convert a bitmap wich is larger then the standard size of a .cur file to a cur file (I have AXialis-AX cursor for this). And whill delphi display it?

and.. do you have some sample source to load an external .cur file? and I want to use the cursor only in one panel ...

SkAtAn
skatan187,

what about overiding the Hint component?

Regards, Zif.
And how do I do that?
I am not a professional delphi programmer eh =)

I tried to make a large .cur file and it's possible.. but will
delphi accept these large cur files.. and! the mousePOINT (where the mouse XY coordinates acually are) must be in te centre of this bitmap ! (maybe I am asing to much .. dunno =)
SkA



Try to use TImageList. There is a function to add a bitmap with a transparency mask. After that you added a bitmap you can use it as Icon, too. Look at the functions DragImage, DragMove ... With this functions you can move your Image over the screen. Samples you'll find in the Win32Api help and in the source code of TTreeView and TListView. I've not tested with big Images but with normal Icons it works quite good.
rg
It must be possible to create cursors bigger than 32x32, since if you install the cursor options and go to control panel/mouse, you can install very large cursors.
And I don't think, that Delphi will have problems with that, since Delphi does not implement the cursor drawing, but let Windows do the work.
Sorry, have no sources for loading an external cur file...  :-(

Regards, Madshi.
>>
Sorry, have no sources for loading an external cur file...  :-(

<<

if yha have this..
and it works with a 64*64 cur file..
-> correct answer =)
points:=points+30





Here's one solution, but it uses an external .CUR file not .BMP file:

1) Use DevStudio to create the large cursor
   a) File, New, Files tab, Cursor File
   b) Image menu, New Device Image, Custom
   c) enter size of the cursor you want
   d) select the standard 32x32 cursor and delete (Image menu, Delete Device Image
   e) specify hotspot

2) Use the LoadCursorFromFile API to do the job:

const
  crMyCursor = 5;

procedure TForm1.FormCreate(Sender: TObject);
begin
      Screen.Cursors[crMyCursor] := LoadCursorFromFile ('LargeCur.cur');
      Cursor := crMyCursor;
end;

I've got a working demo, if you need.

Hope this helps.

TC
ow.. and the cursor may only change when in panel1
I will test this first..

I will test this first..

Screen.Cursors[crMyCursor] := LoadCursorFromFile ('LargeCur.cur');

I found the same answer in uddf faq,..
but id didn't worked ,, i'll try again anyhow
dunno if THIS works? because the cursor my only change in panel1
panel1.Cursors[crMyCursor] := LoadCursorFromFile
The line
Screen.Cursors[crMyCursor] := LoadCursorFromFile (...);
is only used to make the cursor available to other components.

The line
Cursor := crMyCursor;
actually sets the cursor for the component.

If you want the cursor to appear like that over all your TControl components, do this in your formcreate:
for i := 0 to ComponentCount-1 do begin
    if Components[i] is TControl then
        TControl(Components[i]).Cursor := crMyCursor;
end;

or you can do
Screen.Cursor := crMyCursor;
to make it a global cursor for your app (note that no matter what you do, Windows will only set the cursor for your app, when you move it out of your app, Windows changes the cursor).

TC
Oops! SKA, I just remembered that Windows (or rather the display drv) won't let you display native cursors that are larger than what it supports as specified in the GetSystemMetrics API (SM_CXCURSOR, SM_CYCURSOR).

So unless your display driver can support it, even if you can create and load a 64x64 cursor, it will not show as 64x64.

TC

What's about my comment (using TImageList)? Why don't you try it? I'm quite shure it works.

regards rg.
nope .. it didn't worked

aacrg.. yha have some source?
Well, here is some stuff. I've tested it with a 300x300 bmp under WinNt4. I'm not absolutely shure if it works under Win95. (Because Winnt supports bigger icons.) On my computer it was a bit slow with this huge bitmap.

New project, new form, imagelist, set width and height of the imagelist, then add the following events:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  WindowHandle: THandle;
begin
  ImageList1.SetDragImage(0 {Index}, ImageList1.Width div 2, ImageList1.Height div 2);
//  WindowHandle:=GetDesktopWindow;   in this case you have to calc your mouse pos with ClientToScreen...
  WindowHandle:=Form1.Handle;
  if not ImageList1.DragLock(DeskHandle, X, Y) then
{    ShowMessage('DragLock failed')};
  ImageList1.ShowDragImage;
  if not ImageList1.BeginDrag(DeskHandle, X, Y) then
{    ShowMessage('BeginDrag failed')};
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  ImageList1.EndDrag;
  ImageList1.DragUnlock;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  ImageList1.DragMove(X,Y);
end;

end.

regards rg.
It was WAY more simple:

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,  Y: Integer);
begin
ImageList1.Draw(form1.Canvas,x,y,0);
end;

BUT THE QUESTION IS NOT FINISHED ! =(
the icon remains on the form each times it's drawn..
AH DAMnnnnn...
(if I do form1.refresh it .. flikkers (i dunno how they say it in english). and it's not really centered (maybe I can change that by de/increasing X and Y a bit (the imageheight dive 2 or somthing like that

HowEver.. the imagelist method is WAY faster then moving a Timage .. so thx for the idea.. now the next problem I and I guess the question is answered.. (FiNAllY.. ! =)


SkAtAn
Adjusted points to 120
another question..
How can get the size adn height of the loaded bitmap
afther some trying I still did't found the answer to
the problem .. that imagelist draws each time a mousemove
event is triggered.. so the images is displayed 100 times
form1.refresh is to slow
form1.Canvas.Refresh; didn't removed the drawn images

AH .. and, when moving over a panel.. the images are behind
the panel.. so you can't see it .. while it's very importand
that the images are above this panel (and refresh..)

I think after DragLock the ParentWindow is locked that'll you can't change it using paint smth. If you like to change it you have to unlock it first. About your problem with the refresh: What's the parent window of TImageList.BeginDrag? Perhaps you can use InvalidateRect to redraw only a specified rectangle. Get the size of the loaded bitmap: Where have you loaded it? In TImageList? TImageList is a list of images with the same size. You have to set it before loading anything. e.g. load your bitmap in a TImage after check the width and height then assign it to the image list.

regards and a happy new year
rg
again.. what my current problems are..
a)I load one external file and I wan't to get the size in pixels
  and use this size for the timagelist...

b)I wan't the draw event only in one panel (panel1) and the
  imagelist.draw must be on the panel, not behind, so that it
  looks like the mouse coursor changes when in the panel...
c)And I wan't to refresh everythime the imageslist.draw is
  called.. so that I don't get a curve of the images (if onmouse
  move the loaded pictures is drawn everytime a mousemove event
  is triggered (so a lot times, I only need once a time)

and if thats not possible.. another way to load a bitmap as mouse cursor IN PANEL1 ONLY ... (the stuff above should do it)

SeeYa all NEXt YEaR :-)
SkAtAn


Dear Skatan187

I can't really understand your problem. Perhaps it's because you just used the TImageList.Draw method? I modified the code of aacrg a bit and it worked wonderful with a form and a panel on it. Even if you moves outside of the form. On MouseDown I capture the cursor so I will get all mouse events. E.g. you could capture the mouse on panel1.mousemove and check if the mouse moves outside the panel (panel1.getclientrect...) and then execute the same code as in Form1.MouseUp in this example.

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  p: TPoint;
begin
  p:=ClientToScreen(Point(x,y));
  ImageList_DragMove(p.x, p.y);
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if not ImageList_EndDrag then
    MessageDlg('EndDrag error!',mtError, [mbOK],0);
  ImageList_DragLeave(0);
  SetCaptureControl(nil);
  Image1.Show;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  p: TPoint;
  HotSpotX, HotSpotY: Integer;
const
  ImageIndex=0;
begin
  GetCursorPos(p);
  SetCaptureControl(Self);
  Image1.Hide;
  Image1.Update;
  HotSpotX:=ImageList1.Height div 2;
  HotSpotY:=ImageList1.Width div 2;
  ImageList_BeginDrag(ImageList1.Handle, ImageIndex, HotSpotX, HotSpotY);
  p:=ClientToScreen(Point(x,y));
  ImageList_DragEnter(0, p.x, p.y);
end;

SeeYa next year!
I had a few errors:

ImageList_DragMove(p.x, p.y);  I changed these to
ImageList.DragMove(p.x, p.y); .. I added 2 image lists:
imagelist1 and imagelist (because the source has to different
imagelists ?!) and a timage (image1) .. I gave all of these components a little bitmap.. adjusted the size etc.. and when
tryng to drag I get the error: enddrag error... (thats all that happens)
I found it using aacrg's source  :
so.. aacrg resubmit this answer and you'll get the points
(lol) .. IF, you can also tell me how to find the with and height of a bitmap-file .. it has nothing to do with timagelist,
I just want to get the width and height of a bitmap file..
if somebody else put it in a comment.. since I cant give to persons points =) aacrg get the 170 .. :-) , but: AsAP !

SkATAn

procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  WindowHandle: THandle;
begin
ImageList1.EndDrag;
ImageList1.DragUnlock;

  ImageList1.SetDragImage(0, ImageList1.Width div 2, ImageList1.Height div 2);
  WindowHandle:=Form1.Handle;
  if not ImageList1.DragLock(windowHandle, panel1.left+X, panel1.top+Y) then
  ImageList1.ShowDragImage;
  if not ImageList1.BeginDrag(windowHandle, panel1.left+X, panel1.top+Y) then
ImageList1.DragMove(panel1.left+X,panel1.top+Y);
end;
Get the width and the height of a BMP:

var
  BMP: TBitmap;
begin
  try
    BMP:=TBitmap.Create;
    BMP.LoadFromFile('MyBitmap.bmp');   // or load from stream, ressource ...
    ShowMessage('Width:'+IntToStr(BMP.Width)+' height:'+IntToStr(BMP.height));
  finally
    BMP.Free;
  end;
end;

Is that what you want to do??

regards, rg
alright.. post an aswer and you'll yet yha points =)
ASKER CERTIFIED SOLUTION
Avatar of aacrg
aacrg

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial