Autor Tema: Dictado del Curso de C# (Deitel)

0 Usuarios y 1 Visitante están viendo este tema.

22 Enero, 2010, 03:13 am
Respuesta #10

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
3.6. Otra aplicación C#: Sumando enteros.

Como siempre, haremos un poco más que lo propone Deitel en su libro.

En esta entrega haremos entrada, procesamiento y salida de datos.
Para entender claramente la mecánica, hacemos una aplicación simple en la consola.
Luego, haremos la misma aplicación, pero funcionando ya con ventanitas y controles de Windows, o sea, una aplicación GUI. Lo haremos en los dos estilos: System.Windows.Forms y Gtk#.

En general, hagamos estas apreciaciones:

  • Para procesar ciertos datos, se necesita primero asignarles un lugar en memoria, y darles un tipo de datos. Esto se hace mediante declaraciones de variables.
    Nuestras variables serán números enteros, así que las declararemos de tipo int.
  • Para que el usuario ingrese datos, se le debe informar más o menos lo que se espera de él.
  • Los datos ingresados en general vienen en formato de cadenas de caracteres.
    Para poder hacer cálculos es necesario hacer una conversión de tipo, transformando la cadena de caracteres en un número entero.
  • Los resultados también ocupan memoria... Declaremos variables para ellos.
  • Tras el ingreso de los datos, se procesan los datos y se efectúan los cálculos.
  • Al final se muestran al usuario los resultados.

Vuestra tarea consistirá en analizar los siguientes programas, copiarlos, correrlos, y ver si todo anda bien.



Aplicación aritmética para la consola.

El método que se usa en consola para recibir datos ingresados por el usuario es System.Console.ReadLine().
Al invocarlo, el usuario ingresa una cadena de caracteres, que es el resultado devuelto por el método... así que hay que convertirlo a número entero.
Esta conversión se hace, por ejemplo, con el método System.Convert.ToInt32().
La operación completa sería System.Convert.ToInt32( System.Console.ReadLine() ).
Declarando el espacio de nombres System podremos quitar los prefijos System. y aliviar un poco el aspecto de las sentencias.

Las variables se deben declarar antes de cualquier operación, y tendrán tipo int. Aquí va el código:


using System;

class Ejemplo_Aritmetica_Basica
{
   static void Main()
   {
     // --- Declaración de variables ---
     int x, y;
     int suma, resta, producto;

     // --- Ingreso de datos ---
     Console.Write("x = ?");
     x = Console.ToInt32( Console.ReadLine() );
     Console.Write("y = ?");
     y = Console.ToInt32( Console.ReadLine() );

     // --- Procesar y calcular ---
     suma = x + y;
     resta = x - y;
     producto = x * y;

     // --- Mostrar resultados ---
     Console.Write(" x+y = {0}\n x-y = {1}\n x.y = {2}\n\n", suma, resta, producto);
   }
}



Aplicación aritmética para la GUI con System.Windows.Forms.

El concepto es el mismo, sólo que ahora debemos definir objetos que permitan al usuario interactuar con una ventana de aplicación.

Primero les encargo unos preparativos:

  • Abrir el IDE de Visual Studio.
  • Crear un proyecto nuevo y vacío, llamado VS0306SWF_Aritmetica_Basica.
  • Agregar al proyecto las Referencias System.Windows.Forms y System.Drawing.
  • Agregar al proyecto un archivo nuevo y vacío con el nombre VS0306SWF_Aritmetica_Basica.cs, y abrir dicho archivo para edición.

Analicemos lo que hay que hacer, y después veamos el código al final.

Lo primero que se debe hacer es llamar al método Run.Application de la librería System.Windows.Forms.
Dicho método ejecuta el bucle de la aplicación bajo Windows, y se encarga de esperar acciones del usuario.
Se necesita crear un objeto de tipo "formulario" y "enganchárselo" al método Run.Application.
El usuario interactúa con una ventana de aplicación correspondiente a dicho formulario.

Los formularios tienen ciertas características básicas predefinidas,
que nososotros debemos invocar mediante herencia a la clase System.Windows.Forms.Form.
Una vez que hemos dado la descripción de nuestro formulario en una clase,
apenas ahí podremos ya crear un objeto de dicha clase para "atarlo" a Run.Application().

A nuestra clase-formulario le hemos dado el nombre Formulario_principal.
Al crear (instanciar) un objeto de dicha clase se invoca a su método del mismo nombre Formulario_principal(), el cual va construyendo todos los widgets que incluiremos en la aplicación.

Queremos que haya 3 widgets: una para albergar el valor de la variable x, otro para y, y un último en donde mostraremos información al usuario, incluyendo todos los resultados.

Los primeros dos serán widgets del tipo TextBox (caja-de-texto), y les pondremos los nombres caja_de_texto_x,caja_de_texto_y.
El de resultado será de tipo Label (etiqueta), y le pondremos el nombre etiqueta_resultado.

Estos objetos deben "atarse" al formulario de la aplicación.
Pero antes, es necesario crear dichos objetos.
Más aún, antes vamos a definir variables correspondientes al tipo de datos de esos objetos.

Supongamos que hemos ya creado los 3 widgets...
Antes de "atarlos" al formulario, es necesario también configurarlos un poco, para que la apariencia en la ventana sea la adecuada.

En particular, lo que vamos a hacer es que la etiqueta reaccione ante un click hecho por el usuario sobre ella. Cuando esto pase, la aplicación hará "algo", en este caso, "mostrar los resultados de los cálculos".

Para esto es menester que escribamos un método específico, en donde desarrollemos todos los cálculos que deseamos, y que se muestren además los resultados.
Este método lo hemos llamado etiqueta_resultado_Click,
y debemos "atarlo" de alguna manera al objeto etiqueta_resultado.
Esto se hace mediante System.Event_Handler (un manejador-de-eventos).

La aplicación es muy precaria en apariencia, porque se ha hecho hincapié en que su programación sea lo más simple posible.

Nótese la aparición del prefijo this. en todas partes.
Ese prefijo es una referencia a la propia clase en la que estamos "parados", en este caso, Formulario_principal.


using System;
using System.Drawing;
using System.Windows.Forms;

static class Aritmetica_con_GUI_SWF
{
    static void Main()
    {
         Application.Run(new Formulario_principal());
    }
}

public class Formulario_principal : Form
{
   // Declaración de las variables/objetos que serán widgets en la aplicación:
   private System.Windows.Forms.TextBox caja_texto_x;
   private System.Windows.Forms.TextBox caja_texto_y;
   private System.Windows.Forms.Label etiqueta_resultado;

   public Formulario_principal()
   {
      // Definiendo los widgets que irán en el formulario
      this.caja_texto_x = new System.Windows.Forms.TextBox();
      this.caja_texto_y = new System.Windows.Forms.TextBox();
      this.etiqueta_resultado = new System.Windows.Forms.Label();
   
      // Configuración inicial del widget "etiqueta_resultado"
      // Se activa "Autosize" para que se vea bien toda la información.
      // Se coloca un texto dando instrucciones. También allí se pondrán los resultados.
      // Se enlaza el evento Clic-del-ratón-en-la-etiqueta al evento etiqueta_resultado_Click.

      this.etiqueta_resultado.AutoSize = true;
      this.etiqueta_resultado.Text =
             "Ingrese valores para x e y, y luego\n click aquí para calcular resultado";
       this.etiqueta_resultado.Click += new System.EventHandler(this.etiqueta_resultado_Click);
   
       // Estas sentencias posicionan bien los widgets sin mucha complicación.
       this.caja_texto_x.Dock = System.Windows.Forms.DockStyle.Top;
       this.caja_texto_y.Dock = System.Windows.Forms.DockStyle.Top;
       this.etiqueta_resultado.Dock = System.Windows.Forms.DockStyle.Top;

       // Se pone un tamaño al formulario bastante grande para que entren sus componentes.
       this.ClientSize = new System.Drawing.Size(300, 200);
   
       // Se agregan los componentes (widgets) al formulario,
       // y en orden inverso, para que quede como queremos, sin mayor complicación.

       this.Controls.Add(this.etiqueta_resultado);
       this.Controls.Add(this.caja_texto_y);
       this.Controls.Add(this.caja_texto_x);
   }

   private void etiqueta_resultado_Click(object sender, EventArgs e)
   {
      int x = Convert.ToInt32(this.caja_texto_x.Text);
      int y = Convert.ToInt32(this.caja_texto_y.Text);
      int suma = x + y;
      int resta = x - y;
      int producto = x * y;

      this.etiqueta_resultado.Text =
            "      x = " + Convert.ToString(x) + "\n" +
            "      y = " + Convert.ToString(y) + "\n" +
            "x + y = " + Convert.ToString(suma) + "\n" +
            "x - y = " + Convert.ToString(resta) + "\n" +
            "x . y = " + Convert.ToString(producto) + "\n" +
            "\n Haga clic aquí para un nuevo recálculo.";
   }
}



Hemos puesto en color púrpura las líneas de comentarios.
Si lo desean, pueden ustedes borrar esas líneas para ver cómo queda el código limpio, sin comentarios. Se los pongo así en el spoiler:

Notemos que los cálculos se han hecho en las mismas líneas en que se hacen las declaraciones de las variables. Esto es perfectamente válido.
Se les da a las variables x, y, los valores extraídos de las cajas-de-texto,
y a las variables suma, resta, producto, se les asigna los resultados de las respectivas operaciones.

Mismo código sin comentarios

using System;
using System.Drawing;
using System.Windows.Forms;

static class Aritmetica_con_GUI_SWF
{
    static void Main()
    {
         Application.Run(new Formulario_principal());
    }
}

public class Formulario_principal : Form
{
   private System.Windows.Forms.TextBox caja_texto_x;
   private System.Windows.Forms.TextBox caja_texto_y;
   private System.Windows.Forms.Label etiqueta_resultado;

   public Formulario_principal()
   {
      this.caja_texto_x = new System.Windows.Forms.TextBox();
      this.caja_texto_y = new System.Windows.Forms.TextBox();
      this.etiqueta_resultado = new System.Windows.Forms.Label();
   
      this.etiqueta_resultado.AutoSize = true;
      this.etiqueta_resultado.Text =
             "Ingrese valores para x e y, y luego\n click aquí para calcular resultado";
       this.etiqueta_resultado.Click += new System.EventHandler(this.etiqueta_resultado_Click);
   
       this.caja_texto_x.Dock = System.Windows.Forms.DockStyle.Top;
       this.caja_texto_y.Dock = System.Windows.Forms.DockStyle.Top;
       this.etiqueta_resultado.Dock = System.Windows.Forms.DockStyle.Top;

       this.ClientSize = new System.Drawing.Size(300, 200);
   
       this.Controls.Add(this.etiqueta_resultado);
       this.Controls.Add(this.caja_texto_y);
       this.Controls.Add(this.caja_texto_x);
   }

   private void etiqueta_resultado_Click(object sender, EventArgs e)
   {
      int x = Convert.ToInt32(this.caja_texto_x.Text);
      int y = Convert.ToInt32(this.caja_texto_y.Text);
      int suma = x + y;
      int resta = x - y;
      int producto = x * y;

      this.etiqueta_resultado.Text =
            "      x = " + Convert.ToString(x) + "\n" +
            "      y = " + Convert.ToString(y) + "\n" +
            "x + y = " + Convert.ToString(suma) + "\n" +
            "x - y = " + Convert.ToString(resta) + "\n" +
            "x . y = " + Convert.ToString(producto) + "\n" +
            "\n Haga clic aquí para un nuevo recálculo.";
   }
}


[cerrar]

Observemos que tanto las variables para los widgets como los métodos del formulario, tanto el constructor Formulario_principal() como el de "reacción al click en la etiqueta", etiqueta_resultado_Click,
se deben declarar todos ellos dentro de la clase Formulario_Principal.

Cuando estudiemos más a fondo las clases y los objetos, así como los conceptos de la programación orientada a eventos y la programación GUI, comprenderemos mejor el fundamento de todo lo hecho.

Observemos también que tanto las cajas-de-texto como las etiquetas muestran exclusivamente información de tipo string, o sea, cadenas de caracteres.
Esto nos obliga a hacer una nueva conversión de tipo, pasando los resultados de tipo numérico a tipo cadena, mediante el método Convert.ToString().

Una última aclaración: para acomodar las widgets hemos usado una manera muy simple, que consiste en apilarlos lo más arriba posible de la ventana de aplicación (Top). Por ello hemos tenido que "atar" las widgets en orden inverso.



Aplicación aritmética para la GUI con Gtk#.

(Estoy teniendo problemas con la "tecnología", ando sin internet y se me queman los periféricos, ahhh!  :'(  :'(  :'( , así que les debo la versión de Gtk# para otro día.
Pueden rebuscárselas consultando los tutoriales que les puse en posts anteriores, o bien esperar a que yo haga y testee el programa, y se los pase.)





24 Enero, 2010, 04:55 am
Respuesta #11

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
3.7. Conceptos de memoria.

De esta sección del Deitel me quedo sólo con uno de sus párrafos, en los que explica las características de una variable:

\( \bullet \) Una variable corresponde a una posición específica de la memoria de la computadora.

Las posiciones de la memoria están numeradas, pero los programadores C# no accedemos a ellas a través de esos números, cosa que sería muy engorrosa.
El acceso se hace indirectamente a través de un identificador definido por el programador.
Esto es bueno, porque así a la variable se le puede dar un nombre significativo que nos ayude en el diseño del programa. Ejemplos de identificadores: numero, x, y, edad, promedio, etc.

Las características de una variable son las siguientes:

  • Nombre: El identificador que elegimos para la variable.
  • Tipo: Es un atributo que permite diferenciar las variables, clasificándolas en conjuntos compatibles entre sí, como ser, número enteros, reales, caracteres, cadenas, u objetos de alguna clase definida por el usuario.
  • Tamaño: Es la cantidad de bytes que ocupa la variable en la memoria.
  • Valor: Es la información que guarda la variable en su seno. Para interpretar correctamente este valor, se debe atender al tipo de la variable.

No vamos a agregar más acerca de esta sección.
Pasemos a la siguiente.




26 Enero, 2010, 02:38 am
Respuesta #12

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
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")
[cerrar]

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;


[cerrar]

\( \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();

        // .....................
   }
}

[cerrar]

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);

       //  ......

[cerrar]

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";

       // ...................

[cerrar]

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...

[cerrar]

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);

       //  .........................
[cerrar]

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)




28 Enero, 2010, 06:31 am
Respuesta #13

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Proyecto: Calculadora (continuación).

  • En primer lugar, notemos que cuando el usuario ingresa datos en los casilleros, la aplicación no reacciona de ninguna manera especial. Tan sólo se deja actuar al widget como lo que es: una caja de texto que permite entrar datos.
    No obstante, tengamos presente que el valor almacenado en esos casilleros es siempre de tipo string, vale decir, una cadena de caracteres.
    Así que, para hacer cálculos aritméticos, en algún momento habrá que convertir los datos de caracteres a números enteros.
  • Cuando el usuario clickea en una de las etiquetas a, b, c, d, e, f, el programa responderá escribiendo el valor correspondiente en el casillero z, que podemos pensarlo como el "visor de resultados".
    Al mismo tiempo, se indicará que se ha "cargado un nuevo operando".
    Esto se hará con un método específico que se invocará en todos los casos, y lo llamaremos nuevo_operando(), que por ahora dejamos sin implementar.
    El código de todos estos métodos es el mismo, y es muy sencillo:

    Click para ver el código

    public class Formulario_principal : Form
    {
        //   ..................

        private void Elegir_Casillero_a(object sender, EventArgs e)
        {
            this.caja_texto_z.Text = this.caja_texto_a.Text;
            this.nuevo_operando();
        }

        private void Elegir_Casillero_b(object sender, EventArgs e)
        {
            this.caja_texto_z.Text = this.caja_texto_b.Text;
            this.nuevo_operando();
        }

        private void Elegir_Casillero_c(object sender, EventArgs e)
        {
            this.caja_texto_z.Text = this.caja_texto_c.Text;
            this.nuevo_operando();
        }

        private void Elegir_Casillero_d(object sender, EventArgs e)
        {
            this.caja_texto_z.Text = this.caja_texto_d.Text;
            this.nuevo_operando();
        }

        private void Elegir_Casillero_e(object sender, EventArgs e)
        {
            this.caja_texto_z.Text = this.caja_texto_e.Text;
            this.nuevo_operando();
        }

        private void Elegir_Casillero_f(object sender, EventArgs e)
        {
            this.caja_texto_z.Text = this.caja_texto_f.Text;
            this.nuevo_operando();
        }

        private void Elegir_Casillero_z(object sender, EventArgs e)
        {
            // this.caja_texto_z.Text = this.caja_texto_z.Text;
            this.nuevo_operando();
        }

        // ....................

    }

    [cerrar]

    Notemos que hasta ahora el casillero de resultados z tiene el mismo tratamiento que los demás: en todos los casos el efecto es dejar en el "visor" el valor del casillero clickeado por el usuario.
    La única diferencia es que la sentencia this.caja_texto_z.Text = this.caja_texto_z.Text;
    es redundante, ya que se está poniendo el valor de ella misma... en ella misma.
  • Notemos que, como las widgets caja_texto_a, y las demás, son de tipo TextBox, todas tienen el atributo Text.
    Dicho atributo es una variable, y se le puede asignar valores, o usar su valor en un cálculo o procesamiento.
  • Notemos que en todas partes estamos usando el prefijo this. para acceder a los objetos del formulario.
    Esto no es estrictamente necesario.
    Pero es de "buena educación" poner this. en todas partes.
    ¿Por qué?
    Porque podría haber varias instancias de la aplicación o de las ventanas, y en esos caso, el prefijo this. ayuda a discernir el correcto comportamiento de la aplicación.
    Al profundizar en la teoría de la programación orientada a objetos explicaremos con más certeza qué es lo que ocurre, y el significado de this.
  • Al presionar un botón de operación aritmética, se debe realizar un cálculo.
    En este caso llevamos a cabo varias operaciones comunes a todos los casos.
    Como son siempre las mismas, creamos un método común de nombre recalcular(), que definiremos más adelante.
    El aspecto de los métodos para los botones de operaciones quedarían así:

    Click para ver el código


       //  ...................

        private void Elegir_Operacion_mas(object sender, EventArgs e)
        {
            this.recalcular();
            this.oper = '+';
        }

        private void Elegir_Operacion_menos(object sender, EventArgs e)
        {
            this.recalcular();
            this.oper = '-';
        }

        private void Elegir_Operacion_por(object sender, EventArgs e)
        {
            this.recalcular();
            this.oper = '*';
        }

        private void Elegir_Operacion_sobre(object sender, EventArgs e)
        {
            this.recalcular();
            this.oper = '/';
        }

        private void Elegir_Operacion_resto(object sender, EventArgs e)
        {
            this.recalcular();
            this.oper = '%';
        }

        private void boton_igual_Click(object sender, EventArgs e)
        {
            this.recalcular();
            this.oper = ';';
            this.nuevo_operando();
        }

       //  ...................

    [cerrar]
  • En los métodos anteriores se ha invocado una variable llamada oper.
    Ella será un miembro de la clase Formulario_principal, será de tipo char, y albergará un caracter indicando el tipo de operación aritmética efectuada.
  • Observemos la extraña codificación de esos métodos.
    "Primero" se llama a la función de recalcular(),
    y "después" se indica el tipo de operación.
    ¿No habría que indicarl antes? ... mmmm

    En realidad esto obedece a la "mecánica" de nuestra calculadora.

    "Suponemos" que tenemos dos operandos y una operación "ya" almacenadas en alguna parte.
    Al presionar el botón = simplemente se "efectiviza" el cálculo y se muestra el resultado.
    Los demás botones +,-,*,/,%, funcionan de la misma forma que el botón =, con la única diferencia de que a su vez quedan "en espera" de un nuevo operando, para seguir con el cálculo.

    Obsérvese que el "signo de la operación" al apretar el botón = es un punto y coma ;.
    Esto quiere decir que la operación aritmética efectuada es simplemente: "separar lo anterior del nuevo valor elegido, y tenerlo guardado como un nuevo operando".

  • Otra sutileza: cuando se presiona el botón = se termina la seguidilla de cálculos.
    En ese caso, el valor que queda en el casillero z se puede usar para hacer nuevas operaciones.
    La idea es que quede incluso disponible, sin necesidad de hacer click sobre él.
    O sea, si en el visor queda un número, querríamos operar con él, sin tener que hacer click sobre la z.

    Pero esto es una cuestión intuitiva del usuario, que el lenguaje C# no es capaz de adivinar...
    Tenemos que indicarlo nosotros adecuadamente.
    Para que esté disponible el valor del visor, lo ponemos como el siguiente nuevo operando.
    Y por eso se agrega una llamada a nuevo_operando(); en el código del método boton_igual_Click.
  • Ahora vamos a implementar los métodos nuevo_operando(), recalcular().
    Antes de ello es necesario declarar unas variables que guardarán valores temporales de los operandos. Ya dijimos que uno se llamará resultado y el otro operando.
    A pesar de los nombres, ambos serán "operandos" cuando hagamos los cálculos.
    La diferencia está en que el valor guardado en resultado es el que se pone en el "visor de resultados".
    También declararemos una variable para almacenar la próxima operación que se habrá de calcular.

    Además, vamos a agregar una variable de tipo string, de nombre formula, que tendrá fines meramente informativos.
    No será necesaria en los cálculos, pero permitirá mostrar al usuario un cartelito resumiendo la operación aritmética que está llevando a cabo, y cuánto da.

    Las declaraciones de las variables son éstas:

        private char oper;
        private int operando;
        private int resultado;
        private string formula;


  • Veamos el método nuevo_operando().
    En él simplemente se pone en la variable operando el valor numérico entero que resulta de transformar el dato puesto en el casillero z , que originalmente es de tipo string.

    ¿Por qué sólo z?
    ¿Qué pasa si quiero poner el valor de c, como operando?
    Bueno, el programa funciona así:

    * Al hacer clic en c se pone el valor del casillero de c en el de z, lo cual es automáticamente visto por el usuario.
    O sea, el valor elegido se pone automáticamente en el "visor de resultados".
    A continuación presionamos un botón de operación, digamos +, y el programa almacenó esta elección del usuario en la variable oper.
    Antes de almacenar este sencillo dato, hizo una llamada a recalcular(), sólo para resolver las operaciones aún pendientes...
    Pero con el signo + aún no puede hacerse nada, porque falta ingresar otro operando.

    * Ahora el usuario elige un segundo operando, y entonces se almacena automáticamente en la variable operando.

    ¡¡En particular, estamos sobreescribiendo el valor anterior de operando!!  :o

    ¿Y entonces, dónde fue a parar el valor del primer operando?
    A no desesperar, que seguramente ha sido guardado en el casillero de z.
    Esto se hizo al momento de clickear sobre el botón +.

    Toda esta discusión para poder poner como método nuevo_operando() una simple línea que resuelve todo, y lo hace bien, del modo esperado:


        private void nuevo_operando()
        {
            this.operando = Convert.ToInt32(this.caja_texto_z.Text);
        }


  • Ahora vamos al método recalcular().
    Este método mira en los valores numéricos que están guardados en las variables resultado y operando, y consulta la operación aritmética que está "en espera" en la variable oper.
    Según de qué operación se trate, hace el cálculo que corresponde.
    La selección de la operación se hace sencillamente, a través del selector de casos switch, que en su momento explicaremos.
    Por ahora basta ver cómo funciona.

    Clic para ver detalles

        private void recalcular()
        {
          &n
    [cerrar]

28 Enero, 2010, 11:55 pm
Respuesta #14

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Proyecto: "La otra" calculadora.

No he tenido noticias vuestras desde la última entrega en que les presenté el ejemplo de la calculadora.
Si no se entendió, o ante cualquier problema que hayan tenido, avísenme.

Para no quitarles la diversión, les propongo un ejercicio similar al programa que hice yo, aunque de comportamiento un poco diferente. Se trata de llevar a cabo una calculadora común y corriente.

El programa tiene que tener botones que simulen los botones de una calculadora, y permitir la entrada de dígitos uno a uno.
Los datos que se van ingresando tienen que aparecer en un visor, que si quieren pueden implementarlo con una simple etiqueta informativa que va mostrando los dígitos y las operaciones.
Al final tiene que mostrar la operación y el resultado.
Tiene que tener un botón para borrar todo, y otro botón para salir del programa.

Todo esto hagámoslo con la GUI de la librería System.Windows.Forms.

Los pasos preliminares son: abrir en Visual Studio un proyecto nuevo vacío, agregarle luego un archivo de código, y también agregarle al proyecto las referencias necesarias para que funcione la parte visual, que serían: System, System.Drawing, System.Windows.Forms.

Luego editamos el archivo de código, imitando la técnica empleada en el ejemplo que yo les dí.
Es simplemente agregar especificaciones, una tras otra: ancho (Width), alto (Height), posición (Location), texto (Text), y eventos asociados (EventHandler).

Finalmente, tenemos que concretar la lógica de los eventos del programa, de manera que el efecto visual para el usuario sea el correcto, y las operaciones aritméticas sean también correctas.

En cuando al punto decimal, les voy a pedir que sólo programen en principio el aspecto visual, o sea, mostrarlo, pero que su evento asociado no haga nada.
O sea que seguiremos trabajando sólo con números enteros, para facilitar un poco el tratamiento.

El aspecto visual del programa puede ser algo como esto, como para que tengan una idea de lo que les estoy pidiendo:


A lo mejor es un error de mi parte pedirles que inicien con ejemplos que usen interface gráfica, porque pedagógicamente hay muchas sutilezas para el principiante: el uso del prefijo this, el uso de una cosa extraña como el método  EventHandler, y la permanente transformación de datos de tipo string a numérico y viceversa.

Pero tengan en cuenta que esto no es un libro plano en el cual ustedes estudian solos.
Tenemos la posibilidad de tener una experiencia interactiva, e intercambiar impresiones.
Por eso, si de pronto no entienden nada de lo que digo, avísenme, ya sea para que yo mejore mi exposición, o para que ustedes se den cuenta que algo que parecía difuso era en verdad algo simple.

Así que traten de hacer el programita, háganme preguntas, intercambiemos opiniones.
Es necesario que lo hagamos para que podamos aprender bien todas las sutilezas.
Si no, seguro que siempre se escapa algo.



Por una cuestión del orden en los contenidos, quise posponer la explicación del objeto sender en los manejadores de eventos.
Pero vi que, por ejemplo, flashtk lo ha usado en su código.
Así que si alguno de ustedes desea utilizarlo, por mí está bien.
Si alguno no sabe cómo usarlo, y desea incluirlo de todos modos, me avisa y se lo explico un poco.

A grandes rasgos el objeto sender permite hacer referencia al objeto (en este caso un widget) [desde el cual se hizo la llamada al  evento.
De esta manera, con un solo manejador se pueden tratar varios eventos similares o relacionados, con un código mucho más claro y breve, y sin los recovecos que tuve que usar... tan sólo para evitar el uso de sender.

En cuanto ahondemos en los objetos y las clases, el significado de sender se hará totalmente claro.






29 Enero, 2010, 03:44 am
Respuesta #15

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)

29 Enero, 2010, 07:50 am
Respuesta #16

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
3.9. Toma de decisiones. Operadores de Igualdad y Relacionales.

En programación es muy común tomar diferentes caminos en un algoritmo, según el valor de cierta cierta condición. En C# se usan las sentencias if para este propósito. Veamos cómo funciona.

El esquema sería así: deseamos evaluar una condición "test", que sólo puede ser verdadera o falsa.
Si la condición es verdadera, se ejecuta una determinada serie de instrucciones.
Si la condición es falsa, se ejecuta otra serie de instrucciones distinta.
El formato sería éste:


   if ( test )
      {
          instrucciones del caso verdadero
      }
      else
      {
          instrucciones del caso falso
      }



Por ejemplo, podríamos querer informar si cierto número es par.
Para eso preguntamos si el resto de la división por 2 es igual a 0:



     int numero;

     Console.Write("Escriba un número entero:");
     numero = Convert.ToInt32( Console.ReadLine() );
       
     if ( numero % 2 == 0 )
      {
          Console.WriteLine("El número {0} es PAR.", numero);
      }
      else
      {
          Console.WriteLine("El número {0} es IMPAR.", numero);
      }



También es posible omitir la parte else.

Aquellos que están habituados a la programación, esperan que haya sentencias de este tipo en un lenguaje dado.

Resta ver cuáles son los operadores de comparación.
Ante todo, digamos que, en general, un operador de comparación pone a prueba un par de objetos, y da como resultado un valor que sólo puede ser verdadero o falso.
El tipo de datos correspondiente a estos valores se llama booleano, y en C# se indica con bool.
Los valores que puede tomar son true (verdadero) y false (falso).
Pueden declararse variables de tipo bool, y dárseles valores.

Los operadores de comparación son seis:
  • ==: compara dos variables y determina si sus valores son iguales.
  • !=: compara dos variables y determina si sus valores son distintos.
  • <: compara dos variables y determina si la primera es estrictamente menor que la segunda (si esto está definido para el tipo de datos que se está comparando).
  • <=: compara dos variables y determina si la primera es menor o igual que la segunda (si esto está definido para el tipo de datos que se está comparando).
  • >=: compara dos variables y determina si la primera es estrictamente mayor que la segunda (si esto está definido para el tipo de datos que se está comparando).
  • <: compara dos variables y determina si la primera es estrictamente menor que la segunda (si esto está definido para el tipo de datos que se está comparando).
  • >=: compara dos variables y determina si la primera es mayor o igual que la segunda (si esto está definido para el tipo de datos que se está comparando).

Por ejemplo, la comparación 5 <= 17 daría como resultado el valor booleano true, y la comparación -3 > 1 daría como resultado false.

En los ejemplos de las calculadoras hemos usado sentencias if,
sin haberlas explicado demasiado.
Confié en que se iban a entender... si no es así, me avisan.



Otra sentencia que permite seleccionar entre varias opciones y distintos caminos es switch, la cual he usado en el ejemplo de la calculadora.



No quiero ahondar demasiado en la teoría de esto, hasta entrar en aguas más profundas.

Deseo simplemente llegar al final de este capítulo, y que se entiendan las cosas más básicas, las cuales repetiremos y usaremos una y otra vez en todos los capítulos siguientes.
Mi intención es que perdamos el miedo a la programación GUI, que sepamos poner widgets en la ventana de una aplicación, que aprendamos a conectar eventos a tareas, y que tengamos en cuenta aspectos muy, pero que muy básicos del lenguaje: la posibilidad de realizar operaciones aritméticas, la existencia de datos de tipo string y bool, y que sepamos que contamos con los operadores de comparación, que han de existir en todo lenguaje.

Todo será profundizado y tratado en detalle a partir del próximo capítulo, que iniciaremos apenas un par de posts más adelante.
Tan sólo les pido que NO SE QUEDEN CON DUDAS. Comenten, pregunten, critiquen.

Cuando puse los ejemplos de las calculadoras, vi que aún tratando de mantener la simplicidad, aparecían complicaciones.
Pero no quiero quitar esos ejemplos, porque pienso que aún sin los conocimientos suficientes todo programador está capacitado para comprenderlos, aún si se considera a sí mismo un novato.

Una vez que tomemos confianza en el funcionamiento de todo lo explicado hasta aquí, tendremos una grata experiencia en el aprendizaje del lenguaje C#, porque la gran mayoría de nuestros ejercicios y ejemplos usarán una interface GUI, que si no, la consola de comandos es muy fea y antipática.

¿Les parece bien eso?

Así que no se me vayan a asustar.  :o  :o  :o

En los capítulos que siguen vamos a usar herramientas mínimas de la programación GUI, muy parecidas a las que les he mostrado hasta ahora. O sea, una interface gráfica básica y modesta, y así podremos concentrarnos en las cuestiones más internas y profundas del lenguaje C#.

También planeo que estudiemos y/o repasemos técnicas de programación eficiente, algoritmos, etc.
Todo con cuidado y paciencia, y asimismo habrá bastante material optativo (eso creo), de modo que cada cual se oriente hacia donde mejor le parezca.




En el siguiente post tan sólo voy a agregar algunos ejemplos y ejercicios más, para reforzar las cosas que hemos visto hasta aquí del material que corresponde al capítulo 3, más el plus de los rudimentos de la programación GUI.





31 Enero, 2010, 10:25 pm
Respuesta #17

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Proyectos de práctica para el capítulo 3.

A lo mejor les he complicado la vida con las "calculadoras".
Aquí les dejo un proyecto algo más fácil de programar, aunque sigue teniendo interface gráfica.
De paso, podrán practicar las sentencias if.

Proyecto "Adivina Número".

El programa tiene el siguiente aspecto visual:


Lo que tienen que hacer es lo siguiente:

  • Iniciar un nuevo proyecto vacío, de nombre VS0309GUISWF_Adivina_Numero, con un nuevo archivo de código vacío VS0309GUISWF_Adivina_Numero.cs.
    Agregar las referencias usuales: System, System.Drawing, System.Windows.Forms.
  • El programa selecciona un número al azar entre 0 y 99, que queda oculto para el usuario.
    El usuario debe escribir en un cuadro el número que él cree correcto.
    O sea, está adivinando.
    Cuando ha escrito el número de su preferencia, presiona el botón "Apostar!", y el programa da pistas con mensajes de texto que dicen: "Frío, Tibio, Caliente, Muy Caliente, Acertaste".
    El botón "Reiniciar" sirve para que el programa seleccione un nuevo número al azar.
    Los botones "<<" y ">>" sirven para retroceder o avanzar 10 pasos. Al presionarlos, el número de la caja de texto debe reflejar este avance o retroceso.

Para elegir un número al azar, se usará un objeto de tipo Random, así:

Random Generador_Aleatorio = new Random();

Supongamos que el número que el programa oculta se guarda en la variable:

int numero_oculto;

Luego, cada vez que se desea generar un número al azar entre 0 y 99 se escribe la sentencia:

this.numero_oculto = this.Generador_Aleatorio(100);

Al presionar el botón "Apostar!", se debe invocar un método asociado, que resuelva si el número elegido por el usuario está cerca del que está oculto.
Para ello se debe calcular la "distancia" entre ambos números (el valor absoluto de la diferencia).
El valor absoluto se obtiene con la función Math.Abs.

A continuación se usan sentencias if para determinar "a cuánta distancia" está el valor propuesto por el usuario del número oculto.
Vamos a estipular que si la distancia es mayor que 15, entonces se da la pista "Frío".
Si la distancia está entre 8 y 14, se dará la pista "Tibio".
Si la distancia está entre 3 y 7, se dará la pista "Caliente".
Si la distancia está entre 1 y 2, se dará la pista "Muy Caliente".
Si la distancia es 0, se mostrará el mensaje: "Acertaste! Felicitaciones!".

Estas pistas y mensajes se muestran con un simple cartel, usando MessageBox.Show, por ejemplo:


        if (distancia > 15)
            MessageBox.Show("Frío... sigue buscando!!");


Y así por el estilo.

Los dejo con la inquietud.
La técnica que les sugiero es "imitar" lo que ya les he enseñado.
No se compliquen mucho la cabeza, y sólo busquen que el programa funcione.
La lógica interna no tiene que ser maravillosa.
Ya tendremos ocasión de pulir nuestras técnicas de programación.
Ahora sólo estamos echando un vistazo de lo básico en la programación GUI, junto con otras herramientas de uso común, a las que debemos acostumbrarnos.

Esta vez los "manejadores de eventos" son métodos muy sencillos, y no hay nada rebuscado.

Aún así: pregunten todas sus dudas e informen de sus problemas, que seguramente los tendrán.





01 Febrero, 2010, 01:23 am
Respuesta #18

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Proyectos de práctica para el capítulo 3 (continuación).

Proyecto "Ta te ti".

El programa tiene el siguiente aspecto visual:


Este ejercicio es más bien un desafío: hacer un juego de 3 en raya para dos jugadores.
Este programa se puede hacer con las herramientas que conocemos hasta este momento, pero aún así es muy probable que necesiten ayuda para hacerlo en forma sencilla... y que funcione bien.

Aquí les explico los detalles.

Cada casillero será un botón.
Cada vez que se presiona un botón, se considera que el turno pasa automáticamente al otro jugador, alternativamente.
Los jugadores son "O" y "X".

Siempre inicia el jugador "O"

Al principio los casilleros están vacíos, y a medida que los jugadores van marcando las casillas, se les cambia el atributo "Text" para que refleje que allí hay una "O" o una "X".

Si una casilla ya está marcada, no permitir que se sobreescriba en ella.

En este ejemplo es bueno usar el objeto "sender" cuando se llama al método que maneja el evento de apretar un botón/casilla.

Allí conviene definir una variable interna que haga referencia al "botón que ha sido presionado".
Esto se hace con esta línea:

Button casilla_tocada = (Button) sender;

No pregunten demasiado por qué eso es así, ya lo veremos en el próximo capítulo.

Ahora podemos hacer cosas como escribir una "O" o una "X" en la casilla:

casilla_tocada.Text = "X";

Internamente, los jugadores tienen los números 1 y 2.
Las casillas sin marcar tendrían el valor 0...

A los botones les he puesto nombres de la rosa de los vientos:

    private Button boton_NW;
    private Button boton_N;
    private Button boton_NE;
    private Button boton_E;
    private Button boton_SE;
    private Button boton_S;
    private Button boton_SW;
    private Button boton_W;
    private Button boton_Centro;


He definido una función que convierte los símbolos "O" y "X" a los números 1 y 2:



    private int nj(string s)
    {
        if (s == "O")
            return 1;
        else if (s == "X")
            return 2;
        else
            return 0;
    }




He usado esa función para calcular el número de jugador asociado  a cada una de las 9 casillas del tablero de tateti.
Por ejemplo:



        int j_NW = this.nj(this.boton_NW.Text);
        int j_N = this.nj(this.boton_N.Text);
        int j_NE = this.nj(this.boton_NE.Text);
        int j_W = this.nj(this.boton_W.Text);
        int j_Centro = this.nj(this.boton_Centro.Text);
        int j_E = this.nj(this.boton_E.Text);
        int j_SW = this.nj(this.boton_SW.Text);
        int j_S = this.nj(this.boton_S.Text);
        int j_SE = this.nj(this.boton_SE.Text);



Estos números los he usado para calcular "valores asociados a las 8 líneas del tablero".
Esas 8 líneas son las 3 horizontales, las 3 verticales y las 2 diagonales.

He usado el razonamiento siguiente, para simplificar el análisis de una determinada posición:

* En una línea hay sólo "O" si y sólo si el jugador 1 ocupa cada casilla de esa línea, y esto es equivalente a que el producto de los valores de esa línea es igual a 1.

* En una línea hay sólo "X" si y sólo si el jugador 2 ocupa cada casilla de esa línea, y esto es equivalente a que el producto de los valores de esa línea es igual a 8.

* Si el producto de los valores de una línea es distinto de 1 o de 8, entonces no hay 3 en raya en esa línea.

Por ejemplo:

        int linea_h_superior = j_NW * j_N * j_NE;

Y luego vendría algo como esto:


        int ganador;

        if (linea_h_superior == 8)
            ganador = 2;


Hay todo un método que se llama Verificar_Ganador(), en el que se hacen todas esas cuentas y consideraciones, y se detemina cuál de los dos jugadores es el ganador, o bien se pone ganador = 0 cuando no hay ganador aún.

En otras partes del programa hay que verificar empates, o dar otro tipo de información.

Varios mensajes pueden darse con MessageBox.Show().

No duden en preguntar cuando la cosa se complique.
Los programas tienen que salir, se tienen que ver bien, tienen que funcionar, y no tienen que tener fallas. Así que insistan hasta que esto se consiga, y también insistanme a mí con las preguntas.


Los programas que propongo como ejercicios primero los resuelvo, y sólo después se los pongo a ustedes como problemas a resolver. O sea que les pongo problemas que pueden resolverse con las herramientas que manejamos hasta ahora. Y además quiere decir que ya he visto las posibles fuentes de errores y fallas del código, y por ende pueden preguntarme.






15 Febrero, 2010, 03:18 am
Respuesta #19

argentinator

  • Consultar la FIRMAPEDIA
  • Administrador
  • Mensajes: 7,739
  • País: ar
  • Karma: +0/-0
  • Sexo: Masculino
  • Vean mis posts activos en mi página personal
    • Mis posts activos (click aquí)
Tutorial GUI con SWF para el capítulo 3.

No sé si los habré asustado o qué con la programación GUI.
Así que se me ocurrió que lo mejor es hacer un tutorial antes de seguir avanzando.
Por ahora este tutorial estará aquí al final del capítulo 3, pero una vez que hayan pasado algunas semanas y los participantes lo hayan puesto en práctica, lo colocaré intercalado antes de los ejemplos de práctica de calculadoras y demás...

Vida y obra de un botón.

Ese sería el título de un cuento que verse sobre cómo se construye un botón en una aplicación con interfase gráfica.
Pero haremos algunas cosas más, no sólo botones.

Este tutorial tiene los siguientes objetivos:

  • Enseñar los rudimentos de la creación de programas en C# con interfase gráfica, usando las librerías System.Windows.Forms.

  • Aprender a configurar los elementos (widgets) más simples de una aplicación con interfase gráfica para el usuario (GUI).

  • Aprender a "hacer reaccionar" a los elementos gráficos (widgets) de la aplicación, "atando" adecuadamente un "evento" (como el hacer click en un botón) a una determinada "acción de respuesta del programa".

  • Vamos a desarrollar paso a paso ejemplos de aplicación que sólo necesiten elementos básicos de programación, como los vistos hasta este momento, sin muchas complicaciones de algoritmos.


Vamos a establecer una clave de colores para los códigos que pongamos de aquí en adelante.
En general, un código de un programar estará en color marrón.
Sin embargo, aquellas porciones de código que vayamos agregando para modificar versiones previas del programa, las indicaremos en azul, para poder distinguir bien la parte nueva agregada de la que ya estaba antes.



Nuestro primer objetivo es hacer una aplicación de ventana vacía, como esta:


Los pasos a seguir son los siguientes:

  • Abrir el programa Visual Studio y crear un proyecto nuevo, tal como se ha explicado en lecciones anteriores.

  • En dicho proyecto, crear un archivo nuevo, tal como se ha venido haciendo siempre, y pongámosle el nombre VS_GUISWF_Tutorial01_Vacia.

  • Antes de ponerse a programar como loco, hay que habilitar las librerías que permiten hacer aplicaciones gráficas. Como ya sabemos, hay varias posibilidades, principalmente las System.Windows.Forms y las Gtk#.
    Nosotros vamos a usar por ahora System.Windows.Forms.
    Para ello, debemos agregar a nuestro proyecto las Referencias correspondientes.
    Ya sabemos cómo hacer esto.
    Tan sólo recordemos que las Referencias que hay que agregar son las siguientes:

    System
    System.Windows.Forms
    System.Drawing


  • Ahora sí nos ponemos a programar.
    En primer lugar tenemos que escribir el código del método Main:


    static class Aplicacion_Vacia
    {
        static void Main()
        {
               
        }
    }


  • Ahora, para facilitar el uso de las librerías de System.Windows.Forms vamos a habilitar los espacios de nombres de las mismas, agregando las sentencias using correspondientes al principio del programa.
    El resultado de esto nos da este código:


    using System;
    using System.Windows.Forms;
    using System.Drawing;


    static class Aplicacion_Vacia
    {
        static void Main()
        {

        }
    }


  • Ahora vamos a "construir" el formulario de la aplicación.
    Tenemos que comprender en este punto de la cuestión, que construir el formulario equivale a la trastienda de una obra de teatro. Los actores se visten y maquillan detrás del telón, pero los espectadores (usuarios) no ven nada hasta que la obra "inicia".

    Así que el formulario lo construiremos un poco "a ciegas", sin saber en principio cómo quedará.

    Lo que hay que hacer es declarar una clase que herede las propiedades de la clase Form, que reside en la librería Windows.System.Forms.

    Esto se hace agregando una declaración como esta:


    public class Formulario : Form
    {

    }


    No nos preocupemos por la sintaxis, ni mucho menos por el significado de la palabra public. Eso lo veremos en el capítulo siguiente.

    Dentro de las llaves { ... } se ponen objetos que representarán a los widgets de la aplicación y también los métodos que los controlan.

    En el desplegable que sigue adjuntamos el código como va quedando hasta ahora.

    Código de la aplicación vacía hasta el momento

    using System;
    using System.Windows.Forms;
    using System.Drawing;

    static class Aplicacion_Vacia
    {
        static void Main()
        {


        }
    }

    // Clase para definir Formulario de aplicación:

    public class Formulario : Form
    {

    }


    [cerrar]


  • La clase Formulario que hemos introducido no hace nada por ahora. Para que haga algo al invocársela, se debe definir su método constructor.
    Se trata de una porción de código con el mismo nombre que la clase, y que se coloca dentro de ella.
    Tiene este aspecto:


        public Formulario()
        {
     
        }


    Obviamente este método por ahora no hace nada.
    Pero todo aquello que queremos que el Formulario realice al iniciarse por primera vez, debemos indicarlo mediante sentencias entre las llaves {   ...   } del método Formulario().

    Estado de la aplicación hasta ahora...



    using System;
    using System.Windows.Forms;
    using System.Drawing;

    static class Aplicacion_Vacia
    {
        static void Main()
        {

        }
    }

    // Clase para definir Formulario de aplicación:

    public class Formulario : Form
    {

        // Método constructor:
        public Formulario()
        {
     
        }

    }


    [cerrar]

  • Ahora deseamos al menos tener algo de control sobre la aplicación, comenzar a hacer algo.
    Lo único que haremos por ahora será manejar los atributos de ancho y largo del formulario principal de la aplicación.
    A este formulario lo estamos definiendo nosotros mismos, es una clase que se comportará del modo que le estamos indicando.
    En particular, estos atributos de tamaño los ha "heredado" de Form.

    Hay en Form una multitud de atributos que se pueden configurar, pero nosotros no debemos preocuparnos por eso ahora, no tiene demasiada importancia.
    Aceptaremos los valores por defecto de esos atributos.

    Sólo vamos a modificar el tamaño del formulario, y esto se hace dando un valor adecuado al atributo Form.ClientSize().
    Sin embargo, como hemos declarado que nuestro formulario hereda los atributos de Form, resulta que ClientSize() está directamente disponible dentro de nuestra clase Formulario.

    El tipo de datos de este atributo no es numérico, sino algo definido en las librerías... No vamos a entrar en detalles por ahora, sólo digamos que la manera correcta de darle un valor es a través del método Size() de la librería System.Drawing.

    La invocación es muy sencilla:


    ClientSize = new Size(300, 600);


    El primer número es el ancho, y el segundo número es el largo.
    O sea que estamos construyendo un formulario, cuya ventana de aplicación tendrá un tamaño de 300x600.

    Estado de la aplicación hasta ahora...



    using System;
    using System.Windows.Forms;
    using System.Drawing;

    static class Aplicacion_Vacia
    {
        static void Main()
        {

        }
    }

    // Clase para definir Formulario de aplicación:

    public class Formulario : Form
    {

        // Método constructor:
        public Formulario()
        {
              ClientSize = new Size(300, 600); 
        }

    }


    [cerrar]

  • Si ejecutamos la aplicación anterior, veremos que no hace nada. ¿Por qué?
    Mencionemos que un formulario es sólo una clase.
    Se necesita ahora crear un objeto que haga las veces de ventana de aplicación,  y cuyo tipo de datos sea el de la clase del formulario que estamos definiendo.

    Esto se hace mediante una declaración del tipo: new Formulario().

    Eso creará un objeto con las características indicadas en Formulario(), y en particular creará la ventana de la aplicación.
    Pero volvamos aquí a la comparación del teatro.

    Definir la clase Formulario equivale a "explicarle a los actores cómo será su vestuario".
    Hacer la invocación new Formulario() equivale a "hacer que los actores se vistan para la obra según las indicaciones antes recibidas, pero aún no se abre el telón a los espectadores".
    Para abrir el telón y que la obra comience, o sea, que en efecto aparezca la ventana de aplicaicón en la pantalla del usuario, se debe iniciar el bucle de ejecución de la aplicación, al tiempo que se le asigna el objeto creado mediante new Formulario().

    El bucle de la aplicación es un "estado de espera" del programa que está aguardando acciones del usuario.
    Ahora bien, para arrancar este bucle se utiliza el método Run.Application)() de la librería System.Windows.Forms.

    Todo lo descripto aquí se hace mediante una sola sentencia como la siguiente:


            Application.Run( new Formulario() );


    Esta sentencia, para que tenga efecto, debe estar en el flujo de ejecución de acciones del programa principal, o sea que la colocamos dentro de Main().
    Estado de la aplicación hasta ahora...



    using System;
    using System.Windows.Forms;
    using System.Drawing;

    static class Aplicacion_Vacia
    {
        static void Main()
        {
            Application.Run(new Formulario());
        }
    }

    // Clase para definir Formulario de aplicación:

    public class Formulario : Form
    {


        public Formulario()
        {
              ClientSize = new Size(300, 600); 
        }

    }


    [cerrar]
  • Nuestra aplicación vacía ya está lista.
    Recordemos guardar todo el proyecto mediante Archivo/Guardar todo...

    Ahora sólo tenemos que ejecutar el programa, como ya sabemos hacerlo (Depurar/Iniciar sin depurar).




A continuación, veremos cómo agregar un botón y que reaccione al hacer click sobre él.