elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Únete al Grupo Steam elhacker.NET


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  .NET (C#, VB.NET, ASP) (Moderador: kub0x)
| | | |-+  [TUTORIAL] [C#] Componente PictureBox para efectos gráficos en una aplicación
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: [TUTORIAL] [C#] Componente PictureBox para efectos gráficos en una aplicación  (Leído 9,096 veces)
DarK_FirefoX


Desconectado Desconectado

Mensajes: 1.263


Be the change you wanna see in te world


Ver Perfil
[TUTORIAL] [C#] Componente PictureBox para efectos gráficos en una aplicación
« en: 31 Octubre 2014, 02:11 am »

Tutorial: Uso del componente PictureBox para efectos gráficos en una aplicación de Windows en C#

0. Introducción

El presente tutorial tiene como objetivo presentar a través de la creación de una sencilla aplicación de C# los conceptos básicos sobre el uso de efectos gráficos bidimensionales en aplicaciones de Windows. Quizás esto no sea de mucha utilidad para muchos, pero cuando comenzaba a aprender Windows Forms, esto me fue muy útil.

A continuación presento un resumen las técnicas y habilidades que se abordan en este tutorial:

  • Organización de componentes visuales en un Windows Form usando las líneas de guía.
  • Utilización de la propiedad Image del componente PictureBox para mostrar imágenes de archivo.
  • Utilización del evento Paint del componente PictureBox para dibujar libremente en su superficie.
  • Uso de los tipos Graphics, Brush, Pen, Color, y el método FillRectangle() de la clase Graphics para generar efectos gráficos.
  • Utilización del tipo Enum para definir enumeraciones.

A continuación presento una serie de habilidades que se presuponen dominadas por ti y que son requeridas para entender completamente el contenido de este tutorial:

  • Declaración y uso de tipos básicos y arrays.
  • Implementación de métodos.
  • Uso de propiedades y eventos.
  • Creación de controles visuales en un Windows Form.
  • Uso de ciclos,  condicionales y en general de técnicas básicas de programación.

1. Diseño del formulario

La aplicación que queremos diseñar mostrará un único formulario con una rejilla y una serie de controles que permitirán cambiar la apariencia de dicha rejilla. Al hacer clic sobre la rejilla esta dibujará una de dos imágenes dependiendo del botón presionado.

Una vista preliminar de nuestro formulario en pleno funcionamiento sería la siguiente:



Comencemos entonces a ubicar los controles que necesitaremos sobre el formulario.

Para seguir un estilo facil de entender, usaremos para cada control un prefijo de tres o cuatro letras según el tipo del control seguido por un nombre que nos indique la función de cada instancia en nuestro formulario. Además, es una buena práctica usar identificadores en inglés por ser el idioma más generalizado entre los programadores del planeta.

Entonces, para nuestro formulario, usaremos el nombre frmDrawing, el prefijo indica que es una instancia de un control Windows Form, y el nombre indica que es un formulario cuya función fundamental está de alguna forma relacionada con el dibujado.

Generalmente los videojuegos dibujan sobre toda la pantalla, esto llama “Full Screen Mode”, algo así como modo a pantalla completa. Sin embargo, la mayoría de los videojuegos permiten también ser visualizados en una ventana de Windows. Esta ventana, como regla general tiene un tamaño cuya relación de aspecto es 4:3, y con mucha frecuencia es uno de los valores de resolución de escritorio que se pueden seleccionar en monitores que no son de pantalla ancha: 640x480, 800x600, 1024x768 píxeles, etc. Para seguir con esta línea asignaremos a la propiedad Size de nuestro formulario el valor 640;480.

Cambiemos ahora el titulo de nuestro formulario. Hacemos esto cambiando su propiedad Text que es de tipo string a PictureBox Tutorial. La mayoría de los controles visuales tienen una propiedad Text que de alguna forma está relacionada con el texto que estos controles muestran.

También queremos que el usuario no pueda cambiar el tamaño de nuestro formulario ni maximizarlo. Esto se logra poniendo la propiedad FormBorderStyle a FixedSingle y la propiedad MaximizeBox a False. Finalmente, para evitar efectos visuales no deseados cada vez que repintemos el formulario, pongamos su propiedad DoubleBuffered a True.

Ahora vamos a ubicar en el formulario un control PictureBox. Se puede encontrar fácilmente en Cuadro de herramientas (ToolBox). Renombrémoslo a pboxGrid indicando que de cierta forma representará una rejilla.

El PictureBox es un control que permite mostrar una imagen en su interior. Pero lo más interesante es que a través de un evento, podemos dibujar libremente en su interior usando la propiedad Graphics y personalizar de esta forma el contenido que queremos mostrar.

Como queremos pintar una especie de rejilla, vamos a hacer que nuestro PictureBox sea cuadrado, por lo tanto en su propiedad Size pondremos 400;400. Ahora ubiquémoslo acercando su extremo derecho e inferior a la esquina correspondiente del formulario hasta que aparezcan las líneas de guía. De esta forma se pueden ubicar controles visuales en un formulario guardando uniformidad en el espaciado entre estos.



Vamos a poner ahora su propiedad BorderStyle a FixedSingle para que los bordes sean visibles aun cuando no haya nada dibujado en su interior.

Ahora vamos a ubicar los controles restantes. Comenzamos por dos controles GroupBox que colocaremos a la derecha. Los llamaremos gboxGrid y gboxImage y sus textos serán Rejilla e Imágenes respectivamente.

Coloquemos el primero alineado con la parte superior del PictureBox y de un ancho tal que cubra el espacio delimitado por el PictureBox y el borde del formulario. Démosle un largo (propiedad Width) de 137. Coloquemos el segundo alineado entre la parte inferior del primero, la parte izquierda del PictureBox, y los bordes del formulario.

La imagen siguiente muestra este procedimiento:



Los GroupBox no son más que contenedores, es decir, controles que pueden contener otros controles en su interior y que se usan generalmente para organizar el formulario. Lo importante de los contenedores es que algunas de sus propiedades visuales influyen sobre sus “hijos”. Por ejemplo, la propiedad Location de cualquier control se refiere a la posición con respecto al borde superior izquierdo del contenedor más inmediato que lo contiene. En este sentido el formulario es el contenedor de más externo. De ahora en adelante, cuando vayamos a colocar controles en cualquier parte del formulario, asumiré que ya sabes como ubicarlos de forma que estén correctamente alineados, siguiendo los procedimientos mencionados hasta ahora.

Una propiedad que nos puede ser de utilidad una vez que hayamos ubicado correctamente nuestros controles es Locked que impedirá que movamos accidentalmente un control si su valor es True. Cuando el formulario está lleno de controles es bastante sencillo equivocarse al seleccionar un control y se puede volver caótico si no están bloqueados en su sitio. Bloqueemos entonces al PictureBox y a los dos GroupBox. De ahora en adelante cada vez que terminemos de ubicar un control en su sitio, asumiré que lo bloquearás (poniendo su propiedad Locked a True) para evitar futuros errores.

Como ya conocemos los procedimientos para ubicar controles, para ubicar los controles restantes simplemente escribiré el tipo, el nombre, y las propiedades que haya que asignar de la siguiente forma.

En el formulario, encima del PictureBox, agreguemos un Label (Name = lblTitle; Text = Haga clic en la rejilla para pintar en las cuadriculas con las imágenes seleccionadas.).

En el GroupBox de arriba, agreguemos los siguientes controles en el orden que se indica y correctamente alineados:

Label (Name = lblCount; Text = Cuadros por línea:)

NumericUpDown (Name = nudCount; Minimun = 2; Maximun = 20; Value = 10)

Label (Name = lblColorLine; Text = Color de línea:)

Panel (Name = pnlColorLine; Size = 30;20)

Label (Name = lblColorBack; Text = Color de fondo:)

Panel (Name = pnlColorBack; Size = 30;20)

Button (Name = btnRestart; Text = Reiniciar rejilla).

Los controles Panel también son contenedores. De hecho son los contenedores más sencillos. Pero en esta ocasión los vamos a usar exclusivamente para mostrar un color en su interior. Esto lo haremos cambiando sus propiedades BackColor a Black y White respectivamente. También sus propiedades BorderStyle a FixedSingle.

Al finalizar, su formulario debe verse así



En el GroupBox inferior vamos a agregar dos GroupBox más con las siguientes propiedades:

GroupBox (Name = gboxLeft; Text = Clic izquierdo)

GroupBox (Name = gboxRight; Text = Clic derecho)

Dentro de cada uno de estos nuevos GroupBox vamos a agregar un control PictureBox con las siguientes propiedades respectivamente:

PictureBox (Name = pboxLeft; BorderStyle = FixedSingle)

PictureBox (Name = pboxRight; BorderStyle = FixedSingle)

Recuerde bloquear todos sus controles (¿Lo habías olvidado?). Su formulario debería verse ahora así:



La propiedad Image de un PictureBox nos permite establecer una imagen de archivo como contenido del control. Lo que queremos hacer ahora es permitir al usuario elegir dicha imagen. Para esto vamos a agregar un control no visual llamado OpenFileDialog. El hecho de que sea un componente no visual hará que aparezca un icono en la parte inferior de la ventana de diseño en vez de un control sobre el formulario. Cambiemos su nombre a odlgImage.

Este componente nos permite mostrar un cuadro de diálogo similar al que aparece cuando queremos abrir un archivo desde cualquier aplicación (como Bloc de Notas) y obtener la dirección del o los archivos seleccionados por el usuario. La propiedad Filter de tipo string nos permitirá elegir que tipos de archivos permitiremos que sean seleccionables. Cambiemos su valor a: Archivos de imagen (*.jpg, *.png, *.bmp, *.gif)|*.JPG; *.PNG; *.BMP; *.GIF|Todos los archivos (*.*)|*.*. Este es un formato usado por el OpenFileDialog para especificar las extensiones válidas. Primero escribimos el texto que será visible para el usuario y separado por una barra vertical (|) las extensiones para dicha selección, separadas por punto y coma ( ; ) si es más de una, y así para cada opción que queramos brindar.

Cambiemos la propiedad Title a Seleccione un archivo de imagen. Este es el texto que será el título del cuadro de diálogo cuando se ejecute.

Agreguemos para finalizar otro cuadro de diálogo, esta vez uno que nos permitirá seleccionar un color, para usarlos más adelante. Sus propiedades:

ColorDialog (Name = cdlgColor).

2. Diseño e implementación de la lógica de la aplicación

Bien, al fin hemos llegado a la parte que más nos gusta: el código.  Después de pasar tanto tiempo diseñando la interfaz grafica de nuestra aplicación, ahora queremos que haga algo ¿no? Empecemos por listar las variables de instancia que vamos a necesitar y hacer un bosquejo de los métodos y algoritmos que tendremos que implementar.

El objetivo de nuestra aplicación es que el usuario pueda personalizar las propiedades de la rejilla que simularemos, y elegir dos imágenes de tal forma que al hacer clic izquierdo sobre una casilla vacía aparezca allí una imagen, y con clic derecho otra. Si la casilla está llena queremos intercambiar la imagen que está puesta si es diferente a la queremos poner o quitarla si es igual. Aunque no parezca algo muy útil, sirve para explicar el trabajo con estos tipos de componentes y el dibujado sobre componentes en Windows Forms, además con un poquito de imaginación se pueden hacer cosas más interesantes.

Vamos a necesitar por el momento dos variables de instancia: una para almacenar la cantidad de casillas que queremos y otra para almacenar los valores de cada casilla. La primera evidentemente será un entero, y la segunda un array. ¿De qué tipo? Podemos hacerlo de enteros, y asumir 0 para casillas blancas, 1 para casillas en las que se hizo clic izquierdo y 2 para clic derecho. Ciertamente funciona, sin embargo, para alguien que no sepa que significan estos valores, el código puede resultar algo confuso, y entonces tendríamos que poner comentarios explicando todo esto, etc. ¿Qué se puede hacer para evitar esto? Usaremos una cosa muy sencilla pero muy útil llamado Enum.

Código
  1. enum GridData { Blank, Left, Right }

De esta manera, una variable de tipo GridData nos permitirá conocer y asignar sin temor a ambiguedades dichos valores. Entonces nuestro array deberá ser de este tipo. Agreguemos entonces las siguientes líneas justo debajo del constructor de nuestro formulario:

Código
  1. enum GridData { Blank, Left, Right } //Valores que puede adoptar una casilla de la rejilla.
  2.  
  3. int count; //Cantidad de casillas que se dibujaran por linea
  4.  
  5. GridData[,] grid; //Array para almacenar los valores de la rejilla.

En tu implementación, una enumeración usa por defecto valores enteros, de forma que Blank = 0, Left = 1, Right = 2. Por lo tanto, al crear nuestro arreglo, automáticamente  todos sus elementos de inicializan a 0, es decir, a Blank, que es justamente lo que queremos.

Para asignar un valor a una variable de un tipo de enumeración de hace de la siguiente manera:

Código
  1. grid[i, j] = GridData.Blank;

Ahora vamos a usar nuestros cuadros de diálogo para permitir al usuario cambiar tanto las imágenes como los colores de la rejilla. Empecemos por las imágenes.

Note que el control PictureBox tiene una propiedad ImageLocation de tipo string que al ser asignada con una ubicación válida en el disco duro de una imagen, la asigna a la propiedad Image. Esto es justamente lo que necesitamos. Queremos entonces que al hacer doble clic sobre el PictureBox correspondiente, se abra el cuadro de diálogo y se asigne su ubicación a la imagen. Vayamos entonces al evento DoubleClick de nuestro control PictureBox llamado pboxLeft y hagamos doble clic para ir directamente al código.

Tenemos el siguiente código autogenerado para nosotros:

Código
  1. private void pboxLeft_DoubleClick(object sender, EventArgs e)
  2. {
  3.  
  4. }

Veamos los argumentos. El primer argumento representa a la instancia que lanzó el evento. El segundo argumento no nos interesa por ahora. Lo interesante es que podemos asignar este mismo método a ambos controles PictureBox e incluso saber cual de ellos fue el que lanzó el evento, para asignar la imagen al control correcto.

Para esto, debemos conocer que en C# existe la palabra clave as que, en pocas palabras, hace conversiones entre tipos por referencia compatibles. Es decir, se parece mucho a un casting, aunque tiene algunas diferencias notables. Por ahora, conformémonos con saber que nos permitirá convertir la variable sender de tipo object en una variable de tipo PictureBox, ya que sabemos que efectivamente fue un PictureBox quien lanzó este evento.

Agreguemos la línea:

Código
  1. if (odlgImage.ShowDialog() == DialogResult.OK)
  2.     (sender as PictureBox).ImageLocation = odlgImage.FileName;

Aquí no estamos haciendo nada nuevo, simplemente lanzando el método ShowDialog() y comprobando su valor de retorno (de tipo DialogResult que, dicho sea de paso, también es una enumeración) que en caso de ser OK indica que el usuario seleccionó un archivo y presionó el botón Abrir, para entonces asignar el valor de la propiedad FileName (que contiene la dirección completa del archivo, cortesía del OpenFileDialog) a la propiedad ImageLocation del PictureBox adecuado.

Ahora seleccionamos el PictureBox llamado pboxRight y en su evento DoubleClick le asignamos el método que acabamos de escribir.

Ya podemos probar nuestra aplicación y ver que efectivamente asigna a cada PictureBox la imagen seleccionada.

Sin embargo, tenemos un problema: si seleccionamos una imagen demasiado grande como para caber en el control, será recortada. En vez de esto, lo que queremos es que la imagen se reduzca de tamaño hasta caber en el control, pero sin deformarse. Esto lo logramos cambiando la propiedad SizeMode a Zoom.

Para seleccionar los colores de cada Panel vamos a escribir un método similar en el evento Click de uno de ellos y asignárselo al otro. Debido a la semejanza con el método anterior, lo pongo a continuación sin más preámbulo:

Código
  1. private void pnlColorLine_Click(object sender, EventArgs e)
  2. {
  3. if (cdlgColor.ShowDialog() == DialogResult.OK)
  4.     (sender as Panel).BackColor = cdlgColor.Color;
  5. }
  6.  

Solamente agregar que las propiedades Color y BackColor de tipo Color de ambos controles sirven para representar el color seleccionado por el usuario en el diálogo y el color de fondo del control.

Si probamos la aplicación ahora veremos que podemos cambiar el color de los controles Panel haciendo clic sobre ellos.

Ahora vamos a implementar el método que asiganará los valores a nuestras variables de instancia, y que además será el llamado al hacer clic sobre el botón btnRestart:

Código
  1. private void RestartGrid()
  2. {
  3.     count = (int)nudCount.Value;
  4.     grid = new GridData[count, count];
  5.     pboxGrid.Refresh();
  6. }

Aquí solo queremos agregar que el método Refresh() de cualquier control visual lo que hace es volver a pintar el control, y es llamado automáticamente cada vez que es necesario (por ejemplo, al cambiar el tamaño o posición de la ventana).

Finalmente, en los eventos Click del botón bntRestart, y Load del formulario agregamos la línea:

Código
  1. RestartGrid();

Hemos terminado con esta sección, así que ha llegado la hora de pintar.

3. Dibujado sobre el PictureBox

Para pintar sobre nuestro PictureBox, en específico sobre la instancia pboxGrid, vamos a implementar un método para su evento Paint, que es el evento lanzado cada vez que hay que pintar el contenido del control (por ejemplo, al llamar al método Refresh()).

Veamos los argumentos del método:

Código
  1. private void pboxGrid_Paint(object sender, PaintEventArgs e)
  2. {
  3.  
  4. }

Ahora nos centraremos en el argumento e de tipo PaintEventArgs que contiene información que nos será muy útil sobre este evento. Por ejemplo, la propiedad Graphics de este argumento es de tipo Graphics, que es el tipo que encapsula los métodos y propiedades más comunes para efectos de gráficos bidimensionales, y representa en este caso el área dentro del PictureBox disponible para dibujar.

Lo primero que haremos será pintar el fondo. Para eso escribiremos las siguientes líneas:

Código
  1. SolidBrush b = new SolidBrush(pnlColorBack.BackColor);
  2. e.Graphics.FillRectangle(b, e.ClipRectangle);

El tipo SolidBrush representa un objeto usado para rellenar, por eso esta sobrecarga de su constructor recibe un argumento de tipo Color. Es algo así como la representación de una brocha. El método FillRectangle() por su parte lo que hace es rellenar un rectángulo con una brocha determinada. En este caso usamos nuestra brocha ya creada, y la propiedad ClipRectangle que nos devuelve el rectángulo que representa el área que tenemos disponible para pintar, que es justamente lo que necesitamos colorear.

Ahora vamos a hacer las líneas. Si para rellenar necesitábamos una brocha, para hacer las líneas ¿que necesitamos? Evidentemente, un pincel. Crearemos un pincel con la siguiente línea:

Código
  1. Pen p = new Pen(pnlColorLine.BackColor, 1);

Esta sobrecarga del constructor recibe un color y un entero para el ancho del pincel.

Para hacer líneas tenemos el método DrawLine() del cual usaremos una sobrecarga que recibe cuatro valores enteros, las coordenadas x e y iniciales y las coordenadas  x e y finales. Por tanto, lo que haremos será hacer un ciclo, calculando cada vez la posición de la nueva línea. ¿Cuántas líneas necesitamos? Bueno, si tenemos count cuadrículas, y tenemos las dos lineas de cada borde, necesitamos count – 1 líneas intermedias, ¿verdad? Además el ancho de cada línea será:

Código
  1. int width = pboxGrid.Width / count;

Y nuestro ciclo tendrá entonces la forma:

Código
  1. for (int i = 1; i < count; i++)
  2. {
  3.    . . . .
  4. }

Ahora podemos escribir las sentencias que dibujarán nuestras líneas dentro del ciclo. Como sabemos, la primera posición es (0;0), por eso restamos 1 a la posición en cada línea para contrarrestar el hecho de que el primer pixel tenga posición 0.

Código
  1.  
  2. {
  3.     e.Graphics.DrawLine(p, i * width - 1, 0, i * width - 1, pboxGrid.Height);
  4.     e.Graphics.DrawLine(p, 0, i * width - 1, pboxGrid.Width,  i * width - 1);
  5. }
  6.  

Aquí no hemos hecho nada más que calcular la posición de cada línea según su ordinalidad (dada por la variable i de control del ciclo) y dibujar una línea usando el método ya explicado DrawLine().

Ahora solo nos queda dibujar la imagen correspondiente en cada casilla según el valor de dicha casilla. Pero antes de dibujar las imágenes, vamos a asegurarnos que el usuario haya seleccionado una imagen para cada valor. Por eso encapsulamos todo en un gran if para evitarnos referencias nulas.

Código
  1. if (pboxLeft.Image != null && pboxRight.Image != null)
  2. {
  3.    for (int i = 0; i < count; i++)
  4.       for (int j = 0; j < count; j++)
  5.           switch (grid[i, j])
  6.           {
  7.             . . . .
  8.           }
  9. }
  10.  

Estos son los ciclos clásicos usados para recorrer una matriz bidimensional, y el switch lo usaremos para elegir que imagen dibujar según el valor del elemento de la matriz.

Para dibujar una imagen usaremos el método DrawImage() de la clase Graphics, en particular una sobrecarga que nos permite especificar la posición de la imagen, y sus dimensiones, lo cuál en última instancia nos pemitirá redimensionar nuestra imagen al tamaño deseado:

Código
  1. case GridData.Left:
  2.      e.Graphics.DrawImage(pboxLeft.Image, i * width, j * width, width - 1, width - 1);
  3.      break;
  4. case GridData.Right:
  5.      e.Graphics.DrawImage(pboxRight.Image, i * width, j * width, width - 1, width - 1);
  6.      break;
  7.  

El primer argumento es la imagen deseada, y los restantes representan como ya dijimos las coordenadas x e y de la esquina superior izquierda de la imagen, y sus dimensiones. Como las casillas son de ancho width y las líneas son de ancho 1 entonces nuestras imágenes tienen que ser de ancho width1.

Al terminar esta sección ya conocemos lo suficiente para dibujar sobre un PictureBox, sin embargo, al correr nuestra aplicación no sucede nada más que el dibujado de la rejilla. Esto se debe a que aún necesitamos implementar que sucederá al hacer clic sobre la rejilla.

4. Uso del mouse en el evento MouseClick

Bien, por último, vamos a implementar el método que responderá al evento MouseClick de pboxGrid. Este evento es lanzado al hacer click con el mouse, y lo preferimos al evento Click porque nos provee de información relacionada con las coordenadas y los botones pulsados del mouse.

Como siempre, la signatura del método autogenerado:

Código
  1. private void pboxGrid_MouseClick(object sender, MouseEventArgs e)
  2. {
  3.  
  4. }

El argumento e de tipo MouseEventsArgs nos provee de toda la información que necesitaremos relacionada con el mouse. Por ejemplo, la posicion X e Y del click y los botones pulsados. Comencemos por declarar esta variable que nos servirá para decidir que valor poner en el elemento adecuado del array:

Código
  1. GridData data = GridData.Blank;

Ahora necesitamos calcular que posición ocupa en el array la posición del clic del mouse, determinada por las propiedades X e Y de e

Código
  1. int i = e.X * count / pboxGrid.Width;
  2. int j = e.Y * count / pboxGrid.Height;

Esto es sencillamente un poco de álgebra básica. La coordenada en píxeles es a la longitud de la rejilla, como la posición del array (casilla elegida) es a la cantidad de casillas.

Ahora elegimos el valor de data según el botón del mouse que se haya pulsado. Esta información viene en la propiedad Button y es casualmente un tipo de enumeración.

Código
  1. switch (e.Button)
  2. {
  3.    case MouseButtons.Left:
  4.         data = GridData.Left;
  5.         break;
  6.    case MouseButtons.Right:
  7.         data = GridData.Right;
  8.         break;
  9. }
  10.  

Por último, asignamos el valor de data a la posición del array, según el valor que ya estuviera allí, usando el arhiconocido operador ternario:

Código
  1. grid[i, j] = (grid[i, j] == data) ? GridData.Blank : data;

Y… repintamos el PictureBox.

Código
  1. pboxGrid.Refresh();

Ahora sí nuestra aplicación está completa. Podemos correrla y comprobar que hace exactamente lo que queremos.

5. Conclusiones

Espero sinceramente que este tutorial haya sido de utilidad. Quedan muchísimos métodos y propiedades dentro de la clase Graphics con los que jugar. Lo demás es ponerle imaginación y no cohibirse a la hora de “meter un dedo” donde quiera que queramos husmear, pues a veces, es la única forma de dominar el arte de la programación.


« Última modificación: 31 Octubre 2014, 06:01 am por DarK_FirefoX » En línea

elezekiel

Desconectado Desconectado

Mensajes: 246


Ver Perfil
Re: [TUTORIAL] [C#] Componente PictureBox para efectos gráficos en una aplicación
« Respuesta #1 en: 31 Octubre 2014, 06:15 am »

me baje todo y lo guarde para leerlo tranquilo en cualquier momento de locura que tenga, solo tengo una palabra para esto que no manejo para nada bien c#


bri llan te.


gracias mostro muchos novatos te lo agradeceran.


En línea

DarK_FirefoX


Desconectado Desconectado

Mensajes: 1.263


Be the change you wanna see in te world


Ver Perfil
Re: [TUTORIAL] [C#] Componente PictureBox para efectos gráficos en una aplicación
« Respuesta #2 en: 4 Noviembre 2014, 04:01 am »

Que bueno que te haya sido de ayuda, si tienes alguna duda pregunta! ;)
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines