3

I have a form where I have created a button programmatically like this :

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);        
  private
    FTableButton : TButton;       
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not Assigned(FTableButton) then begin
    FTableButton := TButton.Create(self);
    FTableButton.Parent := self;       
  end;
end;    

end.

How can I let the user move FTableButton on the form by dragging it?

J...
  • 30,968
  • 6
  • 66
  • 143
  • 1
    This is not a code writing service nor a design service. You need to put some effort in yourself. Then, if you get stuck with a particular problem, show us your problem and we will try to help. If you don't know how to drag and drop then google it. There is plenty of stuff out there. – Dsm Dec 21 '16 at 14:11
  • @Dsm What exactly does one google for how to make a button create an object in real time –  Dec 21 '16 at 14:18
  • 1
    This is a programming *project*, not a focused, specific question about a programming *problem*. On the surface the question is short and easy but the solution to implement this is going to require leveraging a lot of different tools. This type of question is off-topic - what you really seem to be looking for here is a tutorial or short course. If you want to ask here, what you need to do is to break this problem down into smaller pieces - figure out what each step will be towards achieving the final goal and ask about *specific* places you get stuck. – J... Dec 21 '16 at 14:23
  • This could be a good place to start [Drag and Drop in Controls](http://docwiki.embarcadero.com/RADStudio/en/Implementing_Drag_and_Drop_in_Controls) – J... Dec 21 '16 at 14:25
  • @J... What more can i do to break this down? thanks for the down vote –  Dec 21 '16 at 14:26
  • @J... If I'm going to be breaking this down, then the first problem is the program generating something that can be dragged when the user clicks a button –  Dec 21 '16 at 14:28
  • What more? *You need to make the buttons at the top create an item of sorts.* Do you have an object model for those items? Do you need help with this part? Do you know how to create those objects? Do you need help with that part? If yes, ask it as a separate question. – J... Dec 21 '16 at 14:28
  • *If the user selects 'seat' then it also needs to be able to be edited to enter a string.* - Do you need help with this part? Is this part of your question? *Also, I need the location to be saved so that whenever they reopen the saved file all the items return to where they were 'dropped'* Do you need help with this part? Is it part of your question? – J... Dec 21 '16 at 14:29
  • "*...the first problem is the program generating something that can be dragged when the user clicks a button*" Ok, this is getting better. So you're going to need some sort of container to store the collection of objects you will be creating. I'd start by forgetting about drag and drop, at this point, and just get this part implemented. Build an object model, have a button click generate an object, and draw it to the form - forget about interaction, just get the basics working first. Once you have a framework built then you can start implementing more complex behaviour. – J... Dec 21 '16 at 14:33
  • One of the critical things you need to do when developing is to break up the project into logical pieces like this - just jumping in at the deep end without a plan is going to leave you flailing. – J... Dec 21 '16 at 14:35
  • @J... Ok so im assuming that using an onclick event is required but is there some sort of built in function that creates an object in real time that i can use to start this part? –  Dec 21 '16 at 14:39
  • I think you're getting ahead of yourself here. Objects are created by calling their constructors - ie (`TMyObject.Create`, etc). If this doesn't make sense to you then you're probably starting with a project that's too complex. It may be worth spending some time working through a few tutorials first until you're more comfortable with the basics of the language. In this case, it seems like you're starting at the wrong end - the GUI should probably be the *last* thing you implement, not the *first*. – J... Dec 21 '16 at 14:47
  • Maybe start here : [Programming With Delphi](http://docwiki.embarcadero.com/RADStudio/en/Programming_with_Delphi_Index). Pay particular attention to the object model section. – J... Dec 21 '16 at 14:49
  • @J... I have managed to create the the table object, how I am doing seat which eventually will lead me to allowing the user to edit the text. I used the following code: –  Dec 21 '16 at 14:56
  • @J... didnt mean to create separate comments var DF: TButton; begin DF := TButton.Create(Button1); DF.Left := 100; DF.Top := 100; DF.Width := 118; DF.Height := 57; DF.Visible := True; DF.Parent := Self; –  Dec 21 '16 at 14:56
  • @Not_Lucas Ok, you've created a button - but a button is not a table or a seat. Ideally you'll want to design your own object. At this point we're getting way off topic here. This question will almost certainly be closed as too broad. You may want to [edit] it, however, to reduce the scope to something like "How can I make a button draggable on a Form", or some such. – J... Dec 21 '16 at 15:01
  • @Not_Lucas I've edited your question to massively reduce the scope to the one problem of how to move a control on a form. Questions here on Stack Overflow should generally be of this sort - very focused and specific questions. When working through your project you should really try to break it down into micro-steps like this - it will help your development and will keep you thinking about how each piece will fit into the whole. – J... Dec 21 '16 at 15:21

1 Answers1

4

By implementing the OnMouseDown, OnMouseMove and OnMouseUp events of a control you can allow the user to move it like this :

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);        
  private
    FTableButton : TButton;
    FTableButtonDragging : boolean;
    FMouseDownLocation : TPoint;
    FButtonStartingLocation : TPoint;
    procedure TableButtonMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure TableButtonMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure TableButtonMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not Assigned(FTableButton) then begin
    FTableButton := TButton.Create(self);
    FTableButton.Parent := self;
    FTableButton.Caption := 'I am New';
    FTableButton.OnMouseDown := TableButtonMouseDown;
    FTableButton.OnMouseMove := TableButtonMouseMove;
    FTableButton.OnMouseUp := TableButtonMouseUp;
  end;
end;

procedure TForm1.TableButtonMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FTableButtonDragging := true;
  FMouseDownLocation := Mouse.CursorPos;
  FButtonStartingLocation := TPoint.Create(FTableButton.Left, FTableButton.Top);
end;

procedure TForm1.TableButtonMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if FTableButtonDragging then begin
    FTableButton.Left := FButtonStartingLocation.X + (Mouse.CursorPos.X - FMouseDownLocation.X);
    FTableButton.Top := FButtonStartingLocation.Y + (Mouse.CursorPos.Y - FMouseDownLocation.Y);
    FTableButton.Invalidate;
  end;
end;

procedure TForm1.TableButtonMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  FTableButtonDragging := false;
end;

end.

Here we've added three new procedures to the form :

 procedure TableButtonMouseDown(Sender: TObject; Button: TMouseButton;
                                Shift: TShiftState; X, Y: Integer);
 procedure TableButtonMouseMove(Sender: TObject; Shift: TShiftState; 
                                X, Y: Integer);
 procedure TableButtonMouseUp(Sender: TObject; Button: TMouseButton;
                              Shift: TShiftState; X, Y: Integer);

and we have assigned these procedures as handlers for the new FTableButton's events :

FTableButton.OnMouseDown := TableButtonMouseDown;
FTableButton.OnMouseMove := TableButtonMouseMove;
FTableButton.OnMouseUp := TableButtonMouseUp;

When clicking on the button you need to store both the control's location and the mouse position when you placed the click, as well as that the mouse is currently down. Three new fields are used for this :

FTableButtonDragging : boolean;
FMouseDownLocation : TPoint;
FButtonStartingLocation : TPoint;

When moving the mouse, then, you can update the position of the control based on its original position and the difference between the current mouse position and the mouse position when the click was made.

J...
  • 30,968
  • 6
  • 66
  • 143
  • You do need to be careful about the OnClick event. This allows you to move the button, but not to click it (or it will always click anyway - not too sure which). You probably in practice need extra states to indicate clicked-not-yet-moved or an extra button to enable movement. – Dsm Dec 22 '16 at 09:23
  • @Dsm Of course. I'm not writing a tutorial here - there are always a million things you need to be careful about when writing actual code. This is just a minimal example to get OP un-stuck. – J... Dec 22 '16 at 10:14
  • Ok so I changed this code a little so that the table is named depending on how many tables have been produced {Table(i) where i increases each time}, now i'm trying to allow the user to press the button numerous times to produce more tables but I'm not exactly sure of what loop to use as there isn't a condition, e.g once clicked allow to be reclicked to produce another table, that i can use. In its current state once clicked it can't be clicked again. –  Dec 22 '16 at 10:54
  • @Not_Lucas Sounds like a topic for another question... I'd probably suggest you try to do a bit of learning at this point, however. You're still getting stuck on fundamentals. Take some time to work through tutorials - get a handle on object creation, lifetime management, value vs. reference types, etc. You're trying to run before you can walk here and it's getting you into a tangled mess. – J... Dec 22 '16 at 11:14