Solved

Drawing and removing lines on a canvas

Posted on 2001-08-20
25
3,495 Views
Last Modified: 2012-05-04
Hi there!

I'm writing a small graphics editor and I need to know how to do fast removing of lines on a canvas. I have drawn a rectangles on the screen and want to move this rectangle on the canvas. First I remove the current rectangle and then redraw it somewhere else on the canvas. I can't get the removing of the rectangle to work. I've experimented with the Pen.Mode property a lot but didn't get it to work properly. I think I must use something like pmNot,pmXor or pmNotXor in combination with the color of the line and the background of the canvas. I do not want to redraw the entire canvas on the Paint event everytime I move a rectangle. Does anyone know what to do?

Bye,
jccommandeur
0
Comment
Question by:jccommandeur
  • 9
  • 6
  • 4
  • +2
25 Comments
 
LVL 6

Expert Comment

by:Jaymol
ID: 6405570
How about creating a TShape object instead of drawing.  That way, you can just free it.

John.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 6405579
To do 'smooth' rectangle move try this:
let say: background color is white
         line color is black
1.draw black rectangle in position A
2.draw black rectangle in position B
3.draw white rectangle in position A
4.draw black rectangle in position B
first impression is that You make too many rectangle draws but it dosn't slow drawing at all and moving is 'smooth'
ziolko.
 
0
 
LVL 6

Expert Comment

by:Jaymol
ID: 6405586
Or alternatively, have a seperate canvas to draw/delete on, with the background image never changing.

John.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 6405613
try this code
procedure TForm1.Button1Click(Sender: TObject);
var a,b: TRect;
    cnt,d: Integer;
begin
  d:=2;
  a.Left:=100;
  a.Top:=100;
  a.Right:=200;
  a.Bottom:=200;
  for cnt:=1 to 35 do
    begin
      sleep(15);
      a.Left:=a.Left+d;
      a.Top:=a.Top+d;
      a.Right:=a.Right+d;
      a.Bottom:=a.Bottom+d;
      b.Left:=a.Left+d;
      b.Top:=a.Top+d;
      b.Right:=a.Right+d;
      b.Bottom:=a.Bottom+d;
      Canvas.Brush.Color:=clBlack;
      Canvas.FrameRect(a);
      Canvas.FrameRect(b);
      Canvas.Brush.Color:=clBtnFace;
      Canvas.FrameRect(a);
      Canvas.Brush.Color:=clBlack;
      Canvas.FrameRect(b);
    end;
end;
Is taht what You want ??
ziolko.
0
 

Author Comment

by:jccommandeur
ID: 6405628
Hi there,

Thanks for the answers sofar. What I want is to be able to move a rectangle with the mouse while the background is preserved. I have a grid drawn on the canvas + a lot of other rectangles. I want to be able to just move one particular rectangle, while the others stay in position and are not overwritten by the moving of the other rectangle. Do you think using a TShape object will do the trick? If I free such TShape object, will the rectangle be deleted from the canvas as well?

Bye!
jccommandeur
0
 

Author Comment

by:jccommandeur
ID: 6405630
Hi there,

Thanks for the answers sofar. What I want is to be able to move a rectangle with the mouse while the background is preserved. I have a grid drawn on the canvas + a lot of other rectangles. I want to be able to just move one particular rectangle, while the others stay in position and are not overwritten by the moving of the other rectangle. Do you think using a TShape object will do the trick? If I free such TShape object, will the rectangle be deleted from the canvas as well?

Bye!
jccommandeur
0
 
LVL 6

Expert Comment

by:Jaymol
ID: 6405633
jccommandeur,

The TShape will be a visible component so that when you free it, it is no longer visible.  Give it a go, I'm sure you'll be pleased.

Jonh.
0
 
LVL 6

Expert Comment

by:zebada
ID: 6405819
Example code for easiest/fastest way to do this....

unit main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls;

type
  TfRubber = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    anchor: TPoint;
    roam: TPoint;

    procedure PainTfRubberBand;

  public
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure Paint; override;
  end;

var
  fRubber: TfRubber;

implementation

{$R *.DFM}

// -------------------------------------------------------------------------
procedure TfRubber.FormCreate(Sender: TObject);
begin
  anchor := Point(0,0);
  roam := Point(0,0);
end;

// -------------------------------------------------------------------------
procedure TfRubber.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  anchor := Point(X,Y);
  roam := Point(X,Y);
end;

// -------------------------------------------------------------------------
procedure TfRubber.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if ( ssLeft in Shift ) then
  begin
    PainTfRubberBand;
    roam := Point(X,Y);
    PainTfRubberBand;
  end;
end;

// -------------------------------------------------------------------------
procedure TfRubber.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  Roam := Point(X,Y);
  PainTfRubberBand;
  Invalidate;
end;

// -------------------------------------------------------------------------
procedure TfRubber.Paint;
begin
  Canvas.Pen.Color := clWhite;
  Canvas.Pen.Style := psSolid;
  Canvas.Pen.Mode := pmCopy;

  Canvas.Brush.Color := clNavy;
  Canvas.Brush.Style := bsSolid;
  Canvas.Ellipse(0,0,500,500);
  Canvas.Brush.Color := clRed;
  Canvas.Ellipse(10,60,400,300);
  Canvas.Brush.Color := clYellow;
  Canvas.Ellipse(200,400,600,300);
  Canvas.Brush.Color := clGreen;
  Canvas.Ellipse(100,100,300,600);

  Canvas.Brush.Style := bsSolid;
  Canvas.Brush.Color := clWhite;
  Canvas.Rectangle(anchor.X,anchor.Y,roam.X,roam.Y);
end;

// -------------------------------------------------------------------------
procedure TfRubber.PainTfRubberBand;
begin
  if ( (anchor.X=roam.X) or (anchor.Y=roam.Y) ) then
    exit;
  Canvas.Pen.Color := clWhite;
  Canvas.Pen.Style := psDot;
  Canvas.Pen.Mode := pmXor;
  Canvas.Brush.Style := bsClear;
  Canvas.Rectangle(anchor.X,anchor.Y,roam.X,roam.Y);
end;

end.
0
 
LVL 6

Expert Comment

by:zebada
ID: 6405824
oops, sorry didn't read the question.
I'll have another go...later
0
 
LVL 6

Expert Comment

by:zebada
ID: 6405840
Can you give a little more detail on exactly what you want?

- Do you want to move just the outline of the rectangle or the entire rectangle including the contents?
- Do you want the size of the rectangle to change, as in a rubber band/expanding selection type of rectangle? Like in my example code?
What determines the size of the rectangle?
0
 

Author Comment

by:jccommandeur
ID: 6406153
Hi!

I only want to move the outline of the rectangle. All I have is canvas with a grid drawn on it and a unknown number of other rectangles. Now I want to move one rectangle (just the outline) to another position by using the mouseover event. When I move the mouse, I want the rectangle to move to a new position given by the mouse coordinates. The movement must be visible on the screen, so you'll get a 'drag' effect.

Hope you guys can help out!
jccommandeur
0
 
LVL 6

Expert Comment

by:Jaymol
ID: 6406164
You can drag a TShape and the background will automatically redraw.

John.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Author Comment

by:jccommandeur
ID: 6407362
Hi!

Thanks for your answers. I've tried the TShape control and although it would be okay for rectangles and various other shapes, it won't satisfy my needs. I also need to redraw 3d cubes on my screen, not just rectangles. It seems I can't use a TShape control for that. What I would like is to be able to draw those rectangles and 3d cubes by drawing the individual lines of these objects or use Canvas.Polyline. Then, when I want to change the position of these rectangles and 3d cubes, I simply draw the original rectangle/3d cube again in the background color and then draw the new rectangle/3d cube on a different position in black. Seems to me I have to use a combination of TPen.Mode (Xor I think) and TPen.Color to achieve this but I don't know which! I sure hope somebody can help me, it's been bugging me for quite some time now.

Bye!
jccommandeur
0
 
LVL 33

Expert Comment

by:Slick812
ID: 6407551
I tried to find where you said the background was a solid color or not (an Image maybe, or text) , If you use Canvas.Pen.Mode := pmNot   , then the Pen Color is Ignored and a line will be drawn in the Reverse color of the background. . .  redrawing the Same Line will erase the first line as if it was never there. But then you say "then draw the new rectangle/3d cube on a different
position in black"  . . . . if you want to draw the line in a definite color like black you won't be able to Erase it by drawing another line (unless the background is a solid color), you may have to copy small retangles from a  Memory Bitmap that has the previous background on it.
Try setting the Pen Mode to pmNot and draw the new cube then redrawing the same cube to erase it, with the same pmNot pen mode. you may not get black lines on the new cubes but it WILL be visible.
0
 

Author Comment

by:jccommandeur
ID: 6407711
Hi there!

Well, I would like to use any colour to draw the rectangles. For example, when I first draw a rectangle, it should be black. When I select a rectangle, it should redraw the selected rectangle in red. Then, when I move the selected rectangle on the screen, it should show the rectangle in red while I'm moving it (using the mouse). Should I use a bitmap in memory to do the drawing on and copy that to the canvas, or something like that?

Bye,
jccommandeur
0
 
LVL 6

Expert Comment

by:zebada
ID: 6407811
Slick812 is exactly right, you will not be able to erase and redraw a rectangle (or any shape) if you want to use a solid color on a varying background.

Given that you have a grid and "other shapes" on the canvas already you will either need to save the background in a bitmap so that it can be restored when the rectangle is erased.

Otherwise you will need to do this:

Keep a "database" of shapes that you have drawn on the canvas - The "database" should contain enough information about each shape (color, coordinates, vertices etc) to enable you to "redraw" that shape.

When you "select" and exsiting shape on the canvas you will need to redraw the entire canvas, including the gridlines and all shapes EXCEPT the one that was selected.

Then...

1. Draw the selected rectangle using Canvas.pen.mode:= pmXor.
2. Then on mouse move redraw it in the same position to erase it.
3. Then redraw it in a new position to show it has moved.
4. Repeat 2 and 3 for each mose movement.
5. on mouseup, update the shapes database with the new position of the shape.
6. Redraw the entire canvas from the information contained in your shapes "database".

Do you want working code?

0
 

Author Comment

by:jccommandeur
ID: 6407889
Hi,

Thanks for all the answers sofar. Seems like we're getting there. I have a shape-database already running. It contains info on all the rectangles (cubes actually) so I can draw them anytime I need to. When I move a rectangle, I need all other rectangles + the grid to be visible and without any flickering. Does the above method do that (I think so). I would like to see that working code, it sounds promising. Mail to jeroencc@hetnet.nl if you like.

Thanks in advance,
jccommandeur
0
 
LVL 6

Expert Comment

by:zebada
ID: 6408324
I'll mail it to this list later tonight, (New Zealand Time) when I get home. I've got to write it first :)
0
 
LVL 33

Accepted Solution

by:
Slick812 earned 100 total points
ID: 6408552
jccommandeur , , I could not find the code I used to do something like what you need, but here are some How To examples from what I remember
 I am using a MouseDown to start the drag and Drop Movement of the cube and the MouseUp to stop it. I use a "ShowPic" memory Bitmap Canvas to create the look I want and then Show it in the PaintBox. I also Make a "BackUpPic" bitmap so the user can undo a misteak.


  private
    { Private declarations }
    ShowPic, BackUpPic: TBitmap;
    DrawIt: Boolean;
    NewX,NewY: Integer;

procedure TForm1.FormCreate(Sender: TObject);
begin
DrawIt := False;
ShowPic := TBitmap.Create;
FirstPic.Width := PaintBox1.Width;
FirstPic.Height := PaintBox1.Height;
BackUpPic := TBitmap.Create;
BackUpPic.Width := ShowPic.Width;
BackUpPic.Height := ShowPic.Height;
NewX := 0;
NewY := 0;
end;

procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
PBrect: TRect;
begin
if Button = mbLeft then
  begin
  BackUpPic.Assign(ShowPic);
{this is for an UnDo event to restore the Positions
if you messed up}
  PBrect := PaintBox1.ClientRect;
  PBrect.TopLeft := ClientToScreen(PBrect.TopLeft);
  PBrect.BottomRight := ClientToScreen(PBrect.BottomRight);
  ClipCursor(@PBrect);
  {this ClipCursor prevents the mouse cursor from
   moving outside the PaintBox during a drag,
   you may want to reduce the rect}
  {PaintBox1.Canvas.Pen.Color := clWhite;}
  {do all of the Canvas Creation with the ShowPic Bitmap -
   ShowPic.Canvas.Draw , Make all your Cubes in Black,
   ect. but DO NOT draw the Moving Cube}
  PaintBox1.Canvas.Draw(0,0,ShowPic);
  {display the finished ShowPic}
  PaintBox1.Canvas.Pen.Style := psSolid;
  PaintBox1.Canvas.Pen.Mode := pmNot;
{you can set this pen Mode in the FormCreate if you don't need to change it}
  PaintBox1.Canvas.Rectangle(X-5,Y-5,X+18,Y+18);
  {now draw a cube on the Display Canvas, I just use Canvas.Rectangle here}
  NewX := X;
  NewY := Y;
  DrawIt := True;
  end;
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
  begin
  PaintBox1.Canvas.Rectangle(NewX,NewY,NewX+18,NewY+18);
   // draw the Cube to erase it
  FirstPic.Canvas.CopyRect(Rect1,PaintBox1.Canvas,Rect1);
  ClipCursor(nil); // Relaese the Cursor
  DrawIt := False;
  PaintBox1.Canvas.Pen.Mode := pmCopy;
  {you don't need to change the pen mode back and forth if
  you don't use the pen in other places}
  {do all of the Canvas Creation with the ShowPic Bitmap
  again and draw a New Cube in it's New Location at the X
   and Y here}
  PaintBox1.Canvas.Draw(0,0,ShowPic);
  {now display the the finished ShowPic with all the cubes}
  end;
end;

procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
if DrawIt then
  begin
  PaintBox1.Canvas.Rectangle(NewX-5, NewY-5, NewX+18, NewY+18);
// this removes the old Cube
  PaintBox1.Canvas.Rectangle(X-5,Y-5,X+18,Y+18);
// this makes a new cube
  NewX := X;
  NewY := Y;
// get NewX and NewY
  end;
end;

procedure TForm1.sBut_UndoClick(Sender: TObject);
begin
PaintBox1.Canvas.Draw(0,0,BackUpPic);
{if you want to have a ReDo then don't Draw on the Showpic}
ShowPic.Canvas.Draw(0,0,BackUpPic);
end;

- - - - - - - - - - - - - - - - -
I hope this gives you an Idea of how to get what you want. .  let me know
0
 

Author Comment

by:jccommandeur
ID: 6408953
Hello there,

Yes, this is looking good. However, I want the moving cube to be in any colour. I think I will have to use 2 bitmaps to achieve that. One contains the background with all the other cubes EXCEPT the selected cube. This bitmap is static. I copy this bitmap to the second bitmap. Then I draw the moving rectangle onto this second bitmap in the colour I want (so I'm using pmCopy). When that's done, I copy the second bitmap to the canvas. The reason for using 2 bitmaps would be to avoid flickering (i hope that works). This does mean, however, that I have to copy the entire second bitmap to the canvas on each mousemove event. Wouldn't this slow things down?

Bye,
jccommandeur
0
 
LVL 6

Expert Comment

by:zebada
ID: 6409103
Try this code...
Although it only draws the moving rectangle in a "wireframe", it is very fast with absolutely
no flicker.

unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

const
  MAX_SHAPES=3;
  ROW_SIZE=20;
  Col_SIZE=20;

type
  TPointArray = array of TPoint;

  // =======================================================================
  TWireFrame = class(TObject)
  private
    // Property storage
    FShape: TPointArray;
    FColor: TColor;

    // Property accessors
    function GetCount: integer;
    procedure SetCount(const Value: integer);
    function GetVertex(Index: integer): TPoint;
    procedure SetVertex(Index: integer; const Value: TPoint);

    // Procedures and functions

  public
    // Constructors and Destructors
    constructor Create;
    destructor Destroy; override;

    // Procedures and functions

    // Properties
    property Count: integer read GetCount write SetCount;
    property Vertex[Index: integer]: TPoint read GetVertex write SetVertex;
    property Shape: TPointarray read FShape;
    property Color: TColor read FColor write FColor;
  end;

  // =======================================================================
  TfWireFrame = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);

    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;

  private
    WireFrames: array of TWireFrame;
    selected: integer;
    anchor: TPoint;
  public
    procedure Paint; override;
    procedure PaintShapes;
    procedure PaintShape(s: integer);
    function SelectShape(X,Y: integer): integer;
  end;

var  fWireFrame: TfWireFrame;

implementation

{$R *.DFM}

// =========================================================================
// TfWireFrame
// =========================================================================
procedure TfWireFrame.FormCreate(Sender: TObject);
var
  i: integer;
begin
  DoubleBuffered := true;  // Stops most of the flicker.

  SetLength(WireFrames,MAX_SHAPES);
  selected := -1;

  for i:=0 to MAX_SHAPES-1 do
    WireFrames[i] := TWireFrame.Create;

  // Generate test data

  // Shape 0 is a Triangle
  WireFrames[0].Color := clBlue;
  WireFrames[0].Count := 4;
  WireFrames[0].Vertex[0] := Point(110,10);
  WireFrames[0].Vertex[1] := Point(210,110);
  WireFrames[0].Vertex[2] := Point(10,110);
  WireFrames[0].Vertex[3] := Point(110,10);

  // Shape 1 is a Rectangle
  WireFrames[1].Color := clRed;
  WireFrames[1].Count := 5;
  WireFrames[1].Vertex[0] := Point(110,120);
  WireFrames[1].Vertex[1] := Point(210,120);
  WireFrames[1].Vertex[2] := Point(210,170);
  WireFrames[1].Vertex[3] := Point(110,170);
  WireFrames[1].Vertex[4] := Point(110,120);

  // Shape 2 is a Square
  WireFrames[2].Color := clGreen;
  WireFrames[2].Count := 5;
  WireFrames[2].Vertex[0] := Point(10,120);
  WireFrames[2].Vertex[1] := Point(60,120);
  WireFrames[2].Vertex[2] := Point(60,170);
  WireFrames[2].Vertex[3] := Point(10,170);
  WireFrames[2].Vertex[4] := Point(10,120);
end;

// _________________________________________________________________________
procedure TfWireFrame.FormDestroy(Sender: TObject);
var
  i: integer;
begin
  for i:=0 to Length(WireFrames)-1 do
    if ( Assigned(WireFrames[i]) ) then
      WireFrames[i].Free;
end;

// _________________________________________________________________________
procedure TfWireFrame.Paint;
var
  r,c: integer;
begin
  inherited;

  Canvas.Brush.Style := bsSolid;
  Canvas.Brush.Color := clSilver;
  Canvas.FillRect(ClientRect);

  // Draw grid
  Canvas.Pen.Style := psDot;
  Canvas.Pen.Color := clBlack;
  Canvas.Pen.Width := 1;
  Canvas.Pen.Mode := pmCopy;
  r := 0;
  while ( r<Height ) do
  begin
    Canvas.MoveTo(0,r);
    Canvas.LineTo(Width,r);
    Inc(r,ROW_SIZE);
  end;
  c := 0;
  while ( c<Width ) do
  begin
    Canvas.MoveTo(c,0);
    Canvas.LineTo(c,Height);
    Inc(c,COL_SIZE);
  end;
  paintShapes;
end;

// _________________________________________________________________________
procedure TfWireFrame.PaintShapes;
var
  s: integer;
begin
  Canvas.Pen.Width := 2;
  // Draw shapes except for selected shape
  for s:=Length(WireFrames)-1 downto 0 do
    if ( s<>selected ) then
    begin
      Canvas.Pen.Color := WireFrames[s].Color;
      PaintShape(s);
    end;
end;

// _________________________________________________________________________
procedure TfWireFrame.PaintShape(s: integer);
begin
  if ( WireFrames[s].Count<=0 ) then
    exit;
  Canvas.MoveTo(WireFrames[s].Vertex[0].X,WireFrames[s].Vertex[0].Y);
  Canvas.PolyLine(WireFrames[s].Shape);
end;

// _________________________________________________________________________
function TfWireFrame.SelectShape(X,Y: integer): integer;
var
  s,i: integer;
  xmin,xmax,ymin,ymax: integer;
begin
  for s:=0 to Length(WireFrames)-1 do
    with WireFrames[s] do
    begin
      xmin := MAXINT;
      xmax := -MAXINT;
      ymin := MAXINT;
      ymax := -MAXINT;
      for i:=0 to Count-1 do
      begin
        if ( Vertex[i].X<xmin ) then xmin := Vertex[i].X;
        if ( Vertex[i].Y<ymin ) then ymin := Vertex[i].Y;
        if ( Vertex[i].X>xmax ) then xmax := Vertex[i].X;
        if ( Vertex[i].Y>ymax ) then ymax := Vertex[i].Y;
      end;
      if ( (xmin<=X) and (x<=xmax) and (ymin<=Y) and (Y<=ymax) ) then
      begin
        Result := s;
        exit;
      end;
    end;
  Result := -1;
end;

// _________________________________________________________________________
procedure TfWireFrame.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  selected := SelectShape(X,Y);
  if ( selected>=0 ) then
  begin
    anchor := Point(X,Y);
    Canvas.Pen.Mode := pmNot;
    Canvas.Pen.Width := 1;
    PaintShape(selected);
  end;
end;

// _________________________________________________________________________
procedure TfWireFrame.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  dx,dy: integer;
  i: integer;
begin
  inherited;
  if ( selected>=0 ) then
  begin
    PaintShape(selected);
    dx := X-anchor.X;
    dy := Y-anchor.Y;
    with WireFrames[selected] do
      for i:=0 to Count-1 do
        Vertex[i] := Point(Vertex[i].X+dx,Vertex[i].Y+dy);
    PaintShape(selected);
    anchor := Point(X,Y);
  end;
end;

// _________________________________________________________________________
procedure TfWireFrame.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  s: integer;
begin
  inherited;
  if ( selected>=0 ) then
  begin
    s := selected;
    PaintShape(s);
    selected := -1;
    Invalidate;
  end;
end;

// =========================================================================
// TWireFrame
// =========================================================================
constructor TWireFrame.Create;
begin
  inherited;
  SetLength(FShape,0);
end;

// _________________________________________________________________________
destructor TWireFrame.Destroy;
begin
  inherited;
end;

// _________________________________________________________________________
function TWireFrame.GetCount: integer;
begin
  Result := Length(FShape);
end;

// _________________________________________________________________________
procedure TWireFrame.SetCount(const Value: integer);
begin
  SetLength(FShape,Value);
end;

// _________________________________________________________________________
function TWireFrame.GetVertex(Index: integer): TPoint;
begin
  if ( (Index<0) or (Count<=Index) ) then
    Raise Exception.CreateFmt('Index: %d out of range: %d..%d in GetVertex',[Index,0,Count-1]);
  Result := FShape[Index];
end;

// _________________________________________________________________________
procedure TWireFrame.SetVertex(Index: integer; const Value: TPoint);
begin
  if ( (Index<0) or (Count<Index) ) then
    Raise Exception.CreateFmt('Index: %d out of range: %d..%d in SetVertex',[Index,0,Count-1]);
  if ( Index=Count ) then
    Count := Count+1;
  FShape[Index] := Value;
end;

end.


0
 
LVL 33

Expert Comment

by:Slick812
ID: 6410860
I would take the easy way and not have the moving cubes be a certain color (like red) but be the pmNOT color, after all you can see it. But you can do page flipping and draw the rectangles as the mouse moves. but you may have some flicker unless you use Direct draw. A trickier problem is the selection of a cube if they overlap (3 or 4 cubes overlap)
0
 

Author Comment

by:jccommandeur
ID: 6411360
Okay, thanks. I'll go and try a few methods and see what works best for me. I absolutely don't wait flicker and redrawing all cubes each frame (each mousemove) isn't an option (too many cubes). I'm also thinking about just saving the background of the moving rectangle and restoring it on each mousemove. That might be faster than copying a bitmap containing the entire canvas. I don't know for sure... I would like to have different colours though.
 Indeed the selection of a cube is trickier. I have a basic selection method working but need to improve that. Of course, suggestions are welcome. ;-)

Bye,
jccommandeur
0
 
LVL 33

Expert Comment

by:Slick812
ID: 6411728
I was wrong about the screen flicker, shows how bad my memory is, ha ha. Here's some code for moving the cube with page flipping. You need to make up a "basePic" to copy the Erase rectangle from and use the ShowPic for the page flipping. Create the basePic in the FormCreate, the Same as the ShowPic (same width and height). This is the code for the MouseDown and MouseMove.



procedure TForm1.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
PBrect: TRect;
begin
if Button = mbLeft then
  begin
  basePic.Canvas.Pen.Color := clBlack;
  basePic.Canvas.Rectangle(35,45,118,68);
  basePic.Canvas.Rectangle(105,205,168,298);
  basePic.Canvas.Rectangle(105,25,148,198);
  {do all of the Canvas Creation with the basePic Bitmap
   Make all your Cubes in Black, ect. but
    DO NOT draw the Moving Cube}
  BitBlt(PaintBox1.Canvas.Handle, 0, 0, basePic.Width, basePic.Height, basePic.Canvas.Handle, 0, 0, SRCCOPY);

  BitBlt(ShowPic.Canvas.Handle, 0, 0, basePic.Width, basePic.Height, basePic.Canvas.Handle, 0, 0, SRCCOPY);
{copy the finished basePic to the Display Cancas and to the ShowPic bitmap BitBlt is faster than Canvas.CopyRect because CopyRect uses the StretchBlt() and is slower}

  PaintBox1.Canvas.Pen.Color := clRed;
  PaintBox1.Canvas.Rectangle(X-5,Y-5,X+18,Y+18);
  {now draw a Red cube on the Display Canvas, I just use Canvas.Rectangle here}
  NewX := X;
  NewY := Y;
  ShowPic.Canvas.Pen.Color := clRed;
  // change the ShowPic pen Color
  DrawIt := True;
  end;
end;

procedure TForm1.PaintBox2MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
if DrawIt then
  begin
BitBlt(ShowPic.Canvas.Handle, NewX-7, NewY-7, 25, 25,
       basePic.Canvas.Handle, NewX-7, NewY-7, SRCCOPY);  
{this removes the old Cube with a Rectangle slightly larger than the cube}

ShowPic.Canvas.Rectangle(X-5,Y-5,X+18,Y+18);
// this makes a new red cube on the ShowPic

BitBlt(PaintBox1.Canvas.Handle, 0, 0, ShowPic.Width, ShowPic.Height, ShowPic.Canvas.Handle, 0, 0, SRCCOPY);
{flip the ShowPic to the display}
  NewX := X;
  NewY := Y;
// get NewX and NewY
  end;
end;

procedure TForm1.PaintBox2MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
  begin
  DrawIt := False;
ShowPic.Canvas.Pen.Color := clBlack;
ShowPic.Canvas.Rectangle(NewX-5,NewY-5,X+18,Y+18);
// this makes a new black cube on the ShowPic over the red one

BitBlt(PaintBox1.Canvas.Handle, 0, 0, ShowPic.Width, ShowPic.Height, ShowPic.Canvas.Handle, 0, 0, SRCCOPY);
  end;
end;

- - - - - - - - - - - - - - - - - - -

I used the keyboard Space key to cycle thorugh the Overlaped images once the left mouse button was down. but this was not a usual method and was missed by many users.
hope this helps
0
 

Author Comment

by:jccommandeur
ID: 6415157
Hi ya'll.

Well, I've tried a few ways and using a few bitmaps as background seems like the best approach for my program (doublebuffering simply rules :-)). Also thanks, Slick812, for providing some sample code, it did help me to remove a nasty bug in my own code. ;-) Btw, too bad I can't give points to more people, I've gained a few nice ideas during this discussing so thanks to all of you!

Bye,
jccommandeur
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Delphi XE7 Rest Client 2 174
ddeman not working in activex 3 78
Send message from delphi to whatsapp, is it possible? 3 923
LAN or WAN ? 11 61
This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
This video discusses moving either the default database or any database to a new volume.
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now