SmRndGuy
SmRndGuy

Reputation: 1819

Drawing on a Canvas - How to check if the left Mouse button is down?

I have a Canvas, and I want to draw on it like MS Paint for example.

I have tried the following methods but with no success:

(1)

Canvas.OnMouseDown

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
       //Draw something (Lets say a rect for example*)
       Image1.Canvas.Rectangle(x,y,x+4,y+4);
end;

(2)

I tried Canvas.OnMouseDown and Canvas.OnMouseUp combined as shown on in an example from this site:

http://www.delphipages.com/forum/showthread.php?t=142153

(3)

GetAsyncKeyState:

http://msdn.microsoft.com/en-us/library/ms646293%28VS.85%29.aspx to detect mouse downs

(4)

Mouse.IsDraging function.

I still cannot get any success with the above methods I have tried.

Every time when I want to drag the cursor and draw it justs places 1 Rect* at the position where I first clicked, how do I get it to progressively draw?

Upvotes: 0

Views: 4684

Answers (4)

MohsenB
MohsenB

Reputation: 1921

if you need line like up code :

procedure TForm1.img1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  (Sender as TImage).Canvas.MoveTo(X, Y);
end;


procedure TForm1.img1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  (Sender as TImage).Canvas.LineTo(X, Y);
end;

or , if you need draw free-from line use:

procedure TForm1.img1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  with (Sender as TImage) do begin
    if Shift = [ssLeft] then
      Canvas.LineTo(X, Y);
    Canvas.MoveTo(X, Y);
  end;
end;

Upvotes: 0

user1175743
user1175743

Reputation:

The way I would do it is like this:

var
  Form1: TForm1;

  IsDrawing: Boolean; // flag to determine if drawing or not

implementation

{$R *.dfm}

procedure DoPaint(ACanvas: TCanvas; X, Y: Integer; AColor: TColor;
  ASize: Integer; AStyle: TPenStyle; Persistent: Boolean);
begin
  with ACanvas do
  begin
    Pen.Color := AColor;
    Pen.Style := AStyle;
    Pen.Width := ASize;

    if not Persistent then
      MoveTo(X, Y);
    LineTo(X, Y);
  end;
end;

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  case Button of
    mbLeft:
    begin
      IsDrawing := True;
      DoPaint(Form1.Canvas, X, Y, clBlue, 10, psSolid, False);
    end;
  end;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if (GetAsyncKeyState(VK_LBUTTON) <> 0) and
     (IsDrawing) then
  begin
    DoPaint(Form1.Canvas, X, Y, clBlue, 10, psSolid, True);
  end;
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  IsDrawing := False;
end;

Two things to note here are the MouseMove event and GetAsyncKeyState. You used MouseDown and MouseUp, but MouseMove which is needed to continue the drawing.

The MouseMove event will track the movement on the canvas. Obviously you only need to draw if you were to begin with. To handle this you can set a simple Boolean flag as I have demonstrated using IsDrawing - This is set to True when you MouseDown on the canvas, and set to False when you MouseUp on the canvas.

Using the IsDrawing flag along with GetAsyncKeyState you can now determine whether to continue drawing on the canvas or not. As described in the MSDN article you need to be aware that GetAsyncKeyState only tracks the physical button layout, not the logical ones:

The GetAsyncKeyState function works with mouse buttons. However, it checks on the state of the physical mouse buttons, not on the logical mouse buttons that the physical buttons are mapped to. For example, the call GetAsyncKeyState(VK_LBUTTON) always returns the state of the left physical mouse button, regardless of whether it is mapped to the left or right logical mouse button. You can determine the system's current mapping of physical mouse buttons to logical mouse buttons by calling GetSystemMetrics(SM_SWAPBUTTON).

which returns TRUE if the mouse buttons have been swapped.

Upvotes: 2

Ken White
Ken White

Reputation: 125708

You need to track whether or not you're dragging the mouse (the left button is down), save where the starting point is, and in the OnMouseUp event draw your line. (This won't fully do what you want, because it doesn't show where your line will appear, and won't clear any previous lines you've drawn. You need to track those in OnMouseMove. It should get you started, though.)

unit Unit2;

interface

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

type
  TForm2 = class(TForm)
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
    Drawing: Boolean;
    mX, mY: Integer;
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if [ssLeft] = Shift then
  begin
    Drawing := True;
    mX := X;
    mY := Y;
  end;
end;

procedure TForm2.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Drawing and not (ssLeft in Shift) then  // Left button released
  begin
    Canvas.MoveTo(mX, mY);
    Canvas.LineTo(X, Y);
    Drawing := False;
  end;
end;

end.

Upvotes: 6

Tony Hopkinson
Tony Hopkinson

Reputation: 20320

In MouseDown, set a boolean to say its down and store the position of the mouse. InMouseMove if the mouse is down draw from last position to current position, store current position. In MouseUp reset the boolean

One way, anyway.

Upvotes: 3

Related Questions