Moving forms. lazarus / 10-Designer ---------------------------------------------------------------------- The_Marlboro_Man · 2007-11-22 16:17 Hi!. Finally I get to figure out why I was having problems with Lazarus and now I am ready to step into questions regarding programming itself. My first question is about moving a form. I have the intention of creating a small application consisting on a single form with the BorderStyle set to "bsNone". Without borders I have no way of moving the form around the screen at runtime... In Delphi we saw someting like MouseDown Event: ReleaseCapture; TControl(Sender).Perform(WM_SysCommand, &F012, 0) but I don't expect that to work in Lazarus. There's no "releasecapture" (the closest I got was "release") and WM_SysCommand is not recognised at all (supposedly a Windows specific???. I am running Ubuntu). Is there any way that I can move a form or component around the screen with the "mousedown" event?. Thanks!. ---------------------------------------------------------------------- Legolas · 2007-11-22 16:37 Look at http://www.lazarus.freepascal.org/lcl_doc/lMessages.html There is something like LM_SysCommand, though I don't know if your delphi code will work under linux ---------------------------------------------------------------------- The_Marlboro_Man · 2007-11-22 17:04 No luck this time... Tried procedure TFormulario1.BBoton_IrADiaActualMouseDown(Sender: TOBject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin  Release;  TControl(sender).Perform(LM_SYSCOMMAND, $F012, 0); end;   And got this as a result: unit1.pas(243,27) Error: Identifier not found "LM_SYSCOMMAND" I also tried with TLMSysCommand" but got the same error. I wonder if there's another way to do this dragging thing. This particular application (almost a gadget) would waste a bit more desktop space than it really needs to if I leave the default borders. Edit: I have been doing some test and I don't really think there's a point on doing the form without borders, at least on my case... I just checked if my "minimize" function would work on a form with borders set to "bsNone" and to my surprise, it just won't work!... I guess I'll have to leave the borders as they are, why having a gadget if you can' t minimize it out of your way?. ---------------------------------------------------------------------- Legolas · 2007-11-22 19:25 Maybe you haven't replaced "Messages" with "LMessages" in the uses section of your unit ---------------------------------------------------------------------- duncanparsons · 2007-11-23 09:10 In Delphi there are ways of dragging a forma and components just using MouseDown, MouseUp and MouseMove. I'll see if I can dig the code out - since it doesn't rely on any win specific code, it should be portable... I'll be back DSP ---------------------------------------------------------------------- The_Marlboro_Man · 2007-11-23 16:07 Legolas: I never knew I had to put the "LMessages" or "Messages" thing :S. At least it compiles now but, as expected, it doesn't work outside Windows (at least for me)... I don't know, maybe the specific message for my system is quite different, if any. Thanks a lot for the tip . DuncanParsons: It would be great if you could find it... Right now I am thinking about alternative methods but having yours should be helpful ... I'll try something about it too now that you suggest using different events . Edit: Here we go! Code: [Select]procedure TForm1.Button1MouseDown(Sender: TOBject; Button: TMouseButton;   Shift: TShiftState; X, Y: Integer); begin       Button1.Caption:='1'; end; procedure TForm1.Button1MouseMove(Sender: TObject; Shift: TShiftState; X,   Y: Integer); begin Form1.Caption:= inttostr(X)+' '+inttostr(Y);     if Button1.Caption='1' then     begin     Form1.Left:=Form1.Left+X;    Form1.Top:=Form1.Top+Y;     end; end; procedure TForm1.Button1MouseUp(Sender: TOBject; Button: TMouseButton;   Shift: TShiftState; X, Y: Integer); begin       Button1.Caption:='2'; end;   So far it is a bit sloppy but I think I can make it much better with a few calculations . Also using the caption while I could use something like the Tag is a bit of a mistake but I can do with it . Edit: It seems there's a problem with this code... Somehow, if I move the form and open a popup menu the form is restored to its original position (as stored in the Ini file). This is no "real" problem for my application as it should always be on a corner of the screen but could be bad for other programs... The exact problem happens when no option of the pop-up menu is selected and the pop-up menu is exited. Can anyone confirm this behaviour?. ---------------------------------------------------------------------- duncanparsons · 2007-11-28 12:36 Try this Interface Code: [Select] type   TForm1 = class(TForm)     procedure MouseMove(Sender: TObject; Shift: TShiftState; X,       Y: Integer);     procedure MouseUp(Sender: TObject; Button: TMouseButton;       Shift: TShiftState; X, Y: Integer);     procedure MouseDown(Sender: TObject; Button: TMouseButton;       Shift: TShiftState; X, Y: Integer);   private     { Private declarations }   public     { Public declarations }     Dragging:boolean;     //Are we dragging?     DragX,DragY:integer;  //What are the current mouse co-ords in the drag?     CtlX,CtlY:integer;    //Original posn of Control     StartPt:TPoint;     DragCtl:TControl;     //What is being dragged?   end; Implementation Code: [Select] procedure TForm1.MouseDown(Sender: TObject; Button: TMouseButton;   Shift: TShiftState; X, Y: Integer); var ix,iy:integer;     pt:TPoint; begin   //We're going to drag this...   DragCtl:=TControl(Sender);   Dragging:=true;   screen.Cursor:=crNone;   DragCtl.BringToFront;   StartPt:=Point(X,Y);   //How far off centre is the cursor to start with?   ix:=(DragCtl.Width shr 1)-X;   iy:=(DragCtl.Height shr 1)-Y;   //These are only for reference, and are relative..   DragX:=X+ix;   DragY:=Y+iy;   //Centre the cursor in the image   GetCursorPos(pt);   SetCursorPos(pt.X+ix,pt.Y+iy); end; procedure TForm1.MouseUp(Sender: TObject; Button: TMouseButton;   Shift: TShiftState; X, Y: Integer); begin   //Finished Dragging...   DragCtl:=nil;   Dragging:=false;   Screen.Cursor:=crDefault; end; procedure TForm1.MouseMove(Sender: TObject; Shift: TShiftState; X,   Y: Integer); var dx,dy:integer; begin   if Dragging then     begin       dx:=X-DragX;       dy:=Y-DragY;       DragCtl.SetBounds(DragCtl.Left+dx,DragCtl.Top+dy,DragCtl.Width,D ragCtl.Height);     end; end; This is taken from a Delphi app I have, so there might be some things that are windows specific [Like Get/SetCursorPos], but you can probably get away without them (if it's a problem, you can lose the centring code as well); You can wire up the Mouse events to any control, including the form. If there are problems let me know, and we can work through it. I haven't tested it on a lazdev box as yet, but it works fine in all versions of Delphi. HTH DSP ---------------------------------------------------------------------- The_Marlboro_Man · 2007-11-28 12:53 Thanks DuncanParsons, I thought you weren't coming back . I'll try to adapt your code to mine's. As you can easily guess, my code is pretty clumsy and always gets the cursor in the upper left corner of the moving object. Just yesterday I was trying to wrap my mind around a method that could store the "relative position" of the mouse but failed... I tried without declaring any globals and it seems that I need some of them. Also, I wasn't using the "setbounds" function, but directly changing the "left" and "top" positions... Anyway, I'll take a good and thorough look at this code and adapt it to my mine's to see if I can get rid of the annoying "upper left corner" behavior I get with this. Thanks!. PS: I'll try and post the finished code once I get it done correctly . Edit: Just did a bit of work and noticed that your code nicely puts the cursor in the middle of the form... I think I could use that in my application. Edit2: This is it Code: [Select] var puntoarrastre: tpoint //Declare this as global. procedure TFormulario1.Mover_Pulsar(Sender: TOBject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin     puntoarrastre.X:=Panel3.Left+BBoton_Mover.Left+X;           puntoarrastre.Y:=Panel3.Top+BBoton_Mover.Top+Y;     BBoton_Mover.Cursor:=crdrag; BBoton_Mover.Tag:=1 end; procedure TFormulario1.Mover_Mover(Sender: TObject; Shift: TShiftState; X, Y: Integer); var     punto: tpoint;     dentrodepantalla: boolean;     begin    dentrodepantalla:=(Formulario1.Left+Formulario1.Width+X <= Screen.Width) and (Formulario1.Top+Formulario1.Height+Y <= Screen.Height);    if (BBoton_Mover.Tag=1) and dentrodepantalla then    begin         punto:=mouse.GetCursorPos;         punto.X:=punto.X-puntoarrastre.X;         punto.Y:=punto.Y-puntoarrastre.Y;         Formulario1.SetBounds(punto.x, punto.y,Formulario1.Width,Formulario1.Height); end; end; procedure TFormulario1.Mover_Soltar(Sender: TOBject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin BBoton_Mover.Tag:=0 Jerky still, I don't know why... This makes Formulario1 (a form) move when pressing BBoton_Mover, a BitButton . ---------------------------------------------------------------------- duncanparsons · 2007-11-28 13:41 Weren't coming back? nah, sometimes things take me a while, but I do my best to honour my promises!! DSP ---------------------------------------------------------------------- The_Marlboro_Man · 2007-11-28 13:49 No problem, really, it is already a lot that you wanted to help and I am very thankful for that . Another question, is there a way to avoid "jerky" movement?. I tried your code and the form moves smoothly but mine's isn't that smooth. Maybe I have many things in the form?. Some code missing?. ---------------------------------------------------------------------- duncanparsons · 2007-11-30 13:15 Jerky.. hmm.. there's no code missing, it's pretty streamlined. Looking at your code.. you shouldn't need to use GetCursorPos, since it's passed to you in the procedure parameters (X, Y). Also I work out the deltas differently to you.. hmmm.. I think the way of getting it smooooth is to copy the code I've posted! You can leave out the CtlX,CtlY and StartPt from the public section, they were used for debugging. But so long as you stick to the essential elements, then you should be fine. DSP