3.8. Aritmética.En esta sección
Deitel introduce las operaciones aritméticas básicas en
C#.
Hay toda una discusión sobre
precedencia de operadores aritméticos.
Nosotros vamos a postergar estas cuestiones teóricas hasta entrar en el capitulo 4.El libro propone hacer unos calculitos en la
consola.
Lo que haremos será muy diferente a lo que propone el libro.
Vamos a desarrollar una aplicación
GUI con
System.Windows.Forms, que servirá para hacer operaciones aritméticas.
Más concretamente, vamos a hacer una modesta pero simpática calculadora.Antes de lanzarnos a programar como locos, tenemos mucho trabajo previo con lápiz y papel.
\( \bullet \) Lo primero que debemos llevar a cabo es el diseño del proyecto.Empecemos con el final:
los objetivos:
- Realizar un programa con interface gráfica en Windows, usando System.Windows.Forms.
- Toda la aplicación debe desarrollarse en una sola ventana, y todos los controles de la misma tienen que estar bien visibles y ser simples de configurar por nosotros en el archivo de código.
- Desde el punto de vista de quien usará nuestro programa, la mecánica de uso tiene que ser clara y simple. El aspecto tiene que ser ordenado, y la interacción tiene que ser natural.
- Tiene que haber un botón para salir del programa en forma ordenada.
Detalles de la calculadora:- Habrá varios casilleros en donde podrán escribirse números.
El usuario tiene que poder editar estos casilleros y poner el número que más le guste, y cuando lo desee.
Por lo tanto, el widget a usar en este caso serán las cajas de texto, que en la librería System.Windows.Forms reciben el nombre de TextBox.
- Esos casilleros tendrán nombres, como a, b, c, etc., y se indicará el nombre debajo del casillero.
Pero para poder hacer esto es menester usar algún widget, concretamente, una etiqueta. En S.W.F. se llaman Label. - Deseamos agregar unos botones para indicar las operaciones aritméticas.
El widget adecuado es un botón, que en S.W.F. corresponde a un Button.
- También pondremos un cartelito informativo, que nos deje constancia de la operación que estamos haciendo, y el resultado que nos da. Esto lo pondremos en una etiqueta.
- También agregaremos un casillero z que mostrará el resultado de las operaciones.
Aún asi, ese casillero también podrá editarse, y tendrá debajo una etiqueta que diga "z".
- Habrá un botón que permita limpiar todos los datos, poniéndolos a 0.
- Y finalmente un botón para terminar el programa.
Sobre la mecánica de los cálculos, hay varias posibilidades para construir una calculadora...
Lo que pretendemos hacer es:- Llevar a cabo operaciones aritméticas de una en una, como una calculadora corriente.
Esto evita además toda la discusión de la precedencia de operadores, o el uso de paréntesis, etc.
- Para realizar un cálculo, se rellenan los casilleros numéricos, luego se hace click sobre uno de los valores deseados, a continuación sobre el botón de la operación deseada, y por último click sobre el segundo operando. Para terminar, se hará click sobre un botón con el signo =.
- Si en vez de presionar el botón = se presiona algún otro botón de operación, se hace igual el cálculo, pero se sigue operando.
Para que esto funcione, nos ayudaremos de dos variables internas: operando y resultado.
El primer operando se guardará en la variable resultado, y el segundo en la variable operando.
Una vez efectuado el cálculo, se pone el resultado en la variable resultado.
A medida que los cálculos continúan, los nuevos valores elegidos se guardan en operando.
El cálculo se efectúa siempre entre el "último resultado" y el "siguiente operando".
- Para simplificar la mecánica anterior, al accionar el botón = no vamos a considerar que se acabaron las operaciones.. sino que se efectúa una operación especial, que consiste en "dar como resultado al último operando clickeado".
- También se debe manejar apropiadamente la situación de una división por 0.
En ese caso, se dejará todo como estaba "hasta ese momento", al tiempo que se mostrará un cartel indicando: "Error de División por 0".
Aclaración importante: los datos que usaremos para los cálculos serán
números enteros. Concretamente, el tipo de los números será
int.
Esto trae como consecuencia que las divisiones son
"enteras", o sea, no tienen parte decimal.
Además, hay un rango limitado de valores, por lo que al poner números muy grandes podrán obtenerse resultados equivocados.
Toda especificidad técnica la postergamos a futuro...
En particular, si en los casilleros de números se colocan datos que no son números enteros, el programa terminará abruptamente con algún error.
Vamos a los detalles de la implementación.El lenguaje
C# trabaja con
clases. Todo debe hacerse a través de una
clase.
En particular, debe haber una
clase donde resida el método
Main, que es el
punto de entrada del programa, o sea, el lugar donde el programa comienza a ejecutarse.
Allí pondremos una sola línea, que consistirá en una llamada al método que inicia la
ventana de la aplicación para
Windows, nuestro ya conocido
Application.Run().
Click para ver código
static class VS0308GUISWF_Calculadora
{
static void Main()
{
Application.Run( new Formulario_principal() );
}
}
(El nombre VS0308GUISWF_Calculadora significa: "aplicación realizada en Visual Studio, captiulo 3, sección 8, GUI con System.Windows.Forms, Calculadora")
Claro que, para llamar a ese método, hace falta haber definido una
clase "formulario", que es una derivada de la
clase System.Windows.Forms.Form.
En esa clase hay un método de "arranque", el constructor del mismo nombre de la clase del
formulario. Allí pondremos todas las inicializaciones de los
widgets de nuestra aplicación.
En el resto de la clase del
formulario vamos a poner las declaraciones de unas variables internas de la clase, entre las que habrá variables para albergar los
widgets y variables para efectuar las operaciones de la calculadora.
También escribiremos los métodos del
formulario. Entre ellos los hay de dos tipos: los que corresponden a
una "reacción" ante un evento en un widget (por ahora, simplemente hacer clic en un botón o una etiqueta), y métodos para manejar las operaciones de la calculadora.
Nuestra
clase para el formulario se llamará
Formulario_principal.
Veamos las declaraciones de las variables que albergarán los
widgets:
Click para ver código
public class Formulario_principal : Form
{
// ..............
private TextBox caja_texto_a;
private TextBox caja_texto_b;
private TextBox caja_texto_c;
private TextBox caja_texto_d;
private TextBox caja_texto_e;
private TextBox caja_texto_f;
private TextBox caja_texto_z;
private Label etiqueta_a;
private Label etiqueta_b;
private Label etiqueta_c;
private Label etiqueta_d;
private Label etiqueta_e;
private Label etiqueta_f;
private Label etiqueta_z;
private Button boton_mas;
private Button boton_menos;
private Button boton_por;
private Button boton_sobre;
private Button boton_resto;
private Button boton_igual;
private Label informacion;
private Label ayuda;
private Button borrar_todo;
private Button terminar_programa;
// ........................
}
La palabra private se usa para encapsular los datos, esto es, para que las variables allí declaradas no sean visibles ni accesibles desde otras partes del programa.
Toda manipulación de esas variables deberá hacerse desde dentro de la clase Formulario_principal.
Los tipos de datos TextBox, Label, Button, son clases que están definidas en el espacio de nombres System.Windows.Forms.
La manera exacta de invocar a Label, por ejemplo, sería escribiendo System.Windows.Forms.Label.
Para evitarnos todo ese prefijo tan largo, basta que indiquemos al principio de nuestro programa que vamos a usar ese espacio de nombres, mediante una sentencia using:
using System.Windows.Forms;
\( \bullet \) Si bien las variables que albergarán los
widgets han sido declaradas... tienen un valor
nulo aún. Se les debe adjudicar un
objeto de la clase a la que cada uno pertenece. Ese
objeto debe crearse mediante una sentencia
new.
En el
método constructor Formulario_principal() vamos a agregar las inicializaciones de todos esos
widgets, empezando por las creaciones de los objetos correspondientes:
Click para ver código
public class Formulario_principal : Form
{
// ..............
public Formulario_principal()
{
// .........................
this.caja_texto_a = new TextBox();
this.caja_texto_b = new TextBox();
this.caja_texto_c = new TextBox();
this.caja_texto_d = new TextBox();
this.caja_texto_e = new TextBox();
this.caja_texto_f = new TextBox();
this.caja_texto_z = new TextBox();
this.etiqueta_a = new Label();
this.etiqueta_b = new Label();
this.etiqueta_c = new Label();
this.etiqueta_d = new Label();
this.etiqueta_e = new Label();
this.etiqueta_f = new Label();
this.etiqueta_z = new Label();
this.boton_mas = new Button();
this.boton_menos = new Button();
this.boton_por = new Button();
this.boton_sobre = new Button();
this.boton_resto = new Button();
this.boton_igual = new Button();
this.informacion = new Label();
this.ayuda = new Label();
this.borrar_todo = new Button();
this.terminar_programa = new Button();
// .....................
}
}
Ahora que los objetos ya han sido creados, podemos configurarlos.Para ello se les debe dar valores a los atributos de
cada objeto.
- El atributo Text de cada objeto sirve para poner un texto en el espacio ocupado por el widget correspondiente.
- Los atributos Width, Height, indican el ancho y el alto del widget en pantalla.
- El atributo Location indica la posición donde queremos que aparezca el widget, en coordenadas relativas al formulario.
La medida se hace en pixels, y las coordenadas verticales comienzan arriba en 0 y avanzan hacia abajo con signo positivo.
Para expresar adecuadamente un par de coordenadas, se debe usar un tipo de datos especialmente construido a este propósito.
No nos preocupemos por los detalles de esto.
Basta saber que con el uso del método System.Drawings.Point ( x, y ) se obtiene un valor del tipo correcto, asignable a Location.
Aquí van las inicializaciones:
Click para ver código
// .......................
// Ancho en pixels de los widgets
this.caja_texto_a.Width = 45;
this.caja_texto_b.Width = 45;
this.caja_texto_c.Width = 45;
this.caja_texto_d.Width = 45;
this.caja_texto_e.Width = 45;
this.caja_texto_f.Width = 45;
this.caja_texto_z.Width = 145;
this.etiqueta_a.Width = 45;
this.etiqueta_b.Width = 45;
this.etiqueta_c.Width = 45;
this.etiqueta_d.Width = 45;
this.etiqueta_e.Width = 45;
this.etiqueta_f.Width = 45;
this.etiqueta_z.Width = 145;
this.boton_mas.Width = 30;
this.boton_menos.Width = 30;
this.boton_por.Width = 30;
this.boton_sobre.Width = 30;
this.boton_resto.Width = 30;
this.boton_igual.Width = 50;
this.informacion.Width = 200;
this.ayuda.Width = 400;
this.ayuda.Height = 100;
this.borrar_todo.Width = 200;
this.terminar_programa.Width = 200;
// Posición esquina sup. izq. widgets respecto formulario
this.caja_texto_a.Location = new System.Drawing.Point(0,0);
this.caja_texto_b.Location = new System.Drawing.Point(50, 0);
this.caja_texto_c.Location = new System.Drawing.Point(100, 0);
this.caja_texto_d.Location = new System.Drawing.Point(150, 0);
this.caja_texto_e.Location = new System.Drawing.Point(200, 0);
this.caja_texto_f.Location = new System.Drawing.Point(250, 0);
this.caja_texto_z.Location = new System.Drawing.Point(0, 100);
this.etiqueta_a.Location = new System.Drawing.Point(0, 20);
this.etiqueta_b.Location = new System.Drawing.Point(50, 20);
this.etiqueta_c.Location = new System.Drawing.Point(100, 20);
this.etiqueta_d.Location = new System.Drawing.Point(150, 20);
this.etiqueta_e.Location = new System.Drawing.Point(200, 20);
this.etiqueta_f.Location = new System.Drawing.Point(250, 20);
this.etiqueta_z.Location = new System.Drawing.Point(0, 120);
this.boton_mas.Location = new System.Drawing.Point(100, 50);
this.boton_menos.Location = new System.Drawing.Point(130, 50);
this.boton_por.Location = new System.Drawing.Point(160, 50);
this.boton_sobre.Location = new System.Drawing.Point(190, 50);
this.boton_resto.Location = new System.Drawing.Point(220, 50);
this.boton_igual.Location = new System.Drawing.Point(250, 50);
this.informacion.Location = new System.Drawing.Point(0, 80);
this.ayuda.Location = new System.Drawing.Point(0, 150);
this.borrar_todo.Location = new System.Drawing.Point(0, 250);
this.terminar_programa.Location = new System.Drawing.Point(0, 300);
// ......
Mediante una sentencia
using podríamos aliviar el uso excesivo del prefijo
System.Drawing., pero no vamos a hacer esto...
Los
espacios de nombres sirven para no mezclar identificadores definidos en contextos diferentes, a fin de tener orden y disponibilidad de identificadores.
Buscar el
"alivio" a través de
using atenta contra este orden.
Tratemos de no abusar de la sentencia
using, llamando tan sólo a los
espacios de nombres más corrientes en nuestras aplicaciones.
Los casilleros numéricos de nuestra calculadora contendrán inicialmente el valor
"0".
Las etiquetas contendrán la información que les corresponde, así como los botones.
Esto lo inicializamos así:
Click para ver código
// .............................
this.caja_texto_a.Text = "0";
this.caja_texto_b.Text = "0";
this.caja_texto_c.Text = "0";
this.caja_texto_d.Text = "0";
this.caja_texto_e.Text = "0";
this.caja_texto_f.Text = "0";
this.caja_texto_z.Text = "0";
this.etiqueta_a.Text = "a";
this.etiqueta_b.Text = "b";
this.etiqueta_c.Text = "c";
this.etiqueta_d.Text = "d";
this.etiqueta_e.Text = "e";
this.etiqueta_f.Text = "f";
this.etiqueta_z.Text = "z (resultado)";
this.boton_mas.Text = "+";
this.boton_menos.Text = "-";
this.boton_por.Text = "*";
this.boton_sobre.Text = "/";
this.boton_resto.Text = "%";
this.boton_igual.Text = "=";
this.informacion.Text = "Programa iniciado";
this.ayuda.Text = "(aquí irá texto de ayuda de uso del programa)"
this.borrar_todo.Text = "Click aquí para borrar datos";
this.terminar_programa.Text = "Click aquí para terminar programa";
// ...................
Tenemos que
"atar" las etiquetas y botones a acciones que respondan al
"click" del usuario final de nuestro programa.
Esto se hace mediante una llamada a
EventHandler.
Por ahora no entramos en más detalles, y lo usamos tal como figura en el siguiente código, sin preguntar por las cosas extrañas que aparecen en las líneas (observar el uso de
+=):
Click para ver código
// .................
this.etiqueta_a.Click += new EventHandler(this.Elegir_Casillero_a);
this.etiqueta_b.Click += new EventHandler(this.Elegir_Casillero_b);
this.etiqueta_c.Click += new EventHandler(this.Elegir_Casillero_c);
this.etiqueta_d.Click += new EventHandler(this.Elegir_Casillero_d);
this.etiqueta_e.Click += new EventHandler(this.Elegir_Casillero_e);
this.etiqueta_f.Click += new EventHandler(this.Elegir_Casillero_f);
this.boton_mas.Click += new EventHandler(this.Elegir_Operacion_mas);
this.boton_menos.Click += new EventHandler(this.Elegir_Operacion_menos);
this.boton_por.Click += new EventHandler(this.Elegir_Operacion_por);
this.boton_sobre.Click += new EventHandler(this.Elegir_Operacion_sobre);
this.boton_resto.Click += new EventHandler(this.Elegir_Operacion_resto);
this.boton_igual.Click += new EventHandler(this.boton_igual_Click);
this.ayuda.Click += new EventHandler(this.ayuda_Click);
this.borrar_todo.Click += new EventHandler(this.borrar_todo_Click);
this.terminar_programa.Click += new EventHandler(this.terminar_programa_Click);
// ..................
Hemos hecho referencia a una larga lista de métodos.
A todos ellos tendremos que definirlos más adelante...
Ahora especificamos el tamaño de la
ventana de la aplicación:
this.ClientSize = new System.Drawing.Size(400, 400);
Y por último, ya que tenemos configurados todos los
widgets, los
"atamos" finalmente al
formulario para que aparezcan en la
ventana de la aplicación:
Click para ver código
// .....................
this.Controls.Add(this.caja_texto_a);
this.Controls.Add(this.caja_texto_b);
this.Controls.Add(this.caja_texto_c);
this.Controls.Add(this.caja_texto_d);
this.Controls.Add(this.caja_texto_e);
this.Controls.Add(this.caja_texto_f);
this.Controls.Add(this.caja_texto_z);
this.Controls.Add(this.etiqueta_a);
this.Controls.Add(this.etiqueta_b);
this.Controls.Add(this.etiqueta_c);
this.Controls.Add(this.etiqueta_d);
this.Controls.Add(this.etiqueta_e);
this.Controls.Add(this.etiqueta_f);
this.Controls.Add(this.etiqueta_z);
this.Controls.Add(this.boton_mas);
this.Controls.Add(this.boton_menos);
this.Controls.Add(this.boton_por);
this.Controls.Add(this.boton_sobre);
this.Controls.Add(this.boton_resto);
this.Controls.Add(this.boton_igual);
this.Controls.Add(this.informacion);
this.Controls.Add(this.ayuda);
this.Controls.Add(this.borrar_todo);
this.Controls.Add(this.terminar_programa);
// .........................
Hemos definido la interface gráfica de la aplicación.Ahora vamos a agregar la parte operativa.Les aviso que va a quedar feo... pero simple.
Al final haremos una autocrítica.
Por ahora vayamos a los hechos: que la aplicación funcione.(El desarrollo de esto continúa en el post siguiente)