Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   crear efecto "deshacer" en editor grafico (https://www.clubdelphi.com/foros/showthread.php?t=61845)

pablopessoa 24-11-2008 18:46:34

crear efecto "deshacer" en editor grafico
 
hola! sigo haciendo mi editor grafico y me gustaria hacer un efecto tipo "deshacer" o "control + z" y que esto borre lo ultimo que se haya hecho.
se que deberia guardar siempre lo ultimo que se hizo para poder eliminarlo, pero no se como se podria hacer, podran iluminarme un poco?
Muchas Gracias!!

coso 24-11-2008 23:01:22

1 Archivos Adjunto(s)
Hola, podrias usar varios metodos:
- ir guardando todos los comandos ejecutados en una lista, y al pulsar deshacer, ir ejecutandolos todos desde el principio hasta el que desees (que tendria que ser el anterior)
- ir guardando las pantallas, y reponerlas al aplicar el deshacer
- ir guardando los 'anticomandos' (si un comando es linea de A a B, este seria linea de B a A con el color de fondo)

Te dejo un ejemplo de el segundo metodo, a ver si te sirve ;):

Código Delphi [-]
unit back;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Guarda;
    procedure Button1Click(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
    index : integer;
    deshacer : array [0..200] of TBitmap;

  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Guarda;
var
     i : integer;
begin
     label1.Caption := inttostr(index);

     if index = 200 - 1 then  // si hay mas de 200, 'movemos' todos para el principio, perdiendo la primera pantalla guardada
     for i := 1 to 200 - 2 do
     bitblt(deshacer[i-1].Canvas.Handle,0,0,deshacer[i-1].Width,deshacer[i-1].Height,deshacer[i].Canvas.Handle,0,0,SRCCOPY);

     bitblt(deshacer[index].Canvas.Handle,0,0,Width,Height,Canvas.Handle,0,0,SRCCOPY);

     if index < 200 - 1 then Inc(index);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
     i : integer;
begin
     Color := $220000;
     Label1.Font.Color := clWhite;
     Label1.Caption := '0';
     for i := 0 to 200 - 1 do
     begin
          deshacer[i] := TBitmap.Create;
          deshacer[i].Width  := ClientWidth;
          deshacer[i].Height := ClientHeight;
     end;

     index := 0;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
     i : integer;
begin
     for i := 200-1 downto 0 do
     deshacer[i].Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
     if index = 0 then exit;

     dec(index);

     bitblt(Canvas.Handle,0,0,ClientWidth,ClientHeight,deshacer[index].Canvas.Handle,0,0,SRCCOPY);
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
const
     op : integer = 10;
     xo : integer = 0;
     yo : integer = 0;
begin
     Canvas.Pen.Color := random($FFFFFF);
     Canvas.MoveTo(xo,yo);
     Canvas.LineTo(x,y);

     op := op + 1;

     xo := X;
     yo := Y;

     if op > 10 then begin Guarda; op := 0; end;
end;

end.

es bastante tosco (no cambies el tamaño de la ventana, pues puede dar error, gasta mucha memoria y repinta otras ventanas). Espero que te sirva de idea ;)

pablopessoa 25-11-2008 15:01:10

hola! pedazo de respuesta!! ,uchas gracias!!
el cliente no puede cambiar el tamaño de la ventana, lo tengo fijo, pero si pasa que el tamaño de la ventana se ajusta a la resolucion de pantalla, pero al sacar el tamaño con el metodo ClientWidth; supongo que no afectaria.
Muchas gracias lo voy a probar a ver si me sale bien :P
un saludo!!!

pablopessoa 26-11-2008 13:16:24

hola coso, lamentablemente tengo que confesarte que no logro adaptar tu solucion a mi aplicacion, lo que pasa es que hay algunas diferencias que no se manejar, por ejemplo : yo trabajo sobre un timage no sobre el formulario en si, yo tengo la posibilidad de hacer circulos, cuadrados, lineas , etc por lo que yo tengo que guardar una ves que se termino de dibujar la figura ( OnMouseUp).
Sigo paso a paso la ejecucion y corre el proceso guardar todo bien, pero me parece que el canvas.handle del timage no guarda lo mismo que el canvas.handle del Form, y cuando apreto "deshacer" no me cambia el bitmap.
Si tenes ganas, te dejo el codigo que hice para que veas si la cagada me la mande yo (lo cual es un 200% probable jajaj ).
Pero de todas maneras te agradezco el tiempo y la respuesta que me diste

coso 26-11-2008 14:29:47

Cita:

pero me parece que el canvas.handle del timage no guarda lo mismo que el canvas.handle del Form
cierto, tendrias que usar el handle de TImage.Picture.Bitmap.Canvas. A la que tenga un momento miro el codigo

coso 26-11-2008 14:34:59

Por otra banda, no te iria mejor para esto un TPaintBox? (paleta System)

coso 26-11-2008 14:47:29

hola de nuevo, te dejo el mismo codigo que puse adaptado a Timage : eso si, no estoy seguro que sea del todo correcto, tendrias que probar el saveto y el loadfrom para saber si realmente funciona, pues no se bien bien que relacion hay entre las clases timage, la tpicture y la tbitmap correspondiente.

Código Delphi [-]
procedure TForm1.Guarda;
var
     i : integer;
begin
     label1.Caption := inttostr(index);

     if index = 200 - 1 then  // si hay mas de 200, 'movemos' todos para el principio, perdiendo la primera pantalla guardada
     for i := 1 to 200 - 2 do
     bitblt(deshacer[i-1].Canvas.Handle,0,0,deshacer[i-1].Width,deshacer[i-1].Height,deshacer[i].Canvas.Handle,0,0,SRCCOPY);

     bitblt(deshacer[index].Canvas.Handle,0,0,Width,Height,Image1.Picture.Bitmap.Canvas.Handle,0,0,SRCCOPY);

     if index < 200 - 1 then Inc(index);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
     i : integer;
begin
     doublebuffered := true;
     Color := $220000;
     Label1.Font.Color := clWhite;
     Label1.Caption := '0';
     for i := 0 to 200 - 1 do
     begin
          deshacer[i] := TBitmap.Create;
          deshacer[i].Width  := ClientWidth;
          deshacer[i].Height := ClientHeight;
     end;

     index := 0;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
     i : integer;
begin
     for i := 200-1 downto 0 do
     deshacer[i].Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
     if index = 0 then exit;

     dec(index);

     bitblt(Image1.Canvas.Handle,0,0,ClientWidth,ClientHeight,deshacer[index].Canvas.Handle,0,0,SRCCOPY);
     Refresh;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
const
     op : integer = 10;
     xo : integer = 0;
     yo : integer = 0;
begin
     Image1.Canvas.Pen.Color := random($FFFFFF);
     Image1.Canvas.MoveTo(xo,yo);
     Image1.Canvas.LineTo(x,y);

     op := op + 1;

     xo := X;
     yo := Y;

     if op > 10 then begin Guarda; op := 0; end;
end;


La franja horaria es GMT +2. Ahora son las 10:59:50.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi