Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Grabar y recuperar imagen de Simplegraph (https://www.clubdelphi.com/foros/showthread.php?t=93896)

rrf 26-04-2019 07:30:36

Grabar y recuperar imagen de Simplegraph
 
Hola.

Este mensaje es una petición dirigida principalmente a Neftali, Germán. Aún así, cualquier aportación de otra persona sería bienvenida.

Buscando información sobre el componente Simplegraph, que lo utilizo en un programa que estoy haciendo, encontré este comentario tuyo:

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 115912)
(2) En mi caso lo que hago es olvidarme del formato que trae para guardar en fichero. Al salir recorro todos los objetos creados "dentro" de éste componente y almaceno en Base de Datos sus características (posicion, color, Tipo,...). Al recuperar el diseño hago el paso contrario.

y en este comentario dices que grabas la información de los gráficos de Simplegraph sin basarte en las opciones que ofrece el componente.

Me interesaría conocer la forma en que lo haces, ¿Sería posible que mostraras un pequeño ejemplo acerca de cómo lo haces al grabar y al leer la información del gráfico?.

El enlace en el que aparece este texto citado está en el comentario #5 en: https://www.clubdelphi.com/foros/sho...ht=simplegraph

Uso Delphi 7 en Windows 7.

Muchas gracias de antemano.

Saludos.

Neftali [Germán.Estévez] 30-04-2019 10:38:13

Bueno la idea es sencilla.
SimpleGraph te da opciones de recorrer los objetos y acceder a todas sus propiedades y también te da opciones por código para crear nuevos elementos.

La idea es que al guardar, puedas recorrer los objetos que existen en el grafo y sus propiedades y almacenarlas en una tabla (posición, colores,...). En mi caso almacenaba sólo algunas porque los objetos eran siempre del mismo tiupo y con algunas variaciones.

Para recuperar
, debes realizar el caso contrario. Recorrer la tabla e ir creando objetos dinámicamente según las propiedades almacenadas.

Te adjunto un código sencillo que funciona para que cojas la idea de cómo hacerlo.


Código Delphi [-]

procedure TMainForm.btnGrabarClick(Sender: TObject);
var
  i, oc:Integer;
  o:TGraphObject;
  FIni:TIniFile;
begin

  // Crear un  INI
  FIni := TIniFile.CReate(ChangeFileExt(Application.ExeName, '.ini'));
  try
    oc := SimpleGraph.ObjectsCount;
    // Recorrer los objetos creados en el grafo
    for I := 0 to (SimpleGraph.Objects.Count - 1) do begin
      o := SimpleGraph.Objects.Items[i];
      // Es un nodo
      if (o is TGraphNode) then begin
        // Acceder à la clase
        FIni.WriteString('OBJ'+IntToStr(i), 'Clase', TGraphNode(o).ClassName);
        // posicion del objeto
        FIni.WriteString('OBJ'+IntToStr(i), 'Left', IntToStr(TGraphNode(o).Left));
        FIni.WriteString('OBJ'+IntToStr(i), 'Top', IntToStr(TGraphNode(o).Top));
        FIni.WriteString('OBJ'+IntToStr(i), 'Ancho', IntToStr(TGraphNode(o).Width));
        FIni.WriteString('OBJ'+IntToStr(i), 'Alto', IntToStr(TGraphNode(o).Height));
        // Color de fondo
        FIni.WriteString('OBJ'+IntToStr(i), 'Color', IntToStr(TGraphNode(o).Brush.Color));
        // ...

      end;
    end;
  finally
    FreeAndNil(FIni);
  end;
end;

procedure TMainForm.btnRecuperarClick(Sender: TObject);
var
  i, oc:Integer;
  o:TGraphObject;
  FIni:TIniFile;
  secc:TStringList;
  str:String;
  Rect:TRect;

  // Obtener la clase del Nodo
  function GetNodeClass(AClass:string):TGraphNodeClass;
  begin
    if (AClass = 'TRectangularNode') then
      Result := TRectangularNode;
  end;

begin

  // Commando por defecto
  SimpleGraph.CommandMode := cmInsertNode;
  // Fichero de objetos
  FIni := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
  secc := TStringList.CReate;
  try
    // Leer la lista de nodos a crear
    FIni.ReadSections(secc);
    // Recorerr los nodos a crear
    for i := 0 to (secc.Count - 1) do begin
      // Clase del nodo
      Str := FIni.ReadString('OBJ' + IntToStr(i), 'Clase', 'TRectangularNode');
      // Definir la clase
      SimpleGraph.DefaultNodeClass := GetNodeClass(Str);
      // Posicion del objeto
      Rect.Left := FIni.ReadInteger('OBJ' + IntToStr(i), 'Left', 10);
      Rect.Top := FIni.ReadInteger('OBJ' + IntToStr(i), 'Top', 10);
      Rect.Width := FIni.ReadInteger('OBJ' + IntToStr(i), 'Ancho', 100);
      Rect.Height := FIni.ReadInteger('OBJ' + IntToStr(i), 'Alto', 50);
      // Crear el nodo
      o := SimpleGraph.InsertNode(Rect);
      // color de fondo..
      TGraphNode(o).Brush.Color := FIni.ReadInteger('OBJ' + IntToStr(i), 'Color', 0);
      // Otras propiedades...
    end;
  finally
    FreeAndNil(FIni);
    FreeAndNil(secc);
  end;
end;

rrf 30-04-2019 11:55:24

Hola.

Muchas gracias, Germán.

Aunque no lo he probado aún; este ejemplo es lo que buscaba.

Ahora lo adaptaré para el programa que realizo.

Espero que también le sirva a otras personas.

De nuevo gracias y un saludo.

rrf 30-04-2019 13:37:44

Bueno, ya lo probé con Delphi 7.

Hice algunos cambios y añado algunos comentarios por si le puede ser de utilidad a otras personas:

El código tal como está, debe probarse usando solo rectángulos porque, aunque graba todos los tipos de nodos, al leerlos da error si no son rectángulos.
  • Dado que RECT no tiene las propiedades Width ni Heigth (y tiene Rigth y Button), hice un pequeña adaptación del código en 2 líneas.
  • En el código tal como está, al crear un archivo INI, se sobreescribe el anterior. Si grabamos más nodos que los que había en el archivo INI, no hay problema.
    Aunque, si en un archivo INI creado anteriormente habían datos de 6 nodos y nosotros grabamos una imagen con 2 nodos, los datos de los 4 últimos nodos seguirán existiendo. Por ello, hice un pequeño añadido al código para que, antes de grabar un archivo INI, borre el archivo anterior (si existe).
  • Y hay que acordarse de añadir INIFILES en el USES:
Código Delphi [-]
  uses inifiles, ...

Incluyo aquí el código de Germán, con esos pequeños cambios hechos en Delphi 7:


Código Delphi [-]
procedure TForm1.btnGrabarClick(Sender: TObject);
var
  i, oc:Integer;
  o:TGraphObject;
  FIni:TIniFile;
begin

  // Borra INI anterior, si existe
  if FileExists( ChangeFileExt(Application.ExeName, '.ini') )
    then DeleteFile(  ChangeFileExt(Application.ExeName, '.ini') ) ;
  // Crear un  INI
  FIni := TIniFile.CReate(ChangeFileExt(Application.ExeName, '.ini'));
  try
    oc := SimpleGraph.ObjectsCount;
    // Recorrer los objetos creados en el grafo
    for I := 0 to (SimpleGraph.Objects.Count - 1) do begin
      o := SimpleGraph.Objects.Items[i];
      // Es un nodo
      if (o is TGraphNode) then begin
        // Acceder à la clase
        FIni.WriteString('OBJ'+IntToStr(i), 'Clase', TGraphNode(o).ClassName);
        // posicion del objeto
        FIni.WriteString('OBJ'+IntToStr(i), 'Left', IntToStr(TGraphNode(o).Left));
        FIni.WriteString('OBJ'+IntToStr(i), 'Top', IntToStr(TGraphNode(o).Top));
        FIni.WriteString('OBJ'+IntToStr(i), 'Ancho', IntToStr(TGraphNode(o).Width));
        FIni.WriteString('OBJ'+IntToStr(i), 'Alto', IntToStr(TGraphNode(o).Height));
        // Color de fondo
        FIni.WriteString('OBJ'+IntToStr(i), 'Color', IntToStr(TGraphNode(o).Brush.Color));
        // ...

      end;
    end;
  finally
    FreeAndNil(FIni);
  end;

end;

procedure TForm1.btnRecuperarClick(Sender: TObject);
var
  i, oc:Integer;
  o:TGraphObject;
  FIni:TIniFile;
  secc:TStringList;
  str:String;
  Rect:TRect;

  // Obtener la clase del Nodo
  function GetNodeClass(AClass:string):TGraphNodeClass;
  begin
    if (AClass = 'TRectangularNode') then
      Result := TRectangularNode;
  end;

begin

  // Commando por defecto
  SimpleGraph.CommandMode := cmInsertNode;
  // Fichero de objetos
  FIni := TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini'));
  secc := TStringList.CReate;
  try
    // Leer la lista de nodos a crear
    FIni.ReadSections(secc);
    // Recorerr los nodos a crear
    for i := 0 to (secc.Count -1) do begin
      // Clase del nodo
      Str := FIni.ReadString('OBJ' + IntToStr(i), 'Clase', 'TRectangularNode');
      // Definir la clase
      SimpleGraph.DefaultNodeClass := GetNodeClass(Str);
      // Posicion del objeto
      Rect.Left := FIni.ReadInteger('OBJ' + IntToStr(i), 'Left', 10);
      Rect.Top := FIni.ReadInteger('OBJ' + IntToStr(i), 'Top', 10);
      Rect.Right  := Rect.Left + FIni.ReadInteger('OBJ' + IntToStr(i), 'Ancho', 100);
      Rect.Bottom := Rect.Top + FIni.ReadInteger('OBJ' + IntToStr(i), 'Alto', 50);
      // Crear el nodo
      o := SimpleGraph.InsertNode(Rect);
      // color de fondo..
      TGraphNode(o).Brush.Color := FIni.ReadInteger('OBJ' + IntToStr(i), 'Color', 0);
      // Otras propiedades...
    end;
  finally
    FreeAndNil(FIni);
    FreeAndNil(secc);
  end;

end;

Neftali [Germán.Estévez] 30-04-2019 16:03:50

^\||/^\||/^\||/

De todas formas, esto es sólo un ejemplo, una prueba de concepto.
En mi caso, toda la información la grababa en Base de Datos. Como bien dices, faltan muchas cosas, pero la idea está ahí.

rrf 07-05-2019 19:30:57

Hola.

Finalmente he conseguido leer y grabar las imágenes en la base de datos Firebird utilizando el formato de texto con los valores de cada una de las propiedades que utilizo de nodos y links de las imágenes de Simplegraph.

Gracias Germán por el ejemplo de código que incluiste. Me sirvió de base para mi código.

Saludos.

tiqui_loquito 16-03-2023 22:00:18

Buenas tardes rrf

Me podrías permitir el código que usas para guardar los datos en la BD firebird

Te lo agradecería mucho

Casimiro Notevi 17-03-2023 15:47:35

Sólo necesitas tener una tabla con los campos para almacenar los valores del objeto, left, right, width y height... lo guardas normalmente y lo lees cuando quieras presentarlo.
¿En qué parte necesitas ayuda?

tiqui_loquito 20-03-2023 17:25:20

Buenos días Casimiro

Lo que deseo hacer es lo siguiente:

Desde una aplicación propia llamo para que se ejecute SimpleGraph.exe, en ese aplicativo el usuario puede realizar su gráfica la cual se guarda con una extensión .sgp

Una vez el usuario cierra SimpleGraph.exe puede continuar llenado alguna otra información en el otro aplicativo. Cuando vaya a guardar todo, la idea es que se tome ese archivo creado por SimpleGraph.exe
y lo guarde en un campo de la BD.

Si cancela la consulta, se elimina el archivo se que creo.


Si luego ingresa a la consulta, entonces se descarga el archivo de la BD, para que dese SimpleGraph.exe se pueda acceder y modificar si esta aun en edición, sino para que solo se pueda ver.


Es posible hacer esto?


He intentado que desde SimpleGraph se gaurde como Jpeg o Jpg, pero al tratar de abrirlo por otra aplicación me sale error, pero desde SimpleGraph si lo abre.

No se si me estoy complicando o pido mucho

gracias

Casimiro Notevi 20-03-2023 17:37:34

Lee los mensajes #2 y #4 de este mismo hilo, ahí tienes cómo guardar y recuperar ^\||/

tiqui_loquito 20-03-2023 18:40:21

La idea sería entonces:

Grabar todos los objetos en el .ini, luego, si desde el otro aplicativo lo guardo, tomo ese .ini y lo guardo en un campo de mi BD. Si doy cancelar borro el .ini y no grabo nada en BD

Luego, si quiero ver la imagen descargo el .ini, lo recorro y lo visualizo en SimpleGraph

Ya probé el guardado en el .ini y funciono, debo agregar las otras propiedades y lectura de otros objetos.


Ahora me surge otra pregunta

Si quiero imprimir la imagen creada en SimpleGraph desde otro aplicativo puedo hacer lo siguiente:

Guardar el .ini en un campo y en otro campo guardo el impr pant(aun no se que función de delphi me hace esto). Ahora, al momento de imprimir desde un reporteador desde mi aplicación me coloque
el campo impr pant en una de las secciones de mi historia clinica.

O que me suguieres?


Gracias

Casimiro Notevi 21-03-2023 09:27:12

Creo recordar que SimpleGraph tiene un método "Print", echa un vistazo.

Neftali [Germán.Estévez] 21-03-2023 09:43:00

Cita:

Empezado por tiqui_loquito (Mensaje 550786)
...
Si luego ingresa a la consulta, entonces se descarga el archivo de la BD, para que dese SimpleGraph.exe se pueda acceder y modificar si esta aun en edición, sino para que solo se pueda ver.
Es posible hacer esto?

He intentado que desde SimpleGraph se gaurde como Jpeg o Jpg, pero al tratar de abrirlo por otra aplicación me sale error, pero desde SimpleGraph si lo abre.
...

Yo creo que la idea en sí es buena, pero la ejecución es incorrecta.
Puedes guardar el gráfico en un fichero SGP y recuperarlo en tu programa.
Puedes guardarlo en Base de Datos. Para ello utiliza campos BLOB, binarios o si te da problemas, siempre puedes convertirlo a base64 y guardarlo en un campo de texto.

Lo que no me queda claro es que intentes guardarlo como JPEG/JPG. Un gráfico de simplegraph está compuesto por múltiples obetos que almacenan sus propiedades, junto con las propiedades del propio gráfco. Puedes expotarlo como JPEG/JPG, pero si lo haces así y lo guardas así, cuando lo recuperes simplemente tendrás una imagen. No podrás modificar nada más de ese gráfico (habrás perdido toda la información).

tiqui_loquito 21-03-2023 18:30:36

Gracias por la orientación Neftali y Casimiro

Por si alguien puede interesarle, realice lo siguiente:

Es un código para probar lo que necesito

Código Delphi [-]
procedure Form1.btn1Click(Sender: TObject);
var
  hInst: Cardinal;
  Paramt,path: string;

  BlobField: TBlobField;
begin
  Paramt := 'HC';
  path := ExtractFilePath(Application.ExeName) + 'Ecograma.exe';

  // Verifica si el archivo existe en la ubicación especificada
  if not FileExists(path) then
  begin
    ShowMessage('El archivo "Ecograma.exe" no se encuentra en la ubicación especificada.');
    Exit;
  end;

  //Aquí envío un parametro para poder ejecutar Ecograma.exe desde mí aplciativo
  //y no cuando le den clic directamenbet a Ecograma.exe
  hInst :=ShellExecute(0, 'open', PChar(path), PChar(Paramt), nil, SW_SHOWNORMAL);


  //Por si no se pudo abrir Ecograma.exe se informa al usuario
  if hInst <= 32 then
  begin
    case hInst of
      ERROR_FILE_NOT_FOUND:
        ShowMessage('El archivo no se encontró.');
      ERROR_PATH_NOT_FOUND:
        ShowMessage('La ruta especificada no se encontró.');
      ERROR_BAD_FORMAT:
        ShowMessage('El formato del archivo no es válido.');
      else
        ShowMessage('Se produjo un error al ejecutar el archivo.');
    end;
  end;

  //Se creo el campo ECOGRAMA en la BD
 IBQuery1.Close;
 IBQuery1.ParamByName('ECOGRAMA').DataType := ftGraphic;
 IBQuery1.ParamByName('ECOGRAMA').LoadFromFile('D:\mychart.sgp', ftBlob);
 IBQuery1.Open;

 IBQuery1.Transaction.CommitRetaining;

 IBQuery2.Close;
 IBQuery2.Open;

 BlobField := TBlobField(IBQuery2.FieldByName('ECOGRAMA'));
 SaveBlobToFile(BlobField, 'C:\mychart.sgp');

end;


//Procedimeinto para guardar el archivo que se descarga de BD
procedure form1.SaveBlobToFile(Blob: TBlobField;
  const FileName: string);
var
  Stream: TFileStream;
begin
  Stream := TFileStream.Create(FileName, fmCreate);
  try
    Blob.SaveToStream(Stream);
  finally
    Stream.Free;
  end;
end;


Con ese trozo de código hago lo siguiente:

Llamo a Ecograma.exe desde mi aplicativo y no permito que se ejecute si le doy doble click a Ecograma.exe, ya que este va a estar en la misma carpeta de mi aplicativo, además si quieren llevarlo
a otro pc y abrirlo no lo podrán hacer.

Código Delphi [-]
  Paramt := 'HC';  //en simplegra

  hInst :=ShellExecute(0, 'open', PChar(path), PChar(Paramt), nil, SW_SHOWNORMAL);

Una vez se abra Ecograma.exe, se guarde el diagrama (aquí debo modificar para que guarde el diagrama con ciertas condiciones), se guarda el fichero en BD(debo modificarlo para que lo guarde cuando le de guardar desde mi aplicativo, ingresando a la ubicación donde se guarda el diagrama ).

Código Delphi [-]
 IBQuery1.Close;
 IBQuery1.ParamByName('ECOGRAMA').DataType := ftGraphic;
 IBQuery1.ParamByName('ECOGRAMA').LoadFromFile('D:\mychart.sgp', ftBlob);
 IBQuery1.Open;

 IBQuery1.Transaction.CommitRetaining;


Finalmente se consulta el campo donde se guardo el fichero y se descarga en C: (aquí también debo hacer varios ajustes).

Código Delphi [-]
 IBQuery2.Close;
 IBQuery2.Open;

 BlobField := TBlobField(IBQuery2.FieldByName('ECOGRAMA'));
 SaveBlobToFile(BlobField, 'C:\mychart.sgp');



//Procedimeinto para guardar el archivo que se descarga de BD
procedure form1.SaveBlobToFile(Blob: TBlobField;
  const FileName: string);
var
  Stream: TFileStream;
begin
  Stream := TFileStream.Create(FileName, fmCreate);
  try
    Blob.SaveToStream(Stream);
  finally
    Stream.Free;
  end;
end;

Probé abrir el fichero descargado y me abre normal y lo puedo editar.


Aun hay trabajo por hacer, pero por ahora va todo viento en popa

Gracias por su colaboración

rrf 22-03-2023 10:26:07

Cita:

Empezado por tiqui_loquito (Mensaje 550778)
Buenas tardes rrf

Me podrías permitir el código que usas para guardar los datos en la BD firebird

Hola tiqui_loquito y a quien lo lea.

Lamento el no haber atendido a tu petición.

He estado enfermo y no he tocado mi correo electrónico en los últimos días.

Me alegra que Germán y Casimiro te hayan ayudado y lo hayas resuelto.

Además, hace mucho tiempo que no trabajo con Simplegraph y estoy desentrenado.

Saludos.


La franja horaria es GMT +2. Ahora son las 10:28:42.

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