Capítulo 15. Modo texto y modo gráfico. 1. Introducción.

Anuncio
Capítulo 15. Modo texto y modo gráfico.
1. Introducción.
2. El modo texto.
2.1. Modos de salida por pantalla.
2.2. Control de posiciones de pantalla.
2.3. Colores.
2.4. Control de ventanas de pantalla.
2.5. Entrada y salida con colores.
3. El modo gráfico.
3.1. Introducción al modo gráfico.
3.2. Inicialización y cierre del modo gráfico.
3.3. Comprobación de error gráfico.
3.4. Manipulación del modo gráfico.
3.5. Control de ventanas y posiciones.
3.6. Manipulación de los colores.
3.7. Visualización de pixels y figuras.
3.8. Entrada y salida en modo gráfico.
1
1. Introducción.
El C++ permite trabajar en modo texto y en modo gráfico.
En modo texto la pantalla se divide en una serie de posiciones y cada
carácter a visualizar ocupará una de esas posiciones. Se permite acceder
individualmente a una posición.
En modo gráfico la pantalla se divide en una serie de pixels, que son
mucho más pequeños que las posiciones en modo texto. Un carácter ocupará
un conjunto de pixels. Se permite acceder de forma individual a un pixel.
2. El modo texto.
2.1. Modos de salida por pantalla.
Para visualizar datos por la pantalla, el C permite usar dos métodos,
directamente a la RAM de la tarjeta gráfica o a través de llamadas a la BIOS
del sistema. Existe la variable global directvideo, predefinida en conio.h, que
por defecto vale 1, indicando que se escriba directamente a la RAM gráfica. Si
se establece a 0, las salidas por pantalla se hacen a través de llamadas a la
BIOS. Con el valor 0 se asegura la compatibilidad con mayor diversidad de
sistemas. Para usar el valor 1, se debe estar seguro que existe compatibilidad
100 % con sistemas PC-IBM.
Por otra parte, la tarjeta gráfica tiene una memoria ROM que contiene la
forma (los pixels que deben iluminarse) de cada carácter ASCII, para trabajar
en modo texto. La tarjeta recibe del procesador el código ASCII del carácter,
consulta en la ROM su forma y visualiza los pixels correspondientes.
La tarjeta gráfica tiene además una memoria RAM donde mantiene la
información mostrada en pantalla, para redibujarla unas 50/60 veces por
segundo (50/60 Hz). En esta memoria RAM existe una celda para cada
posición de pantalla, por ejemplo un array de 80x25 posiciones. Cada posición
ocupa 2 bytes. En el primer byte se almacena el código ASCII del carácter y en
el segundo los atributos, es decir el color de texto, de fondo e si la intermitencia
está activada o no.
2.2. Control de posiciones de pantalla.
Se puede trabajar en 6 modos de texto distintos, utilizando 6 constantes
numéricas predefinidas (en conio.h) para ello:
BW40
C40
BW80
C80
MONO
C4350
40 columnas y 25 filas en blanco y negro.
40 columnas y 25 filas en color.
80 columnas y 25 filas en blanco y negro.
80 columnas y 25 filas en color (valor usado por defecto).
80 columnas y 25 filas en monocromo.
En adaptador EGA: 80 columnas y 43 filas en color.
En adaptador VGA: 80 columnas y 50 filas en color.
Para especificar un modo de trabajo se usa la función textmode(modo).
La constante LASTMODE, cuyo valor es –1, se usa para restablecer el modo
2
de texto existente antes de cambiarlo la última vez, de la forma
textmode(LASTMODE).
Ej.
textmode(C4350);
La función gotoxy(columna, fila) coloca el cursor en la columna y fila
especificados.
Las funciones wherex() y wherey() devuelven la columna y la fila
respectivamente donde está colocado el cursor. Se suelen utilizar para colocar
el cursor en una determinada posición respecto a la posición actual.
Ej.
gotoxy(wherex(), wherey()+1);
//Coloca cursor en la columna actual y en la fila
//siguiente a la actual.
2.3. Colores.
En el modo texto cada posición de la pantalla tiene 3 atributos que son:
el color de texto o primer plano (foreground), el color de fondo (background) y si
la intermitencia (blink) está activa o no.
Para establecer un color para el texto se utiliza la función
textcolor(color). El parámetro color tendrá un valor entre 0 y 15, al cual se le
puede añadir el valor 128 para que sea intermitente. Los colores están
definidos como constantes numéricas en conio.h (BLACK=0, BLUE=1,
BLINK=128, etc.). Los colores de 8 a 15 son los mismos del 0 a 7 pero más
claros (alta luminosidad, por ejemplo la constante RED pasa a ser LIGHTRED).
Para establecer el color de fondo se usa textbackground(color), donde el
parámetro color estará entre 0 y 7, que serán los mismos colores del 0 al 7 que
se usan para el texto (RED, BLUE, etc.). Los colores de 8 a 15, o BLINK, no se
pueden usar para el fondo.
Existen las funciones lowvideo(), highvideo() y normvideo(), que afectan
sólo al texto, no al fondo. La primera quita la alta luminosidad al color de texto
establecido (resta 8), si es que estaba en alta luminosidad. La segunda aplica
alta luminosidad al color (suma 8). La tercera restablece los colores al
comenzar la ejecución del programa (generalmente texto a LIGHTGRAY y
fondo a BLACK).
La función textattr() permite establecer un color de texto y otro de fondo
en una sóla llamada, en lugar de llamar una vez a textcolor() y otra vez a
textbackground(), pero el resultado es el mismo. Como ya se ha comentado,
cada posición de pantalla se almacena en 2 bytes: en el primero se guarda el
código ASCII del carácter mostrado; en el segundo se guardan los atributos de
color de texto, de fondo y la intermitencia. La forma de almacenar esos
atributos en esos 8 bits es la siguiente:
3
7
6
5
4
blink back back back
3
text
2
text
1
text
0
text
Los bits del 0 al 3 guardan el color de texto, de 0 a 15 (16 colores
posibles). Los bits del 4, 5 y 6 guardan el color de fondo, de 0 a 7 (8 colores
posibles). El bit 7 guarda el estado de intermitencia.
Ej.
textattr(5); //5 =0 000 0101 texto=5 fondo=0 Inter=0
textattr(37); //37 =0 010 0101 texto=5 fondo=2 Inter=0
textattr(165);//165=1 010 0101 texto=5 fondo=2 Inter=1
Para no tener que pasar a binario pueden usarse las constantes
predefinidas, multiplicando el color de fondo por 16 y sumando la constante
BLINK (128) para activar intermitencia.
Ej.
textattr(BLINK + 16 * RED + BLUE); //Texto azul, fondo
//rojo e intermitencia activada.
textattr(16*GREEN + RED); //Texto rojo, fondo verde e
//intermitencia desactivada.
Al establecer nuevos colores de fondo o de texto, los caracteres ya
mostrados en pantalla no se ven alterados. Esos colores se utilizan en los
caracteres que se van a mostrar después de usar textcolor() y
textbackground().
Los colores no son tenidos en cuenta por todas las funciones de salida
por pantalla, sólo por aquellas que escriben directamente en pantalla, como
cprintf(), cscanf(), cputs(), etc., no a través del stream (buffer de un fichero)
asociado al fichero de salida estándar (stdout, que es la pantalla), como las
funiones printf(), scanf(), puts(), etc. Las funciones clrscr() y clreol() sí tienen en
cuenta los colores.
Los colores que están establecidos en un momento dado pueden ser
almacenados, para poder restablecerlos más adelante. Esto puede realizarse
con la función gettextinfo(), la cual guarda en una variable de tipo estructura
(tipo estructura text_info predefinido en conio.h) no sólo los atributos del texto,
sino más información. El campo de esa estructura donde se guardan los
atributos de colores se llama attribute.
Ej.
struct text_info ti; //Estructura necesaria para
//guardar la información.
gettextinfo(&ti); //Guarda la información. La
//estructura se pasa por referencia.
4
textattr(ti.attribute); //Restablece los colores
//usando el campo ti.attribute.
2.4. Control de ventanas de pantalla.
Existen funciones que afectan a trozos, rectángulos o ventanas de la
pantalla.
La función clrscr() borra la pantalla completa. La función clreol() borra el
trozo de la línea desde donde esté colocado el cursor hasta el final, colocando
de nuevo el cursor donde estaba antes de borrar la línea.
Las funciones insline() y delline() inserta y elimina respectivamente la
línea completa de pantalla donde esté el cursor. Este es colocado después
donde estaba previamente.
La función window(Col_Izda, Fila_Arriba, Col_Dcha, Fila_Abajo) permite
definir una ventana dentro de la pantalla, es decir un rectángulo. Una vez
definido, las funciones que afectan a la pantalla sólo se aplican sobre ese
rectángulo. Por ejemplo, clrscr() sólo borra ese rectángulo, no la pantalla
completa. Un gotoxy(1,1) se coloca en la esquina superior izquierda del
rectángulo definido. Para volver a usar la pantalla completa se activa un
rectángulo que ocupe toda la pantalla, en función del modo que se esté
usando. Por ejemplo, window(1,1,80,25) para 80 columnas y 25 filas, o
window(1,1,80,50) para 80 columnas y 50 filas. Para conocer el número de filas
y columnas del modo texto que se está usando se usará gettextinfo(), que lo
dejará grabado en la estructura de tipo text_info, como se ha visto
anteriormente.
Las funciones gettext(), puttext() y movetext() permiten almacenar el
texto mostrado en una zona de pantalla, con gettext(Col_Izda, Fila_Arriba,
Col_Dcha, Fila_Abajo, buffer), y mostrarlo después, con puttext(Col_Izda,
Fila_Arriba, Col_Dcha, Fila_Abajo, buffer), ya sea en la misma posición en
pantalla o en una diferente. Cada posición de pantalla ocupa 2 bytes, en el
primer byte se almacena el carácter y en el segundo sus atributos. Por tanto,
para usar estas funciones debe declararse un array de tipo char con el doble de
tamaño que el número de caracteres que se va almacenar.
Ej.
char buffer[200]; //Caben 100 caracteres de pantalla.
gettext(3,5,27,8,buffer);
//25 columnas (de 3 a 27) y 4 filas (de 5 a 8).
//25x4 = 100 posiciones de pantalla
...
puttext(5,7,29,10,buffer);
//Muestra lo guardado en otra zona de pantalla.
Una vez almacenada una ventana de pantalla con gettext() en un array
como buffer, podrán modificarse las posiciones impares de dicho array, con lo
cual se modificarán los atributos de los caracteres almacenados. De esta
5
forma, el posterior puttext() mostrará la ventana con colores diferentes que los
que tenía antes del gettext().
La funcion movetext(Col_Izda, Fila_Arriba, Col_Dcha, Fila_Abajo,
Col_Izda_Destino, Fila_Arriba_Destino) mueve el rectángulo de pantalla
delimitado por Col_Izda, Fila_Arriba, Col_Dcha y Fila_Abajo a otra zona de
pantalla, cuya esquina superior izquierda queda indicada por Col_Izda_Destino
y Fila_Arriba_Destino.
2.5. Entrada y salida con colores.
La función cprintf() es un printf() con pequeñas diferencias. La primera
es que envía la salida directamente a pantalla, sin pasar por el stream o buffer
del fichero de salida estándar (stdout, que es la pantalla), como sí hace printf().
Esto implica que cprintf() realiza la salida a pantalla teniendo en cuenta los
colores activos, mientras que printf() no. Además cprintf() atiende a la ventana
activa, definida con la función window(), es decir se ajusta a dicha ventana, lo
cual no ocurre con la función printf().
Por otra parte, el carácter ‘\n’, que para printf() se traduce como un
CR+LF, para cprintf() sólo es LF (ASCII 10). Para hacer un salto de línea con
cprintf() debe escribirse “\r\n...”, o sea CR+LF (ASCII 13 y 10).
El cscanf() es como scanf() pero lee directamente de la consola, en lugar
de pasar por el stream o buffer del fichero de entrada estándar (stdin, que es el
teclado), el teclado. Las funciones getch() y getche() también leen directamente
de la consola. Esto significa que utilizan los colores que estén activados, algo
que no hacen las funciones scanf() y getchar(), ya que leen a través de stdin.
Por tanto, con cscanf(), getch() y getche() no tiene sentido utilizar después
fflush(stdin).
Las teclas que provocan fin de almacenamiento en la variable de
memoria son las mismas en cscanf() que en scanf(), por ejemplo pulsar un
espacio en blanco cuando el tipo es %s, una letra cuando el tipo es %d, pulsar
3 dígitos con el tipo %2d, pulsar 5 caracteres con el tipo %5s, etc. Es decir el
almacenamiento finaliza cuando se pulsa una tecla que no cumple con el tipo
especificado. Pero mientras scanf() permite que se siga tecleando hasta pulsar
ENTER, dejando en el buffer de teclado los datos no almacenados en la
variable, la función cscanf() no permite que se siga tecleando, sino finaliza su
ejecución y el programa sigue con la sentencia siguiente, aunque no se haya
pulsado ENTER.
Obviamente, cscanf() no deja ningún carácter en el buffer, porque no lo
usa, pero el carácter que finaliza tanto el almacenamiento como el tecleo o
entrada puede ser recogido con un getch() que se coloque después del
cscanf(). Esto significa que si se usa un getch() después del cscanf() para que
produzca una pausa en la ejecución del programa, no se realizará dicha pausa,
ya que ese getch() recoge el carácter (si es ENTER recoge un 13) que produjo
el fin del cscanf(). Por tanto, para realizar dicha pausa deberán ponerse dos
getch() después de un cscanf(). Podría escribirse por tanto:
6
scanf(...);
fflush(stdin);
cscanf(...); getch(); //Este getch() no hace pausa.
La función cscanf() almacena correctamente el carácter fin de cadena
para el tipo %s. Pero sí debe tenerse en cuenta un detalle, el tipo %[^\n]
provoca que el espacio en blanco no finalice la entrada, sino que se almacene
correctamente en la cadena, pero con ese tipo no finaliza la entrada al pulsar
ENTER, sino que se guarda en la cadena el carácter 13. Ello se debe a que
para el cscanf() el \n es el ASCII 10, no 13. Como el carácter \r es el 13, se
debe usar el tipo %[^\r].
Por otro lado, tanto scanf() como cscanf() no finalizan nunca si la primera
tecla pulsada es ENTER con un tipo que no sea %[^\n] (o %[^\r] para cscanf()),
por ejemplo con %s, %d, etc. Simplemente con scanf() se ejecuta en pantalla
un CR+LF, y con cscanf() no se ejecuta nada en pantalla.
3. El modo gráfico.
3.1. Introducción al modo gráfico.
Hasta ahora se ha estado trabajando en modo texto, en el cual cada
carácter visualizado ocupa una posición de la pantalla. El número de columnas
puede ser 40 u 80, mientras que el número de filas puede ser 25, 43 o 50, en
función del modo establecido con la función textmode(). En modo texto se
permite acceso independiente a cada posición de consola, a la que se le puede
establecer color de fondo, de texto e intermitencia, así como el carácter que se
muestra en dicha posición. Se pueden usar hasta 16 colores diferentes de texto
y 8 de fondo.
Pero C++ también permite trabajar en modo gráfico, en el que se puede
acceder de forma individual a cada pixel de la pantalla. El número máximo de
pixels depende de la tarjeta gráfica utilizada. Además se pueden usar muchos
más de 16 colores, siempre en función del adaptador gráfico.
Al trabajar en modo gráfico, las funciones de modo texto relacionadas
con la pantalla no funcionarán correctamente, por ejemplo: gotoxy(), clrscr(),
clreol(), textcolor(), textbackground(), printf(), etc.
3.2. Inicialización del modo gráfico.
Para trabajar en modo gráfico debe activarse la opción “Graphics
Library”, que se encuentra dentro del menú en el apartado “Options” – “Linker”
– “Libraries”. Al activar esta opción, el proceso de enlace (link) busca
automáticamente el fichero .BGI de librería gráfica. Además debe incluirse el
archivo de cabecera graphics.h, con la correspondiente sentencia include:
#include <graphics.h>
Aparte de esas dos acciones, para abandonar el modo texto y comenzar
a funcionar en modo gráfico, nuestro programa debe llamar a la función
initgraph(). Esta función activa el hardware para trabajar en modo gráfico,
cargando de disco a memoria el controlador (driver) gráfico del fichero .BGI
7
correspondiente. Al ejecutarse esta función, se borra la pantalla completa. La
sintaxis de esta función es:
void initgraph(int *controlador,int *modo,char *ruta);
En el parámetro ruta debe indicarse la carpeta (una cadena de
caracteres entre comillas dobles) donde se encuentran los ficheros .BGI. Si
estos ficheros están en la carpeta actual de trabajo, se puede dejar en blanco,
escribiendo sólo las comillas. Debe tenerse en cuenta que al especificar una
ruta, la barra invertida debe escribirse dos veces (\\), porque si se escribe una
sola vez es considerada como una secuencia de escape (como \n, \a, \t, etc.).
En el parámetro controlador se especifica la dirección de memoria de
una variable entera (es un puntero). El valor de esta variable indicará el driver a
utilizar. Para asignar dicho valor se pueden usar 11 constantes numéricas
predefinidas:
DETECT
CGA
MCGA
EGA
EGA64
EGAMONO
0
1
2
3
4
5
IBM8514
HERCMONO
ATT400
VGA
PC3270
6
7
8
9
10
Se suele usar la opción DETECT, con la que el programa autodetecta el
tipo de adaptador gráfico del sistema.
En el parámetro modo se especifica la dirección de una variable entera,
cuyo valor indicará el modo gráfico a utilizar, es decir el número de pixels y de
colores. Si el controlador se ha establecido a DETECT, el modo se establece
automáticamente al máximo permitido por el adaptador detectado. En este
caso, modo puede ser simplemente la dirección de una variable entera en la
que no se necesita haber guardado previamente ningún valor. En esa variable
quedará grabado el valor entero correspondiente a ese modo máximo después
de la llamada a initgraph(). Si no se usa DETECT en controlador, se debe
especificar un modo. Para ello pueden usarse unas constantes numéricas
predefinidas. Por ejemplo, cuando el controlador especificado es VGA, las
constantes para el modo pueden ser:
VGALO
VGAMED
VGAHI
0
1
2
640x200
640x350
640x480
Para utilizar un fichero .BGI suministrado por el fabricante de una tarjeta
gráfica podrá usarse la función installuserdriver().
Cuando ya no se necesita trabajar en modo gráfico y se quiere volver a
modo texto, se utilizará la función closegraph(), cuya sintaxis es:
void closegraph(void);
8
Esta función libera la memoria dinámica ocupada por el controlador
gráfico, las fuentes y todo lo relacionado con el sistema gráfico.
Ej.
#include <graphics.h>
...
void main(void)
{
int controlador = DETECT;
int modo;//No es necesario darle un valor, ya que
...
//se ha usado DETECT en controlador.
initgraph(&controlador, &modo, “C:\\BC\\BGI”);
...
closegraph();
}
Ej.
#include <graphics.h>
...
void main(void)
{
int controlador = VGA;
int modo = VGAHI;
...
initgraph(&controlador, &modo, “C:\\BC\\BGI”);
...
closegraph();
//A partir de esta línea se trabaja en modo texto.
...
}
Para conocer el adaptador gráfico de nuestro sistema y el modo gráfico
de mayor resolución para ese adaptador, puede utilizarse la función
detectgraph(). Su sintaxis es:
void detectgraph(int *controlador, int *modo)
Ej.
#include <graphics.h>
...
void main(void)
{
int controlador, modo;
detectgraph(&controlador, &modo);
//En controlador y modo queda grabado el número de
//controlador y máximo modo gráfico del sistema.
...
9
}
3.3. Comprobación de error gráfico.
Cada vez que se llama a una función que trabaja en modo gráfico,
puede producirse algún tipo de error. La función graphresult() permite
comprobar dicha situación. La sintaxis es la siguiente:
int graphresult(void);
El valor entero que devuelve indicará el tipo de error producido. Este
valor puede ser pasado a la función grapherrormsg() para visualizar una
cadena que explica el error. La sintaxis de esta función es:
char *grapherrormsg(int CodigoError);
Ej.
#include <graphics.h>
...
void main(void)
{
int controlador = DETECT, modo;
int CodigoError;
initgraph(&controlador, &modo, “C:\\BC\\BGI”);
//Para comprobar si initgraph() ha dado error:
CodigoError=graphresult();
if (CodigoError != grOk) //grOk es una cte.
{
//predefinida que vale 0.
printf(“Error:%s”,grapherrormsg(CodigoError));
//Visualiza una explicación del error.
getch(); exit(1);
}
...//Si no hay error, el programa continúa por aquí
}
3.4. Manipulación del modo gráfico.
Una vez que se ha inicializado el sistema gráfico con un controlador y un
modo gráfico por haber llamando a la función initgraph(), existen otras
funciones que permiten conocer el modo que se está usando, así como
modificar dicho modo, sin necesidad de cerrar con closegraph() y volver a
inicializar los gráficos.
La función getdrivername() devuelve el nombre del controlador usado.
La sintaxis es:
char * getdrivername(void);
La función getgraphmode() devuelve un valor entero que se corresponde
con el modo gráfico que se está usando. La sintaxis es:
10
int getgraphmode(void);
La función setgraphmode() permite establecer un nuevo modo gráfico a
utilizar. La sintaxis es:
void setgraphmode(int modo);
La función getmaxmode() devuelve el máximo modo gráfico, como
número entero, para el controlador usado. La sintaxis es:
int getmaxmode(void);
La función getmoderange() permite conocer el rango de modos válidos
que se pueden especificar para un controlador especificado. La sintaxis es:
void getmoderange(int controlador,int *ModMen,int *ModMay);
La función getmodename() devuelve el nombre que corresponde al
modo gráfico cuyo valor numérico se le pase como parámetro. La sintaxis es:
char * getmodename(int modo);
La función restorecrtmode() permite regresar al modo texto, sin cerrar el
modo gráfico. Para volver de nuevo al modo gráfico se realizará una llamada a
la función setgraphmode(), pasándole como parámetro el valor devuelto por
getgraphmode(). La sintaxis es:
void restorecrtmode(void);
Ej.
#include <graphics.h>
...
void main(void)
{
int controlador = DETECT, modo;
int CodigoError;
initgraph(&controlador, &modo, “C:\\BC\\BGI”);
CodigoError=graphresult();
if (CodigoError != grOk)
{
printf(“Error:%s”,grapherrormsg(CodigoError);
getch(); exit(1);
}
...
restorecrtmode(); //Vuelve a modo texto.
...
setgraphmode(getgraphmode()); //Vuelve a gráficos,
//con el modo usado antes de restorecrtmode()
...
11
}
La función graphdefaults() restaura los valores gráficos por defecto:
activa pantalla completa, coloca cursor en columna 0 y fila 0, color de fondo y
texto, la paleta de colores, patrón y color de relleno, la fuente y la justificación
de caracteres. Su sintaxis es:
void graphdefaults(void);
3.5. Control de ventanas y posiciones.
El C proporciona una serie de funciones que permiten el control de la
consola a nivel de pixel. Debe tenerse en cuenta que la primera columna de
pixels es la 0, al igual que ocurre con la primera fila. Por tanto, esto es una
diferencia con el modo texto, en el que la primera columna y fila es la 1.
La función que permite borrar la pantalla completa en modo gráfico es
cleardevice(), colocando después el cursor en la posición 0,0. Borrar realmente
significa rellenar con el color de fondo establecido. Su sintaxis es:
void cleardevice(void);
La función setviewport() permite definir un rectángulo (ventana) de la
pantalla, para que ciertas funciones se restrinjan a él. Una vez definido un
rectángulo, la esquina 0,0 será la esquina superior izquierda del mismo, no de
la pantalla completa. El cursor será colocado en dicha esquina del rectángulo.
La sintaxis es:
void setviewport(int CI,int FS,int CD,int FI,int trunca);
Los parámetros CI, FS, CD y FI son la columna izquierda, fila superior,
columna derecha y fila inferior respectivamente, que delimitan la ventana. El
parámetro trunca puede valer 0 para indicar que al visualizar un texto, se
muestre completo aunque no quepa en la ventana definida. Si trunca toma un
valor distinto de 0, el texto que no quepa en la ventana no se visualizará, es
decir que se corta en los límites de la ventana.
La función getviewsettings() permite conocer las características de la
ventana activada, es decir los límites y el valor de trunca.
La función clearviewport() borrará la ventana definida con la función
anterior, colocando el cursor en la posición 0,0 de dicha ventana. La sintaxis
es:
void clearviewport(void);
La función moveto() coloca el cursor en una posición de pantalla. Su
sintaxis es:
void moveto(int x, int y); //x es columna, y es fila.
12
La función moverel() desplaza el cursor desde la posición actual el
número de columnas y filas indicadas. Su sintaxis es:
void moverel(int x, int y);
Las funciones getmaxx() y getmaxy() devuelven la columna y fila máxima
respectivamente con el sistema gráfico que se esté usando. Esta columna y fila
son relativas a la pantalla completa, no a la ventana activa. La sintaxis es:
int getmaxx(void);
int getmaxy(void);
Por ejemplo, en una pantalla de 640x480, getmaxx() devuelve 639 y
getmaxy() devuelve 479.
Las funciones getx() y gety() devuelven la columna y la fila
respectivamente de la posición donde se está situado en ese momento. Esta
columna y fila son relativas a la ventana activa, no a la pantalla completa. La
sintaxis es:
int getx(void);
int gety(void);
3.6. Manipulación de los colores.
Para cambiar los colores de los pixels y del fondo en modo gráfico deben
usarse funciones diferentes a las usadas en modo texto.
Los colores funcionan a través de paletas. Una paleta es un array
unidimensional de colores, que son los que se pueden usar en un momento
dado. Para poder usar un color que no está en la paleta, primero debe
guardarse dicho color en la paleta, para posteriormente ser utilizado. En el
modo EGA/VGA, la paleta contiene 16 colores, es decir el array tiene 16
elementos. Cada color tiene asociado un número entero entre 0 y 63.
El color de un pixel se especifica con un número de 0 a 15, que será la
posición de la paleta, entre los 16 elementos del array, donde está almacenado
el número entero que corresponde al color. El color que se almacene en la
posición 0 de la paleta será siempre utilizado como color de fondo.
La función getpalette() permite conocer la información actual de la
paleta, cargándola en una estructura cuyo tipo está predefinido. Este tipo se
llama struct palettetype y su formato es:
struct palettetype{
unsigned char size; //Nºcolores en la paleta.
char colors[ ];
//Array de la paleta. El tamaño
};
//depende del modo gráfico.
La sintaxis de la función getpalette() es:
13
void getpalette(struct palettetype *paleta);
Como puede verse, el parámetro paleta es un puntero a estructura del
tipo palettetype.
Ej.
struct palettetype paleta; //No es puntero, es struct.
...
getpalette(&paleta); //Se pasa un puntero a paleta.
//En paleta.size queda el número de colores de la
//paleta. En paleta.colors[i] quedan los colores que
//se están usando (i de 0 a paleta.size – 1).
La función getpalettesize() devuelve el número de elementos del array
de la paleta. Su sintaxis es:
int getpalettesize(void);
La función setpalette() permite cambiar un color de la paleta, es decir
modifica el valor de un elemento del array de la paleta. Su sintaxis es:
void setpalette(int elemento, int color);
Ej.
setpalette(0, 62); //En el elemento 0 de la paleta
//guarda el color 62. Por tanto,
//ahora el color de fondo será ese.
Al cambiar el color guardado en un elemento del array de la paleta,
todos los pixels que tuvieran el color de ese elemento (antes del cambio) se
actualizan en pantalla inmediatamente al nuevo color. Por ejemplo, al cambiar
el elemento 0 de la paleta, automáticamente se actualiza el nuevo color de
fondo en pantalla.
La función setallpalette() permite cambiar todos o algunos de los colores
de la paleta. Automáticamente se actualizan los pixels mostrados en pantalla a
los nuevos colores, por ejemplo si el color blanco se cambia a rojo, todo lo que
hubiera en pantalla en blanco se cambia a rojo después de ejecutar
setallpalette(). La sintaxis de esta función es:
void setallpalette(struct palettetype *paleta);
Ej.
struct palettetype paleta;
...
for (i = 0; i < 16; i++) //Se guardan en el array los
paleta.colors[i] = i + 20; //colores del 20 al 35.
14
setallpalette(&paleta);
Cuando no se desea modificar un color de la paleta, debe guardarse el
valor –1 en el elemento de la estructura paleta, antes de ejecutar setallpalette().
Por ejemplo, paleta.colors[5] = -1, setallpalette() no modificará el elemento 5
del array de la paleta.
La función getcolor() devuelve el color de dibujo que está activado en
ese momento. Su sintaxis es:
int getcolor(void);
La función getmaxcolor() devuelve el valor de color más alto que se
puede usar en el modo gráfico que se esté usando. Su sintaxis es:
int getmaxcolor(void);
La función setcolor() permite establecer un nuevo color de dibujo. Su
sintaxis es:
void setcolor(int colordibujo);
El parámetro colordibujo puede valer desde 0 hasta el valor que
devuelva getmaxcolor(). El cambio se actualiza inmediatamente en pantalla,
por ejemplo si el color de dibujo es blanco y se cambia a verde, todos los pixels
de color blanco en la pantalla se mostrarán en verde.
La función getbkcolor() devuelve el color de fondo que está activado en
ese momento. Su sintaxis es:
int getbkcolor(void);
La función setbkcolor() permite establecer un nuevo color de fondo, el
cual actualiza inmediatamente la pantalla. Esta función modifica la entrada 0 de
la paleta usada. Su sintaxis es:
void setbkcolor(int colorfondo);
La función setrgbpalette() permite la selección de 16 colores de un total
de 256 colores con un controlador VGA. Sólo 16 colores pueden utilizarse en
un momento determinado. Es decir, si se cambia alguno de esos 16 colores en
la paleta, los pixels de pantalla que tuvieran el color que se ha cambiado,
automáticamente se actualizan al nuevo color. Su sintaxis es:
void setrgbpalette(int NColor,int rojo,int verde,int azul);
En el parámetro NColor se indica el número de color al que se le va a
dar una mezcla de rojo, verde y azul. Es decir, NColor no es la posición de la
paleta. Los parámetros rojo, verde y azul indican los componentes de color a
guardar en el color indicado en NColor. Por ejemplo, si el color 63 es el blanco
15
y se ejecuta setrgbpalette(63, 20, 20, 20), ahora el 63 será un tono de gris. Si el
color 63 está almacenado en la posición 15 de la paleta, para usar ese tono de
gris deberá ejecutarse setcolor(15). Todo lo que hubiera en pantalla en color
blanco (63) se cambiará a gris.
Ej.
struct palettetype paleta;
getpalette(&pal);
setrgbpalette(pal.colors[15],32,32,32);
//El color de la posición 15 de la paleta será gris.
setcolor(15); //Activa el nuevo color gris.
Los parámetros rojo, verde y azul son de tipo int, es decir que ocupan 2
bytes. Sólo se usa el byte menos significativo, y dentro de ese byte sólo se
cargan en la paleta los 6 bits más significativos, por tanto el rango de valores
para cada componente de color será de 0 a 63 (con 6 bits se pueden codificar
64 valores distintos).
3.7. Visualización de pixels y figuras.
La función putpixel() pinta un píxel con un color. Su sintaxis es:
void putpixel(int x, int y, int color);
Los parámetros x e y son la columna y fila respectivamente del píxel que
se desea pintar, mientras que color es el que se utiliza para pintarlo.
La función getpixel() devuelve el color de un píxel. Su sintaxis es:
int getpixel(int x,int y);
Los parámetros x e y son la columna y fila respectivamente del píxel
cuyo color desea conocerse.
Ej.
putpixel(200, 300, 15); //Pinta de color 15.
color = getpixel(200,300); //En color queda un 15.
La función getimage() permite grabar en memoria una imagen mostrada
en pantalla. Su sintaxis es:
void getimage(int CI,int FS, int CD, int FI, void *imagen);
Los parámetros CI y CD indican la columna izquierda y derecha
respectivamente del tramo de pantalla a grabar. Los parámetros FS y FI indican
la fila superior e inferior del tramo de pantalla a grabar. El parámetro imagen
debe ser un puntero a una zona de memoria con el tamaño suficiente para
almacenar la imagen seleccionada. Para conocer el tamaño en bytes que
ocupará una imagen puede utilizarse la función imagesize(), cuya sintaxis es:
16
int imagesize(int CI,int FS,int CD, int FI);
Los parámetros CI, CD, FS e FI tienen el mismo significado que en el
caso anterior, es decir indican los límites de la imagen.
Para volver a mostrar en pantalla una imagen grabada en memoria se
utiliza la función putimage(). Su sintaxis es:
void putimage(int CI, int FS, void *imagen, int opc);
Como puede verse, aquí sólo se especifica la esquina superior izquierda
(CI y FS) donde comienza a mostrarse la imagen. El parámetro imagen será el
puntero usado en getimage(). El parámetro opc permite cambiar el color de la
imagen original cuando se va a mostrar de nuevo con putimage(). Cuando opc
es 0, no cambia el color de la imagen original.
Ej.
void *p; //puntero sin especificar a qué tipo apunta.
int nbytes;
nbytes = imagesize(10,10,40,50);
p = malloc(nbytes);
getimage(10, 10, 40, 50, p);
putimage(300, 300, p, 0);
La función line() dibuja una línea entre dos puntos dados con el color,
grosor y estilo de línea establecidos. Se le pasa como parámetros la columna y
fila del punto inicial (CI y FI) y del punto final (CF y FF). Su sintaxis es:
void line(int CI, int FI, int CF, int FF);
La función lineto() dibuja una línea partiendo desde la posición donde
esté el cursor hasta un punto cuya columna (CF) y fila (FF) se pase como
parámetros. Su sintaxis es:
void lineto(int CF, int FF);
La función linerel() dibuja una línea partiendo desde la posición donde
esté el cursor hasta un punto final. Este punto final se especifica pasando 2
parámetros a la función que son la distancia relativa desde la posición del
cursor en columnas (DC) y en filas (DF). Su sintaxis es:
void linerel(int DC, int DF);
Por ejemplo, si el cursor está en la posición 120,200 y se ejecuta
linerel(40,70), se pinta una línea desde el punto 120,200 hasta el punto
160,270, donde 160=120+40 y 270=200+70.
La función rectangle() permite dibujar un rectángulo, pasándole como
parámetro la columna y fila de la esquina superior izquierda (CI y FS) y de la
17
esquina inferior derecha (CD y FI). Se usará el color, grosor y estilo de línea
activos. Su sintaxis es:
void rectangle(int CI, int FS, int CD, int FI);
La función bar() permite dibujar una barra o rectángulo sin borde,
especificando las coordenadas de las esquinas superior izquierda (CI y FS) e
inferior derecha (CD y FI). Se rellena con el patrón y color de relleno activos. Si
se desea pintar con borde, se puede usar la función bar3d() con profundidad 0.
La sintaxis de la función bar() es:
void bar(int CI, int FS, int CD, int FI);
La función bar3d() permite dibujar una barra en 3 dimensiones,
especificando las coordenadas de las esquinas superior izquierda (CI y FS) e
inferior derecha (CD y FI), así como la profundidad y si se desea pintar la cara
superior. Se rellena con el patrón y color de relleno activos. La línea del borde
se pinta con el estilo de línea activo. Como referencia se puede decir que una
profundidad razonable es el 25% de la anchura de la barra, es decir (CD-CI)/4.
Su sintaxis es:
void bar3d(int CI,int FS,int CD,int FI,int Prof, int Cara);
El parámetro Cara se usa para pintar la línea correspondiente a la cara
superior, cuando vale 1, o para no pintarla, cuando vale 0. Esto permite apilar
una barras con otras, pintando sólo la cara superior de la barra más alta.
La función arc() permite dibujar un arco. Su sintaxis es:
void arc(int x, int y, int AnguloI,int AnguloF, int radio);
Los parámetros x e y indican la columna y fila respectivamente del
centro del arco. Los parámetros AnguloI y AnguloF indican los ángulos de inicio
y final del arco, expresados en grados (de 0º a 360º en sentido contrario a las
agujas del reloj). Finalmente el parámetro radio especifica el radio del arco.
La función pieslice() permite dibujar un arco y a continuación lo rellena
del color y patrón de relleno activos. Su sintaxis es idéntica a la función arc():
void pieslice(int x,int y,int AnguI,int AnguF, int radio);
La función circle() permite dibujar un círculo, especificando las
coordenadas del centro y el radio. Su sintaxis es:
void circle(int x, int y, int radio);
Cuando los círculos no se muestran perfectamente redondos, debe
usarse la función setaspectratio().
18
La función ellipse() permite dibujar un arco elíptico, especificando los
mismos parámetros que en la función arc(), excepto que se deben indicar dos
radios, el radio del ancho de la elipse y el radio de alto. Su sintaxis es:
void ellipse(int x,int y,int AI,int AF,int radX,int radY);
La función sector() permite dibujar un arco elíptico y después lo rellena
con el patrón y color de relleno activos. Se especifican los mismos parámetros
que en la función ellipse(). Por tanto, su sintaxis es:
void sector(int x,int y,int AI,int AF,int radX,int radY);
La función fillellipse() permite dibujar una elipse y rellenarla con el patrón
y color de relleno activos. Se le deben pasar las coordenadas del centro y los
radios de ancho y de alto de la elipse. Su sintaxis es:
void fillellipse(int x,int y, int radioX,int radioY);
La función drawpoly() permite dibujar un polígono cualquiera, es decir
una serie de líneas unidas, especificando una serie de parejas de puntos, es
decir una serie de coordenadas x,y. Cada pareja x,y indica donde finaliza una
línea y comienza la siguiente. Su sintaxis es:
void drawpoly(int Npuntos, int *poligono);
El parámetro Npuntos indica el número de vértices del polígono, es decir
el número de parejas de puntos, que será uno más que el número de líneas
que forman el polígono. El parámetro poligono es un puntero a la serie de
parejas de puntos, es decir a la serie de coordenadas x,y. Para dibujar un
polígono cerrado, la última pareja de puntos debe coincidir con la primera
pareja y el parámetro Npuntos será uno más que el número de vértices del
polígono.
Ej. Pintar un exágono (6 líneas y 6 vértices).
int poligono[]={300,200, //Vértice superior
320,220,
320,240,
300,260, //Hay 7 parejas de números.
280,240,
280,220,
300,200};//Coincide con vert.superior.
drawpoly(7, poligono);
//El parámetro poligono es un puntero,ya que es array.
La función fillpoly() es idéntica a drawpoly(), excepto que después de
pintar el polígono, lo rellena con el patrón y color de relleno activos.
La función floodfill() permite rellenar, con el patrón y color de relleno
activos, un área cerrada de la pantalla. Su sintaxis es:
19
void floodfill(int x,int y, int color);
Los parámetros x e y indican un punto cualquiera del área cerrada,
rellenándose desde ese punto, en todas direcciones, hasta encontrar el color
indicado en el parámetro color. Si este color no se encuentra, se rellena la
pantalla completa. Si el punto x,y está fuera del área cerrada, se rellena el resto
de la pantalla.
La función setfillstyle() permite especificar un patrón y color de relleno,
que afectará a todas las funciones que dibujen relleno. Su sintaxis es:
void setfillstyle(int patron, int color);
El parámetro patron debe ser un valor de 0 a 11, donde el 0 significa sin
relleno (se usa para rellenar con el color de fondo activo). Los valores de 1 a 11
son distintos patrones predefinidos. Si se le pasa un valor erróneo, no se altera
el patrón activo. El parámetro color es cualquier posición de la paleta.
La función getfillsettings() nos permite conocer el patrón y color de
relleno activos. Su sintaxis es:
void getfillsettings(struct fillsettingstype *pfill);
El único parámetro es un puntero a una estructura de tipo predefinido,
struct fillsettingstype, cuyo formato sólo incluye 2 enteros, que coinciden con
los 2 parámetros de la función setfillstyle():
struct fillsettingstype {
int pattern;
int color; };
Ej.
struct fillsettingstype relleno;
getfillsettings(&relleno); //Se pasa un puntero, la
//dirección de la estructura relleno.
//En relleno.patron queda el valor del patrón activo.
//En relleno.color queda el color de relleno activo.
La función setlinestyle() permite especificar el estilo y grosor de línea,
afectando a todas las funciones que dibujen líneas. Su sintaxis es:
void setlinestyle(int estilo,
unsigned int EstiloUsuario,
int grosor);
Como puede verse, tiene 3 parámetros. El parámetro estilo puede valer
de 0 a 3, siendo 0 una línea normal. El parámetro grosor puede tomar sólo dos
valores, 1 o 3. El parámetro EstiloUsuario se utiliza cuando estilo vale 4, con el
que se permite al usuario definir su propio estilo de línea.
20
La función getlinesettings() permite conocer el estilo y ancho de línea
activos. Su sintaxis es:
void getlinesettings(struct linesettingstype *plinea);
El único parámetro es un puntero a una estructura de tipo predefinido,
struct linesettingstype, que consta de 3 campos, los cuales coinciden con los 3
parámetros de la función setlinestyle():
struct linesettingstype {
int estilo;
unsigned int EstiloUsuario;
int grosor; };
3.8. Entrada y salida en modo gráfico.
La función gettextsettings() nos permite conocer las características de
visualización de texto que están activas. Estas características son: fuente,
dirección de visualización, tamaño de carácter, justificación horizontal y
justificación vertical. Su sintaxis es:
void gettextsettings(struct textsettingstype *ptext);
El único parámetro es un puntero a una estructura de tipo predefinido,
struct textsettingstype. Esta estructura tiene 5 campos de tipo int donde se
almacenan las 5 características de texto mencionadas previamente. El formato
es:
struct
int
int
int
int
int
textsettingstype {
font;
direction;
charsize;
horiz;
vert; } ;
El campo font puede tomar un valor de 0 a 4, el 0 indica la fuente
normal y del 1 al 4 son fuentes trazadas (“stroked”). El campo direction puede
valer 0 para visualizar en dirección horizontal de izquierda a derecha, o 1 para
visualizar en dirección vertical de abajo a arriba, o sea girando 90º el texto
horizontal (el extremo derecho pasa arriba y el izquierdo pasa abajo). El campo
charsize puede tomar un valor de 0 a 10. Para la fuente normal (valor 0 de
fuente), un charsize de 0 o 1 indica 8x8 pixels, el 2 es 16x16, el 3 es 24x24,
hasta el 10 que es 80x80 pixels. Para las fuentes trazadas (valor de fuente
entre 1 y 4), un charsize de 1 a 10 indica el factor de aumento, siendo el valor 4
el factor de aumento por defecto. Cuando charsize vale 0, las fuentes trazadas
se visualizan con el tamaño por defecto (factor de aumento 4) o con un tamaño
definido por el usuario (ver función setusercharsize()). El campo horiz puede
valer 0, 1 o 2, para justificar horizontalmente a la izquierda, en el centro o a la
derecha respectivamente. El campo vert puede valer 0, 1 o 2, para justificar
21
verticalmente abajo, al centro o arriba respectivamente. Estas justificaciones se
aplican respecto a la posición del cursor, por ejemplo si la justificación
horizontal se establece a 1 (en el centro) y el cursor está en el píxel de la
columna 100, el texto se visualiza de forma que quede centrado en la columna
100, por lo que se visualiza desde la posición 100 hacia la izquierda la mitad
del texto y hacia la derecha la otra mitad.
Ej.
struct textsettingstype infotexto; //No es puntero.
gettextsettings(&infotexto); //Se pasa la dirección
//de la estructura, es decir un puntero.
//En infotexto.font se graba la fuente activa.
//En infotexto.vert se graba la justificación vertical
La función settextstyle() permite activar o establecer las 3 primeras
características de texto citadas previamente, es decir la fuente, la dirección y el
tamaño, que son pasadas como parámetros. Su sintaxis es:
void settextstyle(int fuente,int direccion,int tama);
La función setusercharsize() permite definir un factor de aumento para
las fuentes trazadas (“stroked”, fuente activa entre 1 y 4). Este factor estará
activo si el tamaño de fuente (parámetro tama) se ha establecido a 0 con la
función settextstyle(). La sintaxis es:
void setusercharsize(int multx, int divx,
int multy, int divy);
Los 2 primeros parámetros, multx y divx, indican el aumento a lo ancho
respecto al tamaño por defecto (un charsize de 4). Por ejemplo, si multx vale 2
y divx vale 1, el ancho se multiplica con 2/1 (es decir, por 2), por lo que la
fuente será el doble de ancha que el ancho por defecto. Si multx vale 1 y divx
vale 3 (1/3), la fuente será 3 veces menos ancha que el ancho por defecto. En
cuanto al alto de la fuente se aplica un tratamiento similar. Por ejemplo, si multy
vale 4 y divy 2 (4/2=2), la fuente será el doble de alta que el alto por defecto.
Para conocer cuántos pixels va a ocupar un texto al visualizarlo en
pantalla, pueden usarse las funciones textheight() y textwidth(), que nos
devuelven el número de pixels de alto y ancho respectivamente. Para calcular
dicho número de pixels, estas funciones tienen en cuenta la fuente y el factor
de multiplicación activos. La sintaxis es:
int textheight(char *cad); //ALTO
int textwidth (char *cad); //ANCHO
Como se ve, el parámetro para ambas funciones es un puntero a char,
es decir el nombre de la cadena donde está el texto que se quiere visualizar.
Ej.
int alto, ancho;
22
char cadena=”LISTADO DE ARTICULOS”;
alto = textheight(“LISTADO DE CLIENTES”);
ancho = textwidth (cadena);
Para una fuente y factor de multiplicación activos, todos los caracteres
ocupan el mismo número de pixels de alto, mientras que el ancho depende del
carácter. Por ejemplo, los caracteres “Ñ” y “_” ocupan lo mismo de alto y los
caracteres “i” y “O” no ocupan lo mismo de ancho.
La función settextjustify() permite establecer la justificación horizontal y
vertical, pasándole para ello 2 parámetros enteros. La sintaxis es:
void settextjustify(int JHoriz, int JVert);
Los valores posibles para los parámetros JHoriz y JVert son 0, 1 y 2,
para justificar horizontalmente a la izquierda, en el centro o a la derecha, y
verticalmente abajo, al centro o arriba respectivamente. Las justificaciones por
defecto son la horizontal a la izquierda (JHoriz a 0) y la vertical arriba (JVert a
2).
La función outtext() permite visualizar una cadena (texto) en modo
gráfico, a partir de la posición donde esté el cursor, con las características de
texto que estén activas. Cuando se usa justificación horizontal a la izquierda y
dirección de visualización horizontal (es decir, los valores por defecto), la
posición del cursor avanza automáticamente, en otros casos permanece
inalterada, el cursor no se coloca al final de lo visualizado, por lo que se
podrían visualizarse unas cadenas sobre otras. Su sintaxis es:
void outtext(char *cad);
El parámetro cad es la cadena que se desea visualizar.
Ej.
char cadena[]=”TECLEE “;
moveto(100,100);
outtext(cadena); //Se le puede pasar un array de char.
outtext(“NOMBRE:”); //Se le pasa un mensaje.
La función outtextxy() permite visualizar una cadena de texto en una
posición de pantalla, pasándole como parámetro la columna, la fila y la cadena.
Su sintaxis es:
void outtextxy(int col, int fila, char *cad);
Para visualizar datos que no son cadenas, como números enteros o
reales, pueden convertirse a cadenas utilizando la función sprintf(), que tiene la
misma sintaxis que la función printf(), pero en lugar de enviar la información a
la pantalla la graba en una cadena. Una vez que se tiene la información en la
cadena, podrá visualizarse con outtext() o outtextxy(). La sintaxis de sprintf()
es:
23
int sprintf(char *cad, char *control, argumentos);
Los dos últimos parámetros (char *control, argumentos) son los mismos
que usa la función printf(). En el parámetro cad se graba lo que el printf
visualizaría en pantalla. El valor entero que devuelve es el número de
caracteres que graba en la cadena.
Ej.
char cad[80];
int edad = 20;
float sueldo = 1200.00;
sprintf(cad,”Edad: %2d Sueldo: %7.2f”, edad, sueldo);
//En cad queda: “Edad: 20 Sueldo: 1200.00”
outtext(cad);
La entrada de datos en modo gráfico deberá implementarse controlando
cada carácter recogido con getch() y mostrándolo en el formato deseado.
24
EJERCICIOS - CAPITULO 15:
Realizar los siguientes algoritmos en pseudocódigo y en C:
1. Programa que dibuja una línea girando.
2. Función para realizar entrada de datos en modo gráfico, es decir como la
función scanf() pero con caracteres gráficos.
3. Función que visualiza texto con sombra en modo gráfico.
25
Descargar