Recent

Author Topic: Moving forms.  (Read 15512 times)

The_Marlboro_Man

  • New Member
  • *
  • Posts: 33
Moving forms.
« on: November 22, 2007, 05:17:58 pm »
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

  • Full Member
  • ***
  • Posts: 117
    • http://itaprogaming.free.fr
RE: Moving forms.
« Reply #1 on: November 22, 2007, 05:37:22 pm »
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

  • New Member
  • *
  • Posts: 33
RE: Moving forms.
« Reply #2 on: November 22, 2007, 06:04:23 pm »
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

  • Full Member
  • ***
  • Posts: 117
    • http://itaprogaming.free.fr
RE: Moving forms.
« Reply #3 on: November 22, 2007, 08:25:57 pm »
Maybe you haven't replaced "Messages" with "LMessages" in the uses section of your unit :)

duncanparsons

  • Jr. Member
  • **
  • Posts: 83
RE: Moving forms.
« Reply #4 on: November 23, 2007, 10:10:08 am »
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

  • New Member
  • *
  • Posts: 33
RE: Moving forms.
« Reply #5 on: November 23, 2007, 05:07:53 pm »
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 :D. 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

  • Jr. Member
  • **
  • Posts: 83
RE: Moving forms.
« Reply #6 on: November 28, 2007, 01:36:53 pm »
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,DragCtl.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

  • New Member
  • *
  • Posts: 33
RE: Moving forms.
« Reply #7 on: November 28, 2007, 01:53:16 pm »
Thanks DuncanParsons, I thought you weren't coming back :P.

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

  • Jr. Member
  • **
  • Posts: 83
RE: Moving forms.
« Reply #8 on: November 28, 2007, 02:41:18 pm »
Weren't coming back? nah, sometimes things take me a while, but I do my best to honour my promises!!

DSP

The_Marlboro_Man

  • New Member
  • *
  • Posts: 33
RE: Moving forms.
« Reply #9 on: November 28, 2007, 02:49:28 pm »
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

  • Jr. Member
  • **
  • Posts: 83
RE: Moving forms.
« Reply #10 on: November 30, 2007, 02:15:43 pm »
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

 

TinyPortal © 2005-2018