Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   RichEdit para comentar las ventajas de un ‘producto’ (https://www.clubdelphi.com/foros/showthread.php?t=68969)

jusaso 18-07-2010 16:34:40

RichEdit para comentar las ventajas de un ‘producto’
 
Tengo un fichero RTF formateado con información de una serie de productos..
(Antes utilizaba un fichero TXT, pero pienso que con RTF puede quedar más 'bonito').
Y deseo algo muy sencillo….
Leer el fichero RTF, seleccionar la información referente a uno de los productos y mostrar esta información en el RichEdit.
Con ficheros de texto es muy fácil hacerlo....
Lo cargo en un array de texto. Localizo las líneas referentes a uno de los productos y las muestro en un MEMO o un LIST.
Pero si lo hago con RichEdit, pierde el formato y me muestra los caracteres ocultos del texto.
He consultado en Google… sin resultado.
Una ayuda…
Gracias.

ecfisa 19-07-2010 03:53:52

Hola jusas

El problema de la pérdida del formato lo tenés cuando cargas en un arreglo de texto,
lo que luego se mostrará en el RichEdit.

Yo cargaría directamente el archivo .RTF al RichEdit y luego posisionaría en el texto buscado.

Carga:
Código:

procedure CargarRTF;
begin
  RichEdit1.Lines.LoadFromFile('Archivo.RTF');
end;

Busqueda:
Código:

procedure BuscarEnRTF(Producto: string);
  with RichEdit1 do
  begin
    SetFocus;
    SelStart:= Pos(Producto, RichEdit1.Text)-1;
    SelLength:= Length(Producto);
  end;
end;

Este código sólo te situa en el nombre del producto y lo deja seleccionado. Ahora bién, si sólo
querés mostrar la parte correspondiente al producto y no todo, tendríamos que normalizar de algún
modo la ayuda.
Es decir, señalizar donde comienza y términa la información de cada producto para luego eliminar las
líneas anteriores y posteriores a la información que queres mostrar.


Saludos.

jusaso 19-07-2010 11:15:25

Gracias por la respuesta...

Estoy de acuerdo...
Primero el load para cargar el texto que contiene la descripción de todos los productos.
Un texto que préviamente ha sido escrito en Word para que quede 'bonito'.
Cada descripción del producto quedá separada por una línea en la que aparece el número que tiene asignado cada producto.
De esta manera para buscar el producto 1234...

Código Delphi [-]
nIni:=0;nFin:=0;    //numero lineas ini y fin
for i:=1 to totalLin do
   begin
   if ansipos('1234',textoArray[i])>0 then nini:=i;
   if ansipos('1235',textoArray[i])>0 then begin nFin:=i;break;end;
   end;

Continuamos...
Localizado el texto, se selecciona con...

SelStart:= Pos(Producto, RichEdit1.Text)-1;
SelLength:= Length(Producto);

Donde... selStart sería el inicio del texto pero ¿no falta indicar el final para calcular la longitud?

Y finalmente, una vez seleccionado, habría que borrar el richEdit (richEdit1.clear) y mostrar solo la parte del texto correspondiente.

Gracias anticipadas...

Caro 19-07-2010 16:46:41

Hola jusaso, como te dice ecfisa en su codigo de ejemplo solo esta seleccionando el producto por lo que el final es el Length del producto.

No deberías borrar el RichEdit sino trabajar sobre el contenido del mismo RichEdit, yo seleccionaría las líneas que estan antes y despues del texto que se quiere mostrar y eliminarlas.

Código Delphi [-]
procedure BorrarSeleccion;
var
 IniSelect, FinSelect : Integer;
begin
 //Inicio de la selección
 IniSelect := RichEdit1.Perform(EM_LINEFROMCHAR,RichEdit1.SelStart,0);
 //Fin de la selección
 FinSelect := RichEdit1.Perform(EM_LINEFROMCHAR,RichEdit1.SelStart + RichEdit1.SelLength,0);
 
 for i:=IniSelect to FinSelect do
  RichEdit1.Lines.Delete(IniSelect);
end;
...............................................................
...............................................................
...............................................................
 nIni := AnsiPos('1234', Richedit1.Text);
 nFin := AnsiPos('1235', Richedit1.Text);
 
 Richedit1.SelStart := nFin;
 Richedit1.SelLength := Length(Richedit1.Text);
 BorrarSeleccion;
 
 Richedit1.SelStart := 0;
 Richedit1.SelLength := nIni;
 BorrarSeleccion;

el código quedaría mas o menos así, talvez tengas que ajustar algo.

Saluditos

jusaso 19-07-2010 18:52:26

Gracias por sus respuestas.

El código quedaría pues...

Código Delphi [-]
procedure TForm1.Button6Click(Sender: TObject);
var
  nfin,nIni:integer;
begin
 richedit1.Lines.LoadFromFile('GradosBIEN.rtf');
 nIni:=0;
 nFin:=0;
 nIni := AnsiPos('12345', Richedit1.Text);
 nFin := AnsiPos('12346', Richedit1.Text);

 RichEdit1.SetFocus;
 Richedit1.SelStart := nFin;
 Richedit1.SelLength := Length(Richedit1.Text);
 BorrarSeleccion;

 Richedit1.SelStart := 0;
 Richedit1.SelLength := nIni;
 BorrarSeleccion;
end;

procedure TForm1.BorrarSeleccion;
var
 IniSelect, FinSelect,i : Integer;
begin
 //Inicio de la selección
 IniSelect := RichEdit1.Perform(EM_LINEFROMCHAR,RichEdit1.SelStart,0);
 //Fin de la selección
 FinSelect := RichEdit1.Perform(EM_LINEFROMCHAR,RichEdit1.SelStart + RichEdit1.SelLength,0);

 for i:=IniSelect to FinSelect do
  RichEdit1.Lines.Delete(IniSelect);
end;
Y ciertamente funciona.
Pero tiene un problema importante que habría que solucionar.
El documento Word, en su versión RTF, tiene unas cien páginas.
Y tarda varios segundos, bastantes, en cargarse sobre el RichEdit.

El problema se complica cuando esta operación debe repetirse para cada 'producto'.

Por ello, habría que guardar en memoria la totalidad del texto y mostrar en el RichEdit sólo las líneas referentes al artículo seleccionado.

He visto algunos ejemplos que utilizan TMemoryStream o TStringStream pero nunca he tenido que utilizarlos....

Si se os ocurre algo... os lo agradecería.

Un cordial saludo

ecfisa 19-07-2010 20:44:14

Hola jusaso.

El uso de TMemoryStream no va a acelerar significativamente la carga desde el disco,
que es, a mi criterio el punto álgido del problema.

Tal vez la solución pase por dividir el archivo de ayuda. Podés utilizar el criterio que prefieras;
código, nombre,... buscando una distribución lo más simétrica posible.

En mis pruebas con un Core2Duo y 4 Gb de Ram, con las 100 páginas, obtuve 8 s con la carga directa
del RichEdit, 7s y monedas con MemoryStream. Sin embargo dividiendo el archivo en cinco partes de 20
páginas cada uno la carga no llegó a 1s y la demóra fué casi imperceptible.

Lo que sí, te puede adicionar algunas dificultades al momento de ingresar un nuevo producto y en la
preselección de la ayuda, pero creo que es una solución viable.

Saludos.

rrf 19-07-2010 23:40:55

Aunque no era para lo mismo exactamente, ante una situación similar, lo que hice fue utilizar 2 richedit.

El primer RichEdit cargaba y mantenía en memoria el contenido del archivo (siendo invisible para el usuario) y el 2º richedit era el que utilizaba para presentar la información seleccionada.

Así se reducía el tiempo de carga de la información porque, después de leer por primera vez el archivo RTF, ya se podía acceder a él directamente, al tenerlo en memoria.

Salu2.

Ramón.

jusaso 20-07-2010 13:18:20

Hola ecfisa

Estaba equivocado...
El tiempo de espera no se produce al cargar el texto en RichEdit.
La carga la hace muy rápida.
El problema es debido al tener que borrar una a una todas las líneas sobrantes del RichEdit.....
Tarda mucho en hacerlo.


Código Delphi [-]
for i:=IniSelect to FinSelect do
RichEdit1.Lines.Delete(IniSelect);





Las he anulado y es muy rápido.

La solución cosistiría en borrar todo un bloque de líneas, pero no he visto la forma....

Por otro lado, utilizar dos RichEdit...
Todos los ejemplos que he visto en Google se limitan a copiar el TEXT completo del uno al del otro, sin realizar una selección de líneas, que es lo que buscamos.

Gracias por vuestras ideas....

rrf 20-07-2010 16:58:58

Hola.

Bueno, he revisado el código que hice hace meses y, finalmente, lo hice todo con 1 solo RichEdit, aunque me quedó la idea de que había usado 2.

Bueno, te incluyo el código de la función que escribí. Puede tener algún pequeño error puesto que lo he adaptado para ponerlo aquí, pues el código original no se ajusta del todo a lo que se comenta en este hilo.

Código Delphi [-]
procedure TForm1.Selecciona_seccion_texto ( pp: integer );
var
  num_lin, cc : integer ;
  borra_lin : boolean ;
begin
      // Selecciona_seccion_texto
      //---------------------------

    // Eliminar el texto que no esté entre 2 marcas   (EJ: ENTRE  ,,,---2  y  ,,,---3 )
  outRichEdit1.Visible := false ;
  outRichEdit1.Lines.LoadFromFile( 'Archivo_Ayuda.rtf' );  // adaptarlo al nombre de tu archivo RTF

       // Borra hasta que aparece la marca de inicio del apartado de texto que interesa
  while trim ( outRichEdit1.Lines [ 0 ] ) <> ',,,---' + IntToStr ( pp )
    do outRichEdit1.Lines.Delete( 0 );

  outRichEdit1.Lines.Delete( 0 );   // Elimina la línea del separador

       // Borra desde la marca de inicio del siguiente apartado del texto hasta el final del texto
  borra_lin := false ;
  for cc := 0 to outRichEdit1.Lines.Count -1
   do
    begin

      if trim ( outRichEdit1.Lines [ cc ] ) = ',,,---' + IntToStr ( pp +1 )
        then
          begin
            borra_lin := true ;
            num_lin := cc ;
          end ;

      if borra_lin
        then outRichEdit1.Lines.Delete( num_lin ) ;

    end ;

  outRichEdit1.Visible := true ;
  outRichEdit1.Lines.Insert( 0, '' );  // Esto hace que el cursor
  outRichEdit1.Lines.Delete( 0 );      // quede al inicio del texto
  outRichEdit1.SetFocus ;

end ;

El texto está dividido en partes. Los separadores son ",,,---1", ",,,---2", ",,,---3", ..., ",,,---10", ",,,---11", etc.

El contenido del RichEdit sería algo así:
-----------------------------------------------------
,,,---1
Este es el texto del apartado 1 del texto.
Este es el texto del apartado 1 del texto.
Este es el texto del apartado 1 del texto.
,,,---2
Este es el texto del apartado 2 del texto.
Este es el texto del apartado 2 del texto.
Este es el texto del apartado 2 del texto.
,,,---3
Este es el texto del apartado 3 del texto.
Este es el texto del apartado 3 del texto.
Este es el texto del apartado 3 del texto.
Este es el texto del apartado 3 del texto.
,,,---4
-----------------------------------------------------

El nombre del RichEdit es outRichEdit1.

El parámetro "pp" indica el número del apartado del texto que queremos ver.

A mí me funcionó bastante bien y espero que te sirva.

Saludos.

Ramón.

PD.: Creo que el richedit tiene que tener la propiedad WordWrap a false para que funcione bien. Puede que no sea así (lo digo sin haberlo probado).

jusaso 20-07-2010 19:14:58

Saludos compañeros

He vuelto a mi planteamiento inicial y parece que ya funciona. Esperemos...

La idea era la siguiente:
Leer el fichero RTF, seleccionar la información referente a uno de los productos y mostrar esta información en el RichEdit.

Pero se perdía el formato del texto.
¿Porqué?
Porque las líneas extraidas necesitan de la información del encabezado del fichero RTF. Lo puedes comprobar cargando el fichero en el IDE de Delphi.

Por lo tanto la tarea consiste en localizar estas líneas y pasarlas al RicheEdit junto con las seleccionadas.

¿Cuales son estas líneas?
Me ha parecido comprobar que el tamaño de las mismaas varía de un RTF a otro.
Así que he utilizado el siguiente truco...
Al principio del fichero RTF pongo una señal: INIFILE.
Las líneas que estén por encima (unas 40) serán la cabecera.

Y las líneas comprendidas entre cada número de producto serán la descripción del mismo.

¡IMPORTANTE!
Conviene dejar una línea en blanco por encima y debajo de cada señal, al redactar el texto en Word. Simplemente por precaución....

Bueno os pongo el código...

Código Delphi [-]
 
procedure TForm1.Button1Click(Sender: TObject);
var
  nfin,nIni: integer;
  nIniFile,i : integer;
  FichRTF,mislineas : TStringList;
begin
  FichRTF:=TStringList.Create;
  mislineas:=TStringList.Create;
  FichRTF.LoadFromFile('TEXT.RTF');
 
  nIniFile:=0;  //fin de la cabecera
  nIni:=0;       //línea comienzo selección
  nFin:=0;      // fin selección
      //localiza las 3 líneas
  for i:=0 to FichRTF.Count-1-1 do
    begin
    if AnsiPos('INIFILE', FichRTF[i])>0 then nIniFile := i;
    if AnsiPos('12345', FichRTF[i])>0 then nIni := i;
    if AnsiPos('12346', FichRTF[i])>0 then begin nFin := i;break;end;
    end;
 
  if (nIniFile=0)or(nIni=0)or(nFin=0) then showmessage ('Problema');
 
       //seleccionamos las líneas de la cabecera
  for i:=0 to nIniFile-1 do
       mislineas.add(FichRTF.Strings[i]);

       //Y la parte del texto comprendido entre 12345 y 12346
  for i:=nIni+1 to nFin-1 do
       mislineas.add(FichRTF.Strings[i]);
 
       //Finalmente pasamos las líneas de texto al RichEdit
  RichEdit1.Text:=mislineas.Text;

end;


Esto es todo.
Seguramente se me escapa algo...

En respuesta al compañero rrf... Pienso que el delete, una a una, de las líneas tiene que ser algo lento si el texto es abundante...

Gracias...


La franja horaria es GMT +2. Ahora son las 16:09:32.

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