Newsgroup: it.comp.lang.delphi
Titolo: firemonkey e disegno di linee

sto cercando di far disegnare delle linee su paintbox ad un'applicazione per android.
a parte il fatto che non ho trovato l'equivalente di lineto ma solo canvas.drawline... (e vabbè mi posso accontentare) ma il problema prinicipale è che non riesco a disegnare nulla.
in pratica faccio
 
pb.canvas.beginscene
pb.canvas.drawline()
pb.canvas.endsene
 
se compilo l'applicazione per Windows ottengo il disegno delle linee... ma la cosa strana è che le linee vengono disegnate sul canvas della form e non su quello della pb.
se invece compilo per android ed eseguo sul mio dispositivo.... non ottengo nessun disegno
come mai???
esiste inoltre un esempio semplice per vedere come poter disegnare delle semplici lineee su android????

 sto cercando di far disegnare delle linee su paintbox ad un'applicazione per android.
 
Ho provato a riprodurre il tuo problema, ma non ci sono riuscito.
 
Ho messo un controllo *TPaintBox* sul Form principale di un'applicazione FireMonkey e intercettato l'evento /OnPaint/ così:
 
procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
  Canvas.Fill.Color := TAlphaColorRec.Azure;
  Canvas.FillRect(PaintBox1.ClipRect, 8, 8,
    [TCorner.TopLeft, TCorner.TopRight, TCorner.BottomLeft, TCorner.BottomRight],
    1, TCornerType.Round);
end;
 
Lanciando l'applicazione (in Windows, al momento), il riquadro mi viene disegnato nel modo corretto dentro l'area della PaintBox.
 
Puoi postare un pezzo di codice più completo?
 
Ciao,
  Marco.
 
-- 
MARCO BREVEGLIERI (Software and Web Developer)
 #Home: 
http://www.marco.breveglieri.name
 
 #Blog: 
http://www.compilaquindiva.com
 
 #DelphiPodcast: 
http://www.delphipodcast.com
 

ecco il  codice. è un evento associato al timer che crea dei valori random, li memorizza in una stringgrid e poi li usa per disegnare delle linee sul canvas del pb (paintbox)
 
procedure TAcc.Timer1Timer(Sender: TObject);
var
  x,y,ax,ay,xp,yp : real;
  p1, p2: TPointF;
begin
   stringgrid1.RowCount:=stringgrid1.RowCount+1;
   ax:=random(20);
   ay:=random(20);
   x:=1/2*ax*t*t*20;
   y:=1/2*ay*t*t*20;
   stringgrid1.cells[0,stringgrid1.RowCount-1]:=format('%6.3f',[aX]);
   stringgrid1.cells[1,stringgrid1.RowCount-1]:=format('%6.3f',[aY]);
   stringgrid1.cells[2,stringgrid1.RowCount-1]:=format('%6.3f',[X]);
   stringgrid1.cells[3,stringgrid1.RowCount-1]:=format('%6.3f',[Y]);
  if stringgrid1.cells[2,stringgrid1.RowCount-2]<>'' then
    xp:=strtofloat(stringgrid1.cells[2,stringgrid1.RowCount-2])
  else
    xp:=0;
  if stringgrid1.cells[3,stringgrid1.RowCount-2]<>'' then
    yp:=strtofloat(stringgrid1.cells[3,stringgrid1.RowCount-2])
  else
    yp:=0;
  p1 := TPointF.Create(xp,yp);
  p2 := TPointF.Create(x, y);
  pb.Canvas.BeginScene;
  pb.Canvas.DrawLine(p1,p2,1);
  pb.Canvas.EndScene;
end;

 ecco il  codice. è un evento associato al timer che crea dei valori random, li memorizza in una stringgrid e poi li usa per disegnare delle linee sul canvas del pb (paintbox)
 
Il codice di disegno del PaintBox devi inserirlo nell'evento "OnPaint", poiché il disegno deve essere riprodotto ogni volta che i dati cambiano e ogni volta che la finestra viene nascosta e mostrata di nuovo.
 
Nel componente Timer, al massimo, metti una chiamata al metodo "Invalidate" del PaintBox per suggerire che l'aspetto di tale controllo deve essere comunque ridisegnato poiché sono cambiati i dati su cui si basa la rappresentazione.


sarò io che sono negato ma adesso non riesco a disegnare nemmeno una semplice linea
con il mottone invalido il paintbox e quindi dovrebbe richiamare l'evento onpaint che dovrebbe disegnare la linea.... ma non succede niente
 
ecco il codice completo
 
 
unit Unit2;
 
interface
 
uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls, FMX.Objects;
 
type
  TForm2 = class(TForm)
    PaintBox1: TPaintBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.fmx}
{$R *.LgXhdpiTb.fmx ANDROID}
{$R *.LgXhdpiPh.fmx ANDROID}
 
procedure TForm2.Button1Click(Sender: TObject);
var ret : Trectf;
begin
  ret:=ret.create(0,0,paintbox1.Width,paintbox1.Height);
  paintbox1.InvalidateRect(ret);
end;
 
procedure TForm2.FormCreate(Sender: TObject);
begin
  randomize;
end;
 
procedure TForm2.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var x1,y1,x2,y2: integer;
   uno,due : Tpointf;
begin
  x1:=random(100);
  y1:=random(200);
  x2:=random(100);
  y2:=random(200);
  uno:=uno.Create(x1,y1);
  due:=due.Create(x2,y2);
  canvas.BeginScene();
  canvas.DrawLine(uno,due,1);
  canvas.EndScene;
end;
 
end.

 con il mottone invalido il paintbox e quindi dovrebbe richiamare l'evento onpaint che dovrebbe disegnare la linea.... ma non succede niente
 
Prova a chiamare PaintBox.Repaint() al posto di PaintBox.InvalidateRect().
 
Controlla anche con quali valori viene disegnata la linea, trattandosi di dati generati casuali: se si tratta di punti molto vicini, magari neanche li vedi.
 
Hai provato a dare un'occhiata anche agli esempi/demo nella documentazione?


niente da fare.. ho ulteriormente semplificato il codice.... se compilo per windows ottengo il disegn odelle linee ma NON sul paintBox (che è spostato sulla destra della form) ma sul canvas.
se compilo per android non si disegna più niente.
non è un problema di punti disegnati troppo vicini o troppo lontani perchè ho settato il random in modo da avere l'intervallo che mi serve per fare la prova.
tra la documentazione non ho trovato un esempio per disegnare su un canvas.. ricordo che quando ho creato il progetto ho selezionato multi device application e blank application
ecco il codice completo
 
unit Unit2;
 
interface
 
uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls, FMX.Objects;
 
type
  TForm2 = class(TForm)
    PaintBox1: TPaintBox;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.fmx}
{$R *.LgXhdpiTb.fmx ANDROID}
{$R *.LgXhdpiPh.fmx ANDROID}
 
 
 
procedure TForm2.Button1Click(Sender: TObject);
var x1,y1,x2,y2: integer;
   uno,due : Tpointf;
begin
  x1:=random(200);
  y1:=random(400);
  x2:=random(200);
  y2:=random(400);
  form2.Caption:=inttostr(x1)+' '+inttostr(y1)+' '+inttostr(x2)+' '+inttostr(y2);
  uno:=uno.Create(x1,y1);
  due:=due.Create(x2,y2);
  paintbox1.canvas.BeginScene();
  paintbox1.canvas.DrawLine(uno,due,1);
  paintbox1.canvas.EndScene;
end;
 
procedure TForm2.FormCreate(Sender: TObject);
begin
  randomize;
end;
 
end.
 
P.S. naturalmente se compilo come vcl utilizzando i classici canvas.lineto ecc... non ho nessun problema

 niente da fare.. 
 
In una delle mie prime risposte ho fatto uso dell'evento /OnPaint/... perché tu non lo utilizzi?
 
Puoi procedere come credi, ma penso sia inutile chiedere suggerimenti e proseguire comunque sulla propria strada senza nemmeno provare le alternative che vengono proposte. :|



innanzi tutto grazie per i preziosi consigli... poi.. non è che non volevo usare onpaint... semplicemente pensavo di semplificare il più possibile il codice ma evidentemente sbagliavo strada... quindi ho corretto il tutto.
Il problema è ora che disegno si le linee, ma quelle disegnate prima scompaiono. Quello che voglio fare io è scrivere le coordinate di alcune linee su una stringgrid e poi "tradurre" queste coordinate in un disegno.
quello che ottengo con il codice che posto di seguito è invece il disegno solo dell'ultima linea.
a me serve invece che ad ogni evento ontimer si aggiunga al disegno una nuova linea.
grazie
 
unit Unit2;
 
interface
 
uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Rtti,
  FMX.Controls.Presentation, FMX.StdCtrls, FMX.Grid, FMX.Layouts, FMX.Objects;
 
type
  TForm2 = class(TForm)
    StringGrid1: TStringGrid;
    StringColumn1: TStringColumn;
    StringColumn2: TStringColumn;
    StringColumn3: TStringColumn;
    StringColumn4: TStringColumn;
    Timer1: TTimer;
    Button1: TButton;
    PaintBox1: TPaintBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.fmx}
{$R *.LgXhdpiTb.fmx ANDROID}
{$R *.iPhone4in.fmx IOS}
 
 
procedure TForm2.Button1Click(Sender: TObject);
begin
  form2.StringGrid1.Cells[0,0]:='0';
  form2.StringGrid1.Cells[1,0]:='0';
  Timer1.Enabled:=true;
end;
 
procedure TForm2.FormCreate(Sender: TObject);
begin
  randomize;
end;
 
procedure TForm2.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var
  p1, p2: TPointF;
  xp,yp:real;
begin
 if stringgrid1.rowcount>1 then
 begin
    xp:=strtofloat(stringgrid1.cells[0,stringgrid1.RowCount-2]);
    yp:=strtofloat(stringgrid1.cells[1,stringgrid1.RowCount-2]);
    p1 := TPointF.Create(xp,yp);
    p2 := TPointF.Create(strtofloat(stringgrid1.cells[0,stringgrid1.RowCount-1]), strtofloat(stringgrid1.cells[1,stringgrid1.RowCount-1]));
    Canvas.DrawLine(p1,p2,1);
 end;
end;
 
procedure TForm2.Timer1Timer(Sender: TObject);
var x,y : real;
begin
   x:=random(200);
   y:=random(200);
   StringGrid1.RowCount:=StringGrid1.RowCount+1;
   StringGrid1.Cells[0,StringGrid1.RowCount-1]:=format('%6.3f',[x]);
   StringGrid1.Cells[1,StringGrid1.RowCount-1]:=format('%6.3f',[y]);
   paintbox1.Repaint;
end;
 
end.

 grazie
 
Semplificare il codice è senz'altro una buona cosa, però bisogna rispettare i dettami dell'architettura che si sta utilizzando per sviluppare la soluzione. :)
 
Se non usi l'evento "OnPaint", di fatto stai apportando delle modifiche grafiche del tutto transienti, non persistenti, quindi la prima volta che il Form viene nascosto e ripristinato, perderai il disegno che hai fatto, quindi è d'obbligo mettere in quell'evento le istruzioni che servono a ricostruire il disegno, come se tu dovessi ogni volta disegnarlo da capo.
 
Venendo al tuo esempio, se la StringGrid contiene i dati delle linee da tracciare, e se ogni riga che aggiungi ne rappresenta una, mi aspetterei di vedere almeno un ciclo all'interno dell'evento "OnPaint", o comunque una iterazione sulle righe della griglia per andare a disegnare una per una tutte le linee che sono censite.
 
Riassumendo, l'evento "OnPaint" è l'unico responsabile del disegno e deve essere l'unico punto in cui tracci le linee, intendendo *tutte* le linee.
Per aggiungere una nuova linea, dopo aver censito i suoi dati nella StringGrid, chiami PaintBox.Repaint() - come stai già facendo - per dire al controllo che si deve ridisegnare, e lui userà le istruzioni presenti nella griglia per disegnare le linee, non solo l'ultima ma tutte quante, partendo dalla prima.
 
Prova a codificare questa logica, poi in caso di problemi torniamo sull'argomento.
 
Ciao!


allora ho seguito tutti i tuoi suggerimenti
ecco il codice
----------------unit Unit2;
 
interface
 
uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, System.Rtti,
  FMX.Controls.Presentation, FMX.StdCtrls, FMX.Grid, FMX.Layouts, FMX.Objects;
 
type
  TForm2 = class(TForm)
    StringGrid1: TStringGrid;
    StringColumn1: TStringColumn;
    StringColumn2: TStringColumn;
    StringColumn3: TStringColumn;
    StringColumn4: TStringColumn;
    Timer1: TTimer;
    Button1: TButton;
    PaintBox1: TPaintBox;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form2: TForm2;
 
implementation
 
{$R *.fmx}
{$R *.LgXhdpiTb.fmx ANDROID}
{$R *.iPhone4in.fmx IOS}
 
 
procedure TForm2.Button1Click(Sender: TObject);
begin
  form2.StringGrid1.Cells[0,0]:='0';
  form2.StringGrid1.Cells[1,0]:='0';
  Timer1.Enabled:=true;
end;
 
procedure TForm2.Button2Click(Sender: TObject);
begin
   Timer1.Enabled:=false;
end;
 
procedure TForm2.FormCreate(Sender: TObject);
begin
  randomize;
end;
 
procedure TForm2.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
var
  p1, p2: TPointF;
  xp,yp:real;
  i : integer;
begin
 for i:= 2 to stringgrid1.rowcount do
 begin
    xp:=strtofloat(stringgrid1.cells[0,i-2]);
    yp:=strtofloat(stringgrid1.cells[1,i-2]);
    p1 := TPointF.Create(xp,yp);
    p2 := TPointF.Create(strtofloat(stringgrid1.cells[0,i-1]), strtofloat(stringgrid1.cells[1,i-1]));
    Canvas.DrawLine(p1,p2,1);
 end;
end;
 
procedure TForm2.Timer1Timer(Sender: TObject);
var x,y : real;
begin
   x:=random(200);
   y:=random(200);
   StringGrid1.RowCount:=StringGrid1.RowCount+1;
   StringGrid1.Cells[0,StringGrid1.RowCount-1]:=format('%6.3f',[x]);
   StringGrid1.Cells[1,StringGrid1.RowCount-1]:=format('%6.3f',[y]);
   paintbox1.Repaint;
end;
 
end.
--------------
il problema è che se compilo per windows non ho nessun problema
se però compilo per android le linee proprio non ne vogliono sapere di essere disegnate
ma perchè??????????????