PDA

Ver la Versión Completa : Tab en RichEdit


Sonic
22-10-2004, 13:31:19
Buenas a todos!

¿Alguien sabe cómo puedo acceder o cambiar el numero de espacios que equivalen a una pulsación de la tecla Tab?

Estoy haciendo un Editor y me gustaría hacer que se pudiese elegir el tamaño del Tab, pero no encuentro la forma.

Gracias de antemano

barman
22-10-2004, 13:50:52
Si estas trajando con el RichtEdit

RichEdit1->Paragraph->Alignment
RichEdit1->Paragraph->Numbering

Si con TMemo, tendras que capturar el evento OnKeyDown, y comprobar
el Key = VK_TAB

Sonic
25-10-2004, 10:22:28
Si estas trajando con el RichtEdit

RichEdit1->Paragraph->Alignment
RichEdit1->Paragraph->Numbering

Si con TMemo, tendras que capturar el evento OnKeyDown, y comprobar
el Key = VK_TAB
Gracias barman, pero no entiendo como pueden ayudarme esas propiedades. Perdona que se me pasara, estoy trabajando con un TRichEdit y lo que pretendo es analizar las cadenas de texto para que cuando encuentre un \t pueda sustituirlo por el numero de espacios equivalentes, por eso necesito conocer qué propiedad me da dicho valor.

He visto que muchos editores sencillos te dan la opción de elegir el tamaño de tu tabulador, pero no consigo encontrar nada útil al respecto.

He mirado las propiedades que me has dado, pero ninguna me sirve para conocer el Tamaño del tab (o no sé usarlas que también puede ser). De todos modos te agradezco tu respuesta y me gustaría que si después de esta aclaración sigues pensando que mi solución está en las propiedades que me has dado, por favor me las aclares.

Muchas Gracias. Espero respuesta

barman
25-10-2004, 12:04:39
A ver, el TRichtEdit es mas largo de lo que parece, basicamente tiene toda la funcionalidad de un editor de texto complejo, lo primero mirate el ejemplo que trae el compilador

.......Borlan5\CBuilder5\Examples\Apps\RichEdit\

Y seguro que resolvera todas tus dudas.

Por otra parte lo que me refiero es a esto.


void __fastcall TForm1::RichEdit1KeyPress(TObject *Sender, char &Key)
{
int StartPos = RichEdit1->SelStart + RichEdit1->SelLength;
if (Key == VK_TAB)
{
ShowMessage(StartPos);
Key = 0;
}

}

Sonic
25-10-2004, 13:04:21
Buenas barman:

En los ejemplos no encuentro nada que me sirva y este código que has pegado tampoco :confused: hace nada de lo que necesito.

El codigo lo que hace es que cuando se pulse la tecla TAB salga por pantalla la suma del SelStart y del SelLength y aparte de que no se imprima el TAB. Y no le veo relación con lo que yo quiero hacer, ya que estos dos valores son la posición del cursor y de la longitud de la seleccion.

No sé, pero creo que no nos entendemos muy bien :(. Aunque por intentarlo que no quede..... :D.

Se me ocurre que quizá tu idea era que seleccionase con el ratón el un TAB escrito anteriormente y que el código me dijera la longitud, si es eso te adelanto que no funciona ya que la longitud del caracter \t es siempre 1.

Manualmente he comprobado que un TAB equivale a 9 espacios por defecto, y lo que yo quiero es poder cambiar eso (tanto acceder para obtener ese valor como acceder para cambiarlo).

Gracias de todas formas, sigo esperando respuesta.

barman
29-10-2004, 16:48:07
No sé, pero creo que no nos entendemos muy bien :(. Aunque por intentarlo que no quede..... :D.


Creo que no.
A ver por parte, 1º escribres y si pulsas el tabulador le envias 9 espacios.

void __fastcall TForm1::RichEdit1KeyUp(TObject *Sender, WORD &Key,
TShiftState Shift)
{
if (Key == VK_TAB)
{
RichEdit1 ->SetSelTextBuf(" ");
}

}


2º que lea el texto escrito y que cambie los Tabs por que quieras
SetSelTextBuf.

for (int i = 0; i< strlen(RichEdit1 ->Text.c_str()); i++ )
{
if (RichEdit1 ->Text.c_str()[i] == VK_TAB)
ShowMessage("A");
}

Sonic
08-11-2004, 08:47:20
Al final ya entendí por donde ibas :D.

Muchas gracias por no rendirte, es buena la idea pero no me sirve, ya que eso sólo funciona para los textos que se escriban directamente en el RichEdit. Pero si importara un texto desde un archivo los Tabs no se procesarían y tendría que hacer una lectura del texto para cambiar los \t por grupos de 9 espacios. Y resulta que eso tampoco estaría bien porque
por otra parte, también comprendí que el simple hecho de haber planteado la pregunta era un error. Y es que un \t no equivale a ningún número de espacios (será por eso que no encontraba información):D. Si, al principio del texto, escribes " \t" el cursor se pondrá en el mismo lugar que si escribes "\t" solamente.

Quizás por eso no entendía tus explicaciones, porque yo buscaba algún mensaje a la API o alguna propiedad que me diera el número de espacios a que equivale un tab. Y no hacer yo mismo, que dicha equivalencia tuviera lugar. Y seguramente tú ya sabías mejor que yo lo que es un tab.

Al final resolví el problema por otros caminos, pero muchas gracias por tu ayuda.
Saludetes!

roman
09-11-2004, 04:52:39
Al final resolví el problema por otros caminos

Sería bienvenida tu explicación de esos otros caminos para quienes en un futuro se encuentren con un problema similar.

Por otra parte, desde que vi este hilo hace tiempo pensé: un RichEdit tiene una propiedad Paragraph.Tabs que es un arreglo de enteros que indican los puntos donde debe detenerse el tabulador.

Como ya bien notaste, un tabulador no corresponde a un número determinado de caracteres o espacios en blanco por una sencilla razón: a menos que la fuente que uses sea de ancho constante- como la Courier New - no tiene caso tratar de establecer el ancho de las tabulaciones en caracteres ya que éstos son de ancho variable.

Así que, en lugar de eso, las tabulaciones se indican en twips desde el margen izquierdo (según la documentación).

Ahora bien, como dije, había visto este hilo y pensado en la propiedad Paragraph.Tabs. Sin embargo no había dicho nada porque al probarlo yo mismo la mentada propiedad no funcionaba. Por más que le especificaba distintas medidas de tabulaciones, era como si no pasase nada y seguí poniendo las tabulaciones por defecto.

Pero yo había hecho esto alguna vez.

Finalmente, buscando en archivos viejos encontré cómo lo hice. Básicamente me olvidé de fijar las tabulaciones a través de la VCL y lo hice directamente mandando el mensaje EM_SETPARAFORMAT al control. En el código tengo algunos comentarios referentes a que la implementación de la VCL es incorrecta pero confieso que ya no recuerdo bien por qué, así como tampoco recuerdo exactamente qué es lo que hace el código.

Pero lo he probado y funciona.

El código está hecho pensando en una fuente de ancho fijo como Courier New de manera que en ese caso sí podía traducir los anchos de las tabulaciones en número de caracateres.

Como te digo, no puedo explicar los detalles porque ya no los recuerdo pero creo que puede servirte a tí o alguien más para ver por donde va el asunto.

El código es para Delphi pero debiera portarse sin problemas a C++.


(*
Devuelve el ancho promedio de un caracter según la
fuente seleccionada en el RichEdit.
*)
function TForm1.GetCharWidth;
var
DC: HDC;
TM: TTextMetric;

begin
DC := GetDC(RichEdit1.Handle);
SelectObject(DC, RichEdit1.Font.Handle);
GetTextMetrics(DC, TM);
Result := TM.tmAveCharWidth;
ReleaseDC(RichEdit1.Handle, DC);
end;

(*
Establece el ancho de las tabulaciones del RichEdit
Usamos todas las tabulaciones del mismo ancho.
La fórmula usada para establecer el ancho de cada
tabulación es

AnchoReal = 15*Value*CharWidth
*)
procedure TForm1.SetTabWidth(Value: Word);
var
Paragraph: TParaFormat;
Index: Integer;

begin
// Establecer las posiciones de las tabulaciones
with Paragraph do
begin
cbSize := SizeOf(TParaFormat);
dwMask := PFM_TABSTOPS;
cTabCount := MAX_TAB_STOPS;
for Index := 0 to MAX_TAB_STOPS - 1 do
rgxTabs[Index] := 15*(Index*Value + 1)*GetCharWidth;
end;

RichEdit1.Perform(EM_SETPARAFORMAT, 0, LParam(@Paragraph));
end;

procedure TForm1.FormCreate(Sender: TObject);
var
Paragraph: TParaFormat;

begin
// Establecer márgenes izquierdo y derecho
with Paragraph do
begin
cbSize := SizeOf(TParaFormat);
dwMask := PFM_STARTINDENT or PFM_RIGHTINDENT;
dxStartIndent := 15*GetCharWidth;
dxRightIndent := 15*GetCharWidth;
end;

RichEdit1.Perform(EM_SETPARAFORMAT, 0, LParam(@Paragraph));
end;


La parte del FormCreate fue necesaria ya que la primera tabulación no la ponía donde yo quería de manera que establecí el margen con el mismo ancho que la tabulación.

Hace tiempo que hice este código así que desconozco si actualmente el "problema" con la VCL se ha solucionado. Aunque aparentemente no, o bien es simplemente cuestión de que no sé como usar la mencionada propiedad Paragraph.Tabs directamente.

// Saludos

Sonic
23-11-2004, 12:40:05
El problema de los TABS surgió por la necesidad de hacer un Editor que se comportara de manera similar a la de Builder C++. Entre otras cosas lo que pretendía es que en una situación como esta:

linea 1 del texto
linea2 del texto


Al situar el cursor justo delante de la 'l' de la segunda linea el Editor borrara todos los espacios necesarios para dejar la segunda linea al nivel de la primera, para ello necesitaba conocer a que distancia del margen se encontraba el primer caracter de cada linea. Y pensé que lo mejor era medir esa distancia en número de caracteres pensando erróneamente que el caracter \t podía equivaler a un número concreto de espacios (de ahí mi empeño por hallar una propiedad que me diera dicho número)

Hasta que no me di cuenta de que tal número no exístia por no ser '\t' un conjunto de caracteres como muy bien apuntaba Roman. No busqué otras soluciones.

Al final decidí que lo mejor par mi caso era medir la distancia al margen izquierdo en píxels para comparar las distintas lineas. Y así lo hice mediante el mensaje a la API "EM_POSFROMCHAR" que facilita la distancia en píxels a los márgenes izquierdo y superior de un TRichEdit si más que indicar la posición que ocupa el caracter al que se quiere hacer referencia.

Con este mensaje y algunas comparaciones mi problema quedó completamente resuelto.

Muchas gracias Roman por tus aclaraciones y por recordarme que escribiera el final de la historia.

Saludos a todos!