Curso de Pascal. Tema 10: Pantalla en modo texto.
En este tema vamos a ver cómo acceder a la pantalla de texto, y
algunos "bonus".
Este tema va a ser específico de Turbo Pascal para DOS.
Algunas de las cosas que veremos aparecen en otras versiones de Turbo Pascal
(la 3.0 para CP/M, por ejemplo), pero no todas, y de cualquier modo, nada
de esto es Pascal estándar. Aun así, como muchas versiones de Pascal posteriores (Tmt Pascal, Virtual Pascal, Free Pascal, etc) buscan una cierta compatibilidad con Turbo Pascal, es fácil que funcione con muchos compiladores recientes.
Me centraré primero en cómo se haría con las versiones
5.0
y superiores de Turbo Pascal. Luego comentaré cómo
se haría con Turbo Pascal 3.01.
Vamos allá... En la mayoría de los lenguajes de
programación, existen "bibliotecas" (en inglés, "library")
con funciones y procedimientos nuevos, que permiten ampliar el lenguaje.
En Turbo Pascal, estas bibliotecas reciben el nombre de "unidades"
(UNIT), y existen a partir de la versión 5.
Veremos cómo crearlas un poco más adelante, pero de momento
nos va a interesar saber cómo acceder a ellas, porque "de fábrica"
Turbo Pascal incorpora unidades que aportan mayores posibilidades
de manejo de la pantalla en modo texto o gráfico, de acceso a funciones
del DOS, de manejo de la impresora, etc.
Así, la primera unidad que trataremos es la encargada de gestionar
(entre otras cosas) la pantalla en modo texto. Esta unidad se llama
CRT.
Para acceder a cualquier unidad, se emplea la sentencia "uses"
justo después de "program" y antes de las declaraciones de variables:
program prueba;
uses crt;
var
[...]
Voy a mencionar algunos de los procedimientos
y funciones más importantes. Al final de esta lección resumo todos
los que hay y para qué sirven.
-
ClrScr : Borra la pantalla.
-
GotoXY (x, y) : Coloca el cursor en unas coordenadas de la pantalla.
-
TextColor (Color) : Cambia el color de primer plano.
-
TextBackground (Color) : Cambia el color de fondo.
-
WhereX : Función que informa de la coordenada x actual del
cursor.
-
WhereY : Coordenada y del cursor.
-
Window (x1, y1, x2, y2) : Define una ventana de texto.
Algunos "extras" no relacionados con la pantalla son:
-
Delay(ms) : Espera un cierto número de milisegundos.
-
ReadKey : Función que devuelve el carácter que se
haya pulsado.
-
KeyPressed : Función que devuelve TRUE si se ha pulsado alguna
tecla.
-
Sound (Hz) : Empieza a generar un sonido de una cierta frecuencia.
-
NoSound: Deja de producir el sonido.
Comentarios generales, la mayoría "triviales"
:
-
X es la columna, de 1 a 80.
-
Y es la fila, de 1 a 25.
-
El cursor es el cuadrado o raya parpadeante que nos indica donde seguiríamos
escribiendo.
-
Los colores están definidos como constantes con el nombre en inglés.
Así Black = 0, de modo que TextColor ( Black ) es lo mismo
que TextColor(0).
-
La pantalla se puede manejar también accediendo directamente a la
memoria de video, pero eso lo voy a dejar, al menos por ahora...
Aquí va un programita de ejemplo que maneja todo esto...
o casi
{--------------------------}
{ Ejemplo en Pascal:
}
{
}
{ Ejemplo de la unidad }
{ CRT: acceso a panta- }
{ lla en modo texto TP }
{ EJCRT.PAS
}
{
}
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes
}
{
}
{ Comprobado con:
}
{ - Turbo Pascal 7.0
}
{ - Tmt Pascal Lt 1.01 }
{--------------------------}
program PruebaDeCRT;
uses crt;
var
bucle : byte;
tecla : char;
begin
ClrScr;
{ Borra la pantalla }
TextColor( Yellow );
{ Color amarillo }
TextBackground( Red );
{ Fondo rojo }
GotoXY( 40, 13 );
{ Vamos al centro de la pantalla }
Write(' Hola ');
{ Saludamos }
Delay( 1000 );
{ Esperamos un segundo }
Window ( 1, 15, 80, 23 );
{ Ventana entre las filas 15 y 23 }
TextBackground ( Blue );
{ Con fondo azul }
ClrScr;
{ La borramos para que se vea }
for bucle := 1 to 100
do WriteLn( bucle );
{ Escribimos del 1 al 100 }
WriteLn( 'Pulse una tecla..');
tecla := ReadKey;
{ Esperamos que se pulse una tecla }
Window( 1, 1, 80, 25 );
{ Restauramos ventana original }
GotoXY( 1, 24 );
{ Vamos a la penúltima línea }
Write( 'Ha pulsado ', tecla ); { Pos eso }
Sound( 220 );
{ Sonido de frecuencia 220 Hz }
Delay( 500 );
{ Durante medio segundo }
NoSound;
{ Se acabó el sonido }
Delay( 2000 );
{ Pausa antes de acabar }
TextColor( LightGray );
{ Colores por defecto del DOS }
TextBackground( Black );
{ Y borramos la pantalla }
ClrScr;
end.
Finalmente, veamos los cambios para Turbo Pascal 3.01: En TP3
no existen unidades, por lo que la línea "uses crt;" no existiría.
La otra diferencia es que para leer una tecla se hace con "read(kbd,
tecla);" (leer de un dispositivio especial, el teclado, denotado
con kbd) en vez de con "tecla := readkey". Con estos dos cambios,
el programa anterior funciona perfectamente.
Tema 10.2: Pantalla en modo texto con Surpas.
Para Surpas la cosa cambia un poco:
-
GotoXY empieza a contar desde 0.
-
No existen ClrScr, TextColor ni TextBackground (entre otros), que se pueden
emular como he hecho en el próximo ejemplo.
-
No existen Window, Delay, Sound, y no son tan fáciles de crear como
los anteriores.
Con estas consideraciones, el programa (que aun así se parece)
queda:
{--------------------------}
{ Ejemplo en Pascal:
}
{
}
{ Pantalla de texto
}
{ con Surpas
}
{ EJCRTSP.PAS
}
{
}
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes
}
{
}
{ Comprobado con:
}
{ - Surpas 1.00
}
{--------------------------}
program PruebaDeCRT;
{ ----- Aqui empiezan las definiciones que hacen que SurPas
maneje la pantalla
de forma similar a Turbo Pascal ------ }
{ Para comprender
de donde ha salido esto, consulta el
fichero
IBMPC.DOC que acompaña a SURPAS }
const
Black =
0;
Blue =
1;
Green =
2;
Cyan =
3;
Red
= 4;
Magenta = 5;
Brown =
6;
LightGray = 7;
DarkGray = 8;
LightBlue = 9;
LightGreen = 10;
LightCyan = 11;
LightRed = 12;
LightMagenta= 13;
Yellow = 14;
White = 15;
procedure ClrScr;
begin
gotoxy(0,0);
write( CLREOS );
end;
procedure TextColor(n: byte);
begin
write( chr(27), 'b', chr );
end;
procedure TextBackground(n: byte);
begin
write( chr(27), 'c', chr );
end;
{ Se podrían añadir otras posibilidades, como
TextMode, HighVideo y
LowVideo, etc, siguiendo este esquema, si se cree
necesario }
{ ----- Final del añadido ----- }
var
bucle : byte;
tecla : char;
begin
ClrScr;
{ Borra la pantalla }
TextColor( Yellow );
{ Color amarillo }
TextBackground( Red );
{ Fondo rojo }
GotoXY( 30, 13 );
{ Vamos al centro de la pantalla }
Write(' Hola. Pulse una tecla... ');
{ Saludamos }
read(kbd,tecla);
{ Esperamos que se pulse una tecla }
TextBackground ( Blue );
{ Con fondo azul }
ClrScr;
{ La borramos para que se vea }
for bucle := 1 to 100
do Write( bucle, ' ' );
{ Escribimos del 1 al 100 }
WriteLn;
{ Avanzamos una línea }
WriteLn( 'Pulse otra tecla..');
read(kbd,tecla);
{ Esperamos que se pulse una tecla }
GotoXY( 0, 12 );
{ Vamos al centro de la pantalla }
Write( 'Ha pulsado ', tecla ); { Pos eso }
TextColor( LightGray );
{ Colores por defecto del DOS }
TextBackground( Black );
{ Y borramos la pantalla }
GotoXY( 0, 23 );
{ Vamos a la penúltima línea }
end.
Tema 10.3: Procedimientos y funciones en CRT.
Finalmente, y por eso de que lo prometido es deuda,
va un resumen de los
procedimientos y funciones que tenemos
disponibles en la unidad CRT (comprobado con Turbo Pascal 7.0):
AssignCrt Asocia un fichero de texto con
la pantalla, de modo
que podríamos usar órdenes como write(output, 'Hola'),
más cercanas al Pascal "original". Como creo que nadie
la use (ni yo), no cuento más.
ClrEol Borra desde la
posición actual hasta el final de la línea.
ClrScr Borra la pantalla
y deja el cursor al comienzo de ésta
(en la esquina superior izquierda).
Delay Espera un
cierto número de milisegundos.
DelLine Borra la línea
que contiene el cursor.
GotoXY Mueve el cursor
a una cierta posición de la pantalla.
HighVideo Modo de "alta intensidad".
Es casi un "recuerdo" de cuando
las pantallas monocromas no podían mostrar colores (ni
siquiera varios tonos de gris) y sólo podíamos usar
dos tonos: "normal" o "intenso" (si alguien conserva una
tarjeta gráfica Hercules sabrá a qué me refiero, y
con una
VGA basta con escribir MODE MONO desde el DOS).
InsLine Inserta una línea
en la posicón del cursor.
KeyPressed Dice si se ha pulsado una tecla.
El valor de esta tecla
se puede comprobar después con ReadKey.
LowVideo Texto de "baja intensidad"
(ver HighVideo).
NormVideo Texto de "intensidad normal" (la
que tuviera el carácter
del cursor al comenzar el programa).
NoSound Para el sonido del
altavoz interno.
ReadKey Lee un carácter
de el teclado. Si no se ha pulsado ninguna
tecla, espera a que se pulse.
Sound Hace que
el altavozx interno comience a producir un sonido.
La duración se controlará con Delay o algún método
similar,
y el sonido se debe parar con NoSound.
TextBackground Elige el color de fondo.
TextColor Fija el color de primer plano.
TextMode Cambia a un cierto modo
de pantalla.
WhereX Devuelve la posición
X en la que se encuentra el cursor.
WhereY Posición
Y en la que se encuentra.
Window Define una ventana
de texto.
También tenemos las variables siguientes (cuyo valor
podemos leer o cambiar):
CheckBreak Boolean. Indica si puede
interrumpir el programa
pulsando Ctrl+C ó Ctrl+Break.
CheckEOF Boolean. Muestra
un carácter de fin de fichero o no
al pulsar Ctrl+Z.
DirectVideo Boolean. Escritura directa
a video o no. Si el valor
es True (por defecto), Write y WriteLn escriben en la
memoria de pantalla. Si es False, las llamadas utilizan
servicios de la Bios, más lentos. La pregunta es "¿y
quien quiere lentitud? ¿para qué vamos a ponerlo a
False?" La respuesta es que a través de los servicios
de la Bios podemos usar Write para escribir también en
modo gráfico. Se verá un ejemplo del uso de DirectVideo
más adelante, en la Ampliación 2 ("Gráficos sin BGI").
CheckSnow Boolean. Cuando se
escribe directamente en memoria de
pantalla con una tarjeta CGA antigua puede aparecer
"nieve". Si es nuestro caso, o puede darse en alguien
para quien estemos haciendo el programa, deberemos
añadir CheckSnow := True.
LastMode Word. Guarda
el modo de pantalla activo cuando comenzó
el programa.
TextAttr Byte. Atributos
(colores) actuales del texto.
WindMin Word.
WindMax Word. Coordenadas
mínimas y máximas de la ventana actual.
Cada word son dos bytes: el byte bajo devuelve la
coordenada X (p .: lo(WindMin)) y el alto la Y (p .:
hi(WindMin)).
Y como constantes (por ejemplo, para poder escribir el nombre
de un color en vez de recordar qué número indica ese color,
como hemos hecho en los ejemplos anteriores):
Black = 0
Blue = 1
Green = 2
Cyan = 3
Red = 4
Magenta = 5
Brown = 6
LightGray = 7
DarkGray = 8
LightBlue = 9
LightGreen = 10
LightCyan = 11
LightRed = 12
LightMagenta= 13
Yellow = 14
White = 15
Las constantes que indican los modos de pantalla son:
BW40 = 0 Blanco y negro 40x25 en CGA
o superiores.
CO40 = 1 Color 40x25 en CGA o superiores.
BW80 = 2 Blanco y negro 80x25 en
CGA o superiores.
CO80 = 3 Color 40x25 en CGA o superiores.
Mono = 7 Monocromo 80x25 en MDA,
Hercules, EGA Mono o VGA Mono.
Font8x8 = 256 Modo de 43 o 50 líneas en EGA o VGA.
Y por compatibilidad con la versión 3.0:
C40 = CO40
C80 = CO80
Pues hala, a experimentar...
Tema 10.4: Ejemplo: juego del ahorcado.
Antes de dejar el tema, un ejemplo sencillo que ponga a prueba algunas
de las cosas que hemos visto: vamos a hacer el juego del ahorcado:
-
Un primer jugador deberá introducir una frase. La pantalla
se borrará, y en lugar de cada letra aparecerá un guión.
-
El segundo jugador deberá ir tecleando letras. Si falla, ha
gastado uno de sus intentos. Si acierta, la letra acertada deberá
aparecer en las posiciones en que se encuentre.
-
El juego acaba cuando se aciertan todas las letras o se acaban los intentos.
{--------------------------} { Ejemplo en Pascal: } { } { Juego del Ahorcado } { AHORCA.PAS } { } { Este fuente procede de } { CUPAS, curso de Pascal } { por Nacho Cabanes } { } { Comprobado con: } { - Turbo Pascal 7.0 } { - Tmt Pascal Lt 1.20 } {--------------------------}
Program Ahorcado;
Uses crt;
Var palabra, intento, letras:string; { La palabra a adivinar, la que } { el jugador 2 va consiguiendo y } { las letras que se han probado } oportunidades: integer; { El número de intentos permitido } letra: char; { Cada letra que prueba el jug. dos } i: integer; { Para mirar cada letra, con "for" } acertado: boolean; { Si ha acertado alguna letra }
begin clrscr; { Valores iniciales, del jugador 1 } gotoxy (10,5); write ('Jugador 1: ¿Que frase hay que adivinar? '); readln (palabra); gotoxy (10,7); write ('¿En cuantos intentos? '); readln (oportunidades);
intento := ''; { Relleno con _ y " " lo que ve Jug. 2 } for i:=1 to length(palabra) do if palabra[i]= ' ' then intento:=intento+' ' else intento:=intento+'_';
repeat clrscr; gotoxy (10,6); { Digo cuantos intentos le quedan } writeln('Te quedan ',oportunidades,' intentos');
gotoxy (10,8); { Le muestro cómo va } writeln(intento);
gotoxy (10,10); { Y le pido otra letra } write('Letras intentadas: ', letras);
gotoxy (10,12); { Y le pido otra letra } write('¿Qué letra? '); letra := readkey; letras := letras + letra;
acertado := false; { Miro a ver si ha acertado } for i:=1 to length(palabra) do if letra=palabra[i] then begin intento[i]:=palabra[i]; acertado := true; end;
if acertado = false then { Si falló, le queda un intento menos } oportunidades := oportunidades-1;
until (intento=palabra) { Hasta que acierte } or (oportunidades=0); { o gaste sus oportunidades }
gotoxy(10, 15); { Le felicito o le digo cual era } if intento=palabra then writeln('¡Acertaste!') else writeln('Lo siento. Era: ', palabra); end.
Esto es muy mejorable. La primera mejora será que no haya necesidad
de que un primer jugador sea el que escriba la palabra a adivinar y el
número de intentos, sino que el número de intentos esté
prefijado en el programa, y exista una serie de palabras de las que el
ordenador escoja una al azar (para lo que usaremos "random" y "randomize",
que se ven con más detalle en la Ampliación 1):
{--------------------------} { Ejemplo en Pascal: } { } { Juego del Ahorcado } { (segunda version) } { AHORCA2.PAS } { } { Este fuente procede de } { CUPAS, curso de Pascal } { por Nacho Cabanes } { } { Comprobado con: } { - Turbo Pascal 7.0 } { - Tmt Pascal Lt 1.20 } {--------------------------}
Program Ahorcado2;
Uses crt;
Const NUMPALABRAS = 10; MAXINTENTOS = 2; datosPalabras: array[1..NUMPALABRAS] of string = ( 'Alicante','Barcelona','Guadalajara','Madrid', 'Toledo','Malaga','Zaragoza','Sevilla', 'Valencia','Valladolid' );
Var palabra, intento, letras:string; { La palabra a adivinar, la que } { el jugador 2 va consiguiendo y } { las letras que se han probado } numeroPalabra: word; oportunidades: integer; { El numero de intentos permitido } letra: char; { Cada letra que prueba el jug. dos } i: integer; { Para mirar cada letra, con "for" } acertado: boolean; { Si ha acertado alguna letra }
begin randomize; { Comienzo a generar numeros aleatorios } numeroPalabra := { Tomo una palabra al azar } random(NUMPALABRAS); palabra := datosPalabras[numeroPalabra+1]; oportunidades := MAXINTENTOS; intento := ''; { Relleno con _ y " " lo que ve Jug. 2 } for i:=1 to length(palabra) do if palabra[i]= ' ' then intento:=intento+' ' else intento:=intento+'*';
repeat clrscr; gotoxy (10,6); { Digo cuantos intentos le quedan } writeln('Te quedan ',oportunidades,' intentos'); gotoxy (10,8); { Le muestro como va } writeln(intento); gotoxy (10,10); { Y le pido otra letra } write('Letras intentadas: ', letras); gotoxy (10,12); { Y le pido otra letra } write('¿Qué letra? '); letra := upcase(readkey); { Convierto a mayusculas } letras := letras + letra;
acertado := false; { Miro a ver si ha acertado } for i:=1 to length(palabra) do if letra=upcase(palabra[i]) then begin { Comparo en mayusculas } intento[i]:=palabra[i]; acertado := true; end; if acertado = false then { Si falla, le queda un intento menos } oportunidades := oportunidades-1; until (intento=palabra) { Hasta que acierte } or (oportunidades=0); { o gaste sus oportunidades } gotoxy(10, 15); { Le felicito o le digo cual era }
if intento=palabra then begin gotoxy (10,8); writeln(intento); gotoxy(10, 15); writeln('¡Acertaste!') end else writeln('Lo siento. Era: ', palabra); end.
Una segunda mejora podría ser que realmente "se dibujara" el
ahorcado en pantalla en vez de limitarse a decirnos cuantos intentos nos
quedan. Como todavía no sabemos manejar la pantalla en modo gráfico,
dibujaremos de un modo rudimentario, empleando letras. El resultado será
"feo", algo parecido a esto:
(## Imagen todavía no disponible ##)
Y lo podríamos conseguir así:
{--------------------------} { Ejemplo en Pascal: } { } { Juego del Ahorcado } { (tercera version) } { AHORCA3.PAS } { } { Este fuente procede de } { CUPAS, curso de Pascal } { por Nacho Cabanes } { } { Comprobado con: } { - Turbo Pascal 7.0 } { - Tmt Pascal Lt 1.20 } {--------------------------}
Program Ahorcado3;
Uses crt;
Const NUMPALABRAS = 10; datosPalabras: array[1..NUMPALABRAS] of string = ( 'Alicante','Barcelona','Guadalajara','Madrid', 'Toledo','Malaga','Zaragoza','Sevilla', 'Valencia','Valladolid' ); MAXINTENTOS = 5; { No debe ser modificado: vamos a "dibujar" 5 cosas }
Var palabra, intento, letras:string; { La palabra a adivinar, la que } { el jugador 2 va consiguiendo y } { las letras que se han probado } numeroPalabra: word; oportunidades: integer; { El numero de intentos permitido } letra: char; { Cada letra que prueba el jug. dos } i: integer; { Para mirar cada letra, con "for" } acertado: boolean; { Si ha acertado alguna letra }
procedure PrimerFallo; { Primer fallo: } var j: byte; { Dibujamos la "plataforma" } begin for j := 50 to 60 do begin gotoxy(j,20); write('-'); end; end;
procedure SegundoFallo; { Segundo fallo: } var j: byte; { Dibujamos el "palo vertical" } begin for j := 14 to 19 do begin gotoxy(53,j); write('|'); end; end;
procedure TercerFallo; { Tercer fallo: } var j: byte; { Dibujamos el "palo superior" } begin for j := 53 to 57 do begin gotoxy(j,14); write('-'); end; end;
procedure CuartoFallo; { Cuarto fallo: } var j: byte; { Dibujamos la "plataforma" } begin gotoxy(57,15); write('|'); end;
procedure QuintoFallo; { Quinto fallo: } var j: byte; { Dibujamos la "plataforma" } begin gotoxy(56,16); write(' O'); gotoxy(56,17); write('/|'); gotoxy(56,18); write('/ ');
for j := 50 to 60 do begin gotoxy(j,20); write('-'); end; end;
begin randomize; { Comienzo a generar numeros aleatorios } numeroPalabra := { Tomo una palabra al azar } random(NUMPALABRAS); palabra := datosPalabras[numeroPalabra+1]; oportunidades := MAXINTENTOS; intento := ''; { Relleno con _ y " " lo que ve Jug. 2 } for i:=1 to length(palabra) do if palabra[i]= ' ' then intento:=intento+' ' else intento:=intento+'*';
repeat clrscr;
{ Dibujo lo que corresponde del "patibulo" } if oportunidades <= 4 then PrimerFallo; if oportunidades <= 3 then SegundoFallo; if oportunidades <= 2 then TercerFallo; if oportunidades <= 1 then CuartoFallo;
gotoxy (10,6); { Digo cuantos intentos le quedan } writeln('Te quedan ',oportunidades,' intentos'); gotoxy (10,8); { Le muestro como va } writeln(intento); gotoxy (10,10); { Y le pido otra letra } write('Letras intentadas: ', letras); gotoxy (10,12); { Y le pido otra letra } write('¿Qué letra? '); letra := upcase(readkey); { Convierto a mayusculas } letras := letras + letra;
acertado := false; { Miro a ver si ha acertado } for i:=1 to length(palabra) do if letra=upcase(palabra[i]) then begin { Comparo en mayusculas } intento[i]:=palabra[i]; acertado := true; end; if acertado = false then { Si falla, le queda un intento menos } oportunidades := oportunidades-1; until (intento=palabra) { Hasta que acierte } or (oportunidades=0); { o gaste sus oportunidades } { Le felicito o le digo cual era }
if intento=palabra then begin gotoxy (10,8); writeln(intento); gotoxy(10, 15); writeln('¡Acertaste!') end else begin QuintoFallo; gotoxy(10, 15); writeln('Lo siento. Era: ', palabra); end; end.
Tema 10.5: Ejemplo: entrada mejorada.
Finalmente, vamos a hacer algo mejor que el "readln".
Crearemos una rutina de introducción de datos que permita corregir
con mayor facilidad: en cualquier posición de la pantalla, limitando
el tamaño máximo de la respuesta, desplazándonos con
las flechas, usando las teclas Inicio y Fin, permitiendo insertar o sobreescribir,
etc. Podría ser así:
{--------------------------} { Ejemplo en Pascal: } { } { Entrada mejorada de } { datos } { ENTRMEJ.PAS } { } { Este fuente procede de } { CUPAS, curso de Pascal } { por Nacho Cabanes } { } { Comprobado con: } { - Turbo Pascal 7.0 } { - Turbo Pascal 5.0 } {--------------------------}
{ PIDEXY: Entrada mejorada de datos. - En cualquier posición de la pantalla. - Muestra el tamaño máximo y lo limita. - Permite usar las flechas, Inicio, Fin, Ctrl+Flechas, Supr. - Modo de inserción o sobreescritura.
-- Esto es parte de CUPAS, curso de Pascal por Nacho Cabanes --
-- Este ejemplo sólo funcionará en Turbo Pascal 5.0 o superior --
Mejoras posibles no incluidas: - Cambiar la forma del cursor según se esté en modo de inserción o sobreescritura. - Quitar los espacios sobrantes a la derecha de la palabra. - Permitir la edición en varias líneas. - Seguro que alguna más...  }
uses crt;
FUNCTION SPC(n:byte):string; {Espacios en blanco} var b:string; c:byte; begin b:=''; for c:=1 to n do b:=b+' '; spc:=b end;
PROCEDURE PIDEXY(var valor:string; long:byte; x,y:byte; nuevo:boolean); { Valor: la variable en la que se va a devolver } { Long: longitud máxima permitida } { x,y: posición en pantalla } { Nuevo: ¿borrar el contenido anterior de "valor"? }
var i,fila,posix,posiy: byte; {bucles, fila, posición, inicial, final} inicial,final:byte; { inicial, final } tecla:char; { tecla que se pulsa } insertar:boolean; { ¿modo de inserción? }
begin if nuevo=true then valor:=''; gotoxy(x,y); fila:=wherey; write('['); ; for i:=1 to long do write('·'); { Para que se vea mejor } write(']'); ; for i:=length(valor) to long-1 do valor:=valor+'·'; insertar:=false; posix:=1; posiy:=y; repeat gotoxy(x+1,y); write(valor); gotoxy(posix+x,y); tecla:=readkey; { Lee una pulsación }
if ord(tecla)=0 then { Si es tecla de función } case ord(readkey) of { Flecha izquierda } 75: if posix>1 then posix:=posix-1; { Flecha derecha } 77: if posix<long then posix:=posix+1; { Insert } 82: if insertar then insertar:=false else insertar:=true; { Inicio } 71: posix:=1; { Fin } 79: begin i:=long; while valor[i]='·' do dec(i); posix:=i end; { Supr } 83: begin for i:=posix to long-1 do valor[i]:=valor[i+1]; valor[long]:='·' end; { Ctrl + <- } 115: begin inicial:=posix; for i:=1 to posix-2 do if (valor[i]=' ') and (valor[i+1]<>' ') then posix:=i+1; if posix=inicial then posix:=1 end; { Ctrl + -> } 116: for i:=long-1 downto posix do if (valor[i]=' ') and (valor[i+1]<>' ') then posix:=i+1; end else { Si es carácter imprimible } if tecla>=' ' then if not insertar then { Si no hay que insertar } begin valor[posix]:=tecla; { Reemplaza } if posix<long then posix:=posix+1 { y avanza } end else { Si hay que insertar } begin for i:=long downto posix do valor[i]:=valor[i-1]; { Avanza todo } valor[posix]:=tecla; if posix<long then posix:=posix+1 end else { Si es la tecla de borrado } if (ord(tecla)=8) and (posix>1) then begin for i:=posix-1 to long-1 do valor[i]:=valor[i+1]; valor[long]:='·'; posix:=posix-1 end; until ord(tecla)=13; { Hasta pulsar INTRO }
for i:=1 to length(valor) do { Al terminar, pone espacios } if valor[i]='·' then valor[i]:=' '; gotoxy(x,y); write(' ' + valor + ' '); { Y muestra el resultado } end;
{ --- Mini-Programa de prueba --- }
var nombre: string;
begin clrscr; gotoxy(3,3); write( '¿Cómo te llamas?' ); pidexy( nombre, 20, 3,4, TRUE ); gotoxy(3, 10); writeln( 'Tu nombre es: ', nombre ); readln; end.
|