Efectos de Transición de Imágenes
(Actualizado) Fecha: 01/Abr/2004 (02/Abr/2004) |
. |
Este proyecto explica como realizar efectos de transición (movimiento) al estilo de los de Microsoft PowerPoint con GDI+.
Para eso vamos a usar un objeto Graphics y un objeto TextureBrush para dibujar sobre una imagen.
Para crear el proyecto de ejemplo, abrir el Visual Studio y seleccionar "Aplicación para Windows".
Vamos a usar un PictureBox donde pondremos una imagen donde dibujaremos los efectos; un ListBox que va a tener listados los efectos; un Botón para reproducirlos y un ComboBox para modificar la velocidad de los efectos.
Copiar el siguiente código y pegarlo en la vista de código del formulario "Form1" sobrescribiendo
todo el código que se encuentre.
Option Explicit On Option Strict OnImports System Imports System.Drawing.Drawing2D Imports System.Drawing.Imaging#Region " Nota Importante "'PARA EVITAR PARPADEO EN EFECTOS VISUALES DE ESTE TIPO CON IMAGENES, 'DIBUJAR SOBRE UNA IMAGEN VACIA UBICADA EN UN CONTROL, 'Y REFRESCAR EL CONTROL (METODO REFRESH) EN CADA ITERACIÓN 'DE BUCLE O PASADA DE TIMER.#End RegionPublic Class frmEfectos Inherits System.Windows.Forms.Form#Region " Código generado por el Diseñador de Windows Forms "Public Sub New() MyBase.New()'El Diseñador de Windows Forms requiere esta llamada. InitializeComponent() 'Agregar cualquier inicialización después de la llamada a InitializeComponent()'Iniciamos algunos elementos de nuestra interface Iniciar() End Sub'Form reemplaza a Dispose para limpiar la lista de componentes. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub'Requerido por el Diseñador de Windows Forms Private components As System.ComponentModel.IContainer'NOTA: el Diseñador de Windows Forms requiere el siguiente procedimiento 'Puede modificarse utilizando el Diseñador de Windows Forms. 'No lo modifique con el editor de código. Friend WithEvents pic As System.Windows.Forms.PictureBox Friend WithEvents lbEfectos As System.Windows.Forms.ListBox Friend WithEvents btnReproducir As System.Windows.Forms.Button Friend WithEvents lbSpeed As System.Windows.Forms.Label Friend WithEvents lblMulti As System.Windows.Forms.Label Friend WithEvents cboEjes As System.Windows.Forms.ComboBox Friend WithEvents cboSpeed As System.Windows.Forms.ComboBox <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() Me.pic = New System.Windows.Forms.PictureBox() Me.lbEfectos = New System.Windows.Forms.ListBox() Me.btnReproducir = New System.Windows.Forms.Button() Me.lbSpeed = New System.Windows.Forms.Label() Me.cboEjes = New System.Windows.Forms.ComboBox() Me.lblMulti = New System.Windows.Forms.Label() Me.cboSpeed = New System.Windows.Forms.ComboBox() Me.SuspendLayout() ' 'pic ' Me.pic.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle Me.pic.Location = New System.Drawing.Point(205, 82) Me.pic.Name = "pic" Me.pic.Size = New System.Drawing.Size(581, 359) Me.pic.TabIndex = 0 Me.pic.TabStop = False ' 'lbEfectos ' Me.lbEfectos.HorizontalScrollbar = True Me.lbEfectos.Items.AddRange(New Object() {"Barrido Horizontal", "Barrido Vertical", "Circulos Concentricos", "División Horizontal Entrante", "División Horizontal Saliente", "División Vertical Entrante", "División Vertical Saliente", "Empuja División Lados", "Empuja División Topes", "Empujar a la Derecha", "Empujar a la Izquierda", "Empujar en Diagonal (ángulo inferior derecho)", "Empujar en Diagonal (ángulo inferior izquierdo)", "Empujar en Diagonal (ángulo superior derecho)", "Empujar en Diagonal (ángulo superior izquierdo)", "Empujar Hacia Abajo", "Empujar Hacia Arriba", "Persianas Horizontales Abajo", "Persianas Horizontales Arriba", "Persianas Verticales Derecha", "Persianas Verticales Izquierda", "Rueda en sentido de las agujas del Reloj", "Rueda Multiple", "Simetrico"}) Me.lbEfectos.Location = New System.Drawing.Point(8, 82) Me.lbEfectos.Name = "lbEfectos" Me.lbEfectos.Size = New System.Drawing.Size(182, 290) Me.lbEfectos.Sorted = True Me.lbEfectos.TabIndex = 0 ' 'btnReproducir ' Me.btnReproducir.Location = New System.Drawing.Point(8, 468) Me.btnReproducir.Name = "btnReproducir" Me.btnReproducir.Size = New System.Drawing.Size(90, 34) Me.btnReproducir.TabIndex = 1 Me.btnReproducir.Text = "Reproducir" ' 'lbSpeed ' Me.lbSpeed.Location = New System.Drawing.Point(8, 394) Me.lbSpeed.Name = "lbSpeed" Me.lbSpeed.Size = New System.Drawing.Size(89, 20) Me.lbSpeed.TabIndex = 3 Me.lbSpeed.Text = "Velocidad" Me.lbSpeed.TextAlign = System.Drawing.ContentAlignment.MiddleCenter ' 'cboEjes ' Me.cboEjes.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList Me.cboEjes.ItemHeight = 13 Me.cboEjes.Items.AddRange(New Object() {"2", "3", "4", "8"}) Me.cboEjes.Location = New System.Drawing.Point(101, 427) Me.cboEjes.Name = "cboEjes" Me.cboEjes.Size = New System.Drawing.Size(89, 21) Me.cboEjes.TabIndex = 4 Me.cboEjes.Visible = False ' 'lblMulti ' Me.lblMulti.Location = New System.Drawing.Point(8, 427) Me.lblMulti.Name = "lblMulti" Me.lblMulti.Size = New System.Drawing.Size(89, 20) Me.lblMulti.TabIndex = 5 Me.lblMulti.Text = "Nº de Ejes" Me.lblMulti.TextAlign = System.Drawing.ContentAlignment.MiddleCenter Me.lblMulti.Visible = False ' 'cboSpeed ' Me.cboSpeed.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList Me.cboSpeed.Items.AddRange(New Object() {"Rápido", "Medio", "Lento"}) Me.cboSpeed.Location = New System.Drawing.Point(101, 394) Me.cboSpeed.Name = "cboSpeed" Me.cboSpeed.Size = New System.Drawing.Size(89, 21) Me.cboSpeed.TabIndex = 6 ' 'frmEfectos ' Me.AcceptButton = Me.btnReproducir Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.AutoScroll = True Me.ClientSize = New System.Drawing.Size(804, 525) Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.cboSpeed, Me.lblMulti, Me.cboEjes, Me.lbSpeed, Me.btnReproducir, Me.lbEfectos, Me.pic}) Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog Me.MinimumSize = New System.Drawing.Size(700, 550) Me.Name = "frmEfectos" Me.Text = "Efectos" Me.WindowState = System.Windows.Forms.FormWindowState.Maximized Me.ResumeLayout(False)End Sub#End Region#Region " Enumeraciones de Efectos "'Enumeración de Efectos Private Enum Efectos BarridoH = 0 BarridoV Circulos DivisiónH_Entrante DivisiónH_Saliente DivisiónV_Entrante DivisiónV_Saliente Empuja_División_Lados Empuja_División_Topes Empujar_Derecha Empujar_Izquierda Empujar_DiagonalID Empujar_DiagonalII Empujar_DiagonalSD Empujar_DiagonalSI Empujar_Abajo Empujar_Arriba PersianasH_Abajo PersianasH_Arriba PersianasV_Derecha PersianasV_Izquierda Rueda RuedaMultiple Simetrico End Enum'Enumeración de Efectos de Rueda Multiple Private Enum Ejes DosEjes = 0 TresEjes CuatroEjes OchoEjes End Enum#End Region#Region " Variables a nivel de modulo "'Control Timer que controlará los Efectos Private Tiempo As New Timer() 'Velocidad de los efectos Private VelocidadEfecto As Integer'Cuenta las veces que se debe ejecutar el evento Tick para cada efecto Private Contador As Integer'Contiene una copia de la imagén usada Private bmCopia As Bitmap 'Creamos un objeto Graphics para dibujar en Copia Private Gr As Graphics 'Creamos un TextureBrush con la textura de la imágen 'del PictureBox Private Brocha As TextureBrush 'Contienen el Ancho y Alto 'de la Imágen respectivamente Private AnchoImagen, AltoImagen As Single#Region " Variables especificas de Efectos "'Ángulo de giro Private AnguloGiro As Single'Cantidad en que se aumentan las transformaciones de ejes. Private xAumentaPos, yAumentaPos As Single'Determina si es la primera vez que se ejecuta un efecto Private EsPrimera As Boolean 'Aumento progresivo de los dibujos Private Aumento As Single#End Region#End Region'Inicia las variables de nivel de modulo y 'establece algunas propiedades de la interface Private Sub Iniciar() 'Cargamos la imagen. Si no se descarga el proyecto de ejemplo,'ASEGURARSE DE UBICAR UNA IMAGEN VÁLIDA en la línea siguiente pic.Image = New Bitmap("..\Dibujo1.jpg") pic.SizeMode = PictureBoxSizeMode.AutoSize 'Hay imagenes que tienen un formato de pixel 'que no permite crear un objeto Graphics para dibujar sobre 'ellas, por eso creamos una 'copia de pic.Image,del mismo tamaño 'y con un formato de pixel que no de problemas bmCopia = New Bitmap(pic.Image.Width, pic.Image.Height, PixelFormat.Format32bppArgb) 'Establecemos las variables de nivel de modulo AnchoImagen = bmCopia.Width AltoImagen = bmCopia.Height 'Controlador del evento Tick del objeto Timer AddHandler Tiempo.Tick, AddressOf TiempoEfectos Tiempo.Interval = 100End Sub'Seleccionamos el primer elemento del ListBox y los ComboBox para que todo quede listo para usar. Private Sub frmEfectos_Load(ByVal sender As Object, ByVale As System.EventArgs) Handles MyBase.Load lbEfectos.SetSelected(0, True) cboSpeed.SelectedIndex = 1 cboEjes.SelectedIndex = 0 End Sub'Inicia objetos, variables y controles Private Sub EstableceObjetos() 'Iniciamos el objeto Graphics Gr = Graphics.FromImage(bmCopia) 'Iniciamos el objeto TextureBrush Brocha = New TextureBrush(pic.Image) 'Asignamos bmCopia a el PictureBox pic.Image = bmCopia 'Limpiamos el contenido de bmCopia Gr.Clear(pic.BackColor) 'Elección de Velocidades Select Case cboSpeed.SelectedItem.ToString Case "Rápido" VelocidadEfecto = 5 Case "Medio" VelocidadEfecto = 15 Case "Lento" VelocidadEfecto = 30 End Select'Deshabilitamos controles hasta que se termine el efecto btnReproducir.Enabled = False lbEfectos.Enabled = False 'Reiniciamos variables Contador = 0 Aumento = 0 AnguloGiro = 0 xAumentaPos = 0 yAumentaPos = 0 EsPrimera = True 'Iniciamos el objeto Timer Tiempo.Start() End Sub'Muestra los controles de los efectos de Rueda Multiple Private Sub lbEfectos_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lbEfectos.SelectedValueChanged lblMulti.Visible = (lbEfectos.SelectedIndex = Efectos.RuedaMultiple) cboEjes.Visible = (lbEfectos.SelectedIndex = Efectos.RuedaMultiple) End Sub'Reproduce el Efecto seleccionado en el ListBox Private Sub btnReproducir_Click(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles btnReproducir.Click, lbEfectos.DoubleClick'Iniciamos los objetos de dibujo ,el PictureBox y el Timer EstableceObjetos()End Sub'Controlador del evento Tick del control Timer Private Sub TiempoEfectos(ByVal sender As System.Object, ByVal e As System.EventArgs)Try 'Ejecutamos cada 100 milesimas de segundo, el efecto selecionado Select Case lbEfectos.SelectedIndex Case Efectos.BarridoH Barrido(Efectos.BarridoH) Case Efectos.BarridoV Barrido(Efectos.BarridoV) Case Efectos.Circulos Circulos() Case Efectos.DivisiónH_Entrante DivisionH(Efectos.DivisiónH_Entrante) Case Efectos.DivisiónH_Saliente DivisionH(Efectos.DivisiónH_Saliente) Case Efectos.DivisiónV_Entrante DivisionV(Efectos.DivisiónV_Entrante) Case Efectos.DivisiónV_Saliente DivisionV(Efectos.DivisiónV_Saliente) Case Efectos.Empujar_Abajo Empujar(Efectos.Empujar_Abajo) Case Efectos.Empujar_Arriba Empujar(Efectos.Empujar_Arriba) Case Efectos.Empujar_Derecha Empujar(Efectos.Empujar_Derecha) Case Efectos.Empujar_DiagonalID Empujar(Efectos.Empujar_DiagonalID) Case Efectos.Empujar_DiagonalII Empujar(Efectos.Empujar_DiagonalII) Case Efectos.Empujar_DiagonalSD Empujar(Efectos.Empujar_DiagonalSD) Case Efectos.Empujar_DiagonalSI Empujar(Efectos.Empujar_DiagonalSI) Case Efectos.Empujar_Izquierda Empujar(Efectos.Empujar_Izquierda) Case Efectos.PersianasH_Abajo PersianasH(Efectos.PersianasH_Abajo) Case Efectos.PersianasH_Arriba PersianasH(Efectos.PersianasH_Arriba) Case Efectos.PersianasV_Derecha PersianasV(Efectos.PersianasV_Derecha) Case Efectos.PersianasV_Izquierda PersianasV(Efectos.PersianasV_Izquierda) Case Efectos.Rueda Rueda() Case Efectos.Simetrico Simetrico() Case Efectos.RuedaMultiple 'Seleciona la variante de efecto de Rueda Multiple Select Case cboEjes.SelectedIndex Case 0 RuedaMultiple(Ejes.DosEjes) Case 1 RuedaMultiple(Ejes.TresEjes) Case 2 RuedaMultiple(Ejes.CuatroEjes) Case 3 RuedaMultiple(Ejes.OchoEjes) End SelectCase Efectos.Empuja_División_Lados EmpujaDivision(Efectos.Empuja_División_Lados) Case Efectos.Empuja_División_Topes EmpujaDivision(Efectos.Empuja_División_Topes) End SelectCatch ex As System.Exception End Try End SubEfectos con Persianas.Estos efectos dibujan una imagen con franjas que se mueven en una misma dirección,como persianas que se cierran.Para generar este tipo de efectos, la idea es dividir la imagen en rectángulos,de igual tamaño, e ir dibujándolos todos al mismo tiempo pero solamente una franja de cadarectángulo por vez (ejecución del evento del Timer). Para poder ir dibujando todos los rectángulos a la vez,lo que hacemos es primero dibujarlos todos en memoria y luego los mostramos de una sola vez.'Genera los efectos con Persianas Horizontales Private Sub PersianasH(ByVal Efecto As Efectos)Dim Persiana As Integer 'Total de Persianas Dim TotalPersianas As Integer= 12 Dim Velocidad As Integer= TotalPersianas * VelocidadEfecto 'Si es la primera vez que se llega aquí, establecemos algunas variables If EsPrimera ThenIf Efecto = Efectos.PersianasH_Abajo Then Aumento = 0 ElseIf Efecto = Efectos.PersianasH_Arriba Then Aumento = AltoImagen / TotalPersianas End If EsPrimera = FalseEnd IfFor Persiana = 0 To TotalPersianas - 1 'Dibuja un trozo de cada una de las persianas por cada ejecución del evento Dim SupIzquierda As New PointF(0, Aumento + (Persiana * (AltoImagen / TotalPersianas))) Dim TamañoPersiana As New SizeF(AnchoImagen, AltoImagen / Velocidad) Dim RecPersiana As New RectangleF(SupIzquierda, TamañoPersiana) Gr.FillRectangle(Brocha, RecPersiana) Next pic.Refresh() 'Aumentamos el tamaño de cada persiana para la próxima vez que se dibujen If Efecto = Efectos.PersianasH_Abajo Then Aumento += AltoImagen / Velocidad ElseIf Efecto = Efectos.PersianasH_Arriba Then Aumento -= AltoImagen / Velocidad End If 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado VelocidadEfecto + 1 veses terminamos el efecto If Contador = VelocidadEfecto + 1 Then DescargaObjetos() End IfEnd Sub'Genera los efectos con Persianas Verticales Private Sub PersianasV(ByVal Efecto As Efectos)Dim Persiana As IntegerDim TotalPersianas As Integer= 12 Dim Velocidad As Integer= TotalPersianas * VelocidadEfecto 'Si es la primera vez que se llega aquí, establecemos algunas variables If EsPrimera ThenIf Efecto = Efectos.PersianasV_Izquierda Then Aumento = 0 ElseIf Efecto = Efectos.PersianasV_Derecha Then Aumento = AnchoImagen / TotalPersianas End If EsPrimera = FalseEnd IfFor Persiana = 0 To TotalPersianas - 1 'Dibuja un trozo de cada una de las persianas por cada ejecución del evento Dim SupIzquierda As New PointF(Aumento + (Persiana * (AnchoImagen / TotalPersianas)), 0) Dim TamañoPersiana As New SizeF(AnchoImagen / Velocidad, AltoImagen) Dim RecPersiana As New RectangleF(SupIzquierda, TamañoPersiana) Gr.FillRectangle(Brocha, RecPersiana) Next pic.Refresh() 'Aumentamos el tamaño de cada persiana para la próxima vez que se dibujen If Efecto = Efectos.PersianasV_Izquierda Then Aumento += AnchoImagen / Velocidad ElseIf Efecto = Efectos.PersianasV_Derecha Then Aumento -= AnchoImagen / Velocidad End If 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado VelocidadEfecto + 1 veses terminamos el efecto If Contador = VelocidadEfecto + 1 Then DescargaObjetos() End IfEnd SubEfecto de Persianas Horizontales.Efectos de Empuje.Para generar este tipo de efectos, lo que vamos a hacer es cambiar el centro de los ejes de coordenadasdel objeto Graphics con el método TranslateTransform, lo suficientemente haciaun lado u otro para que inicialmente la imagen se dibuje pero no se vea, y luego con deshaciendola transformación progresivamente y volviendo a dibujar cada vez toda la imagen.El efecto que se crea es de una imagen que se mueve de un lado para otro, como si la empujaran.
'Genera los efectos de Empuje Private Sub Empujar(ByVal Efecto As Efectos) 'Si es la primera vez que se llega aquí, 'Establecemos las transformaciónes iniciales 'según la variante de efecto de Empuje If EsPrimera Then If Efecto = Efectos.Empujar_Abajo Then Gr.TranslateTransform(0, -AltoImagen) xAumentaPos = 0 : yAumentaPos = AltoImagen / VelocidadEfecto ElseIf Efecto = Efectos.Empujar_Arriba Then Gr.TranslateTransform(0, AltoImagen) xAumentaPos = 0 : yAumentaPos = -AltoImagen / VelocidadEfecto ElseIf Efecto = Efectos.Empujar_Derecha Then Gr.TranslateTransform(-AnchoImagen, 0) xAumentaPos = AnchoImagen / VelocidadEfecto : yAumentaPos = 0 ElseIf Efecto = Efectos.Empujar_Izquierda Then Gr.TranslateTransform(AnchoImagen, 0) xAumentaPos = -AnchoImagen / VelocidadEfecto : yAumentaPos = 0 ElseIf Efecto = Efectos.Empujar_DiagonalSI Then Gr.TranslateTransform(-AnchoImagen, -AltoImagen) xAumentaPos = AnchoImagen / VelocidadEfecto : yAumentaPos = AltoImagen / VelocidadEfecto ElseIf Efecto = Efectos.Empujar_DiagonalSD Then Gr.TranslateTransform(AnchoImagen, -AltoImagen) xAumentaPos = -AnchoImagen / VelocidadEfecto : yAumentaPos = AltoImagen / VelocidadEfecto ElseIf Efecto = Efectos.Empujar_DiagonalII Then Gr.TranslateTransform(-AnchoImagen, AltoImagen) xAumentaPos = AnchoImagen / VelocidadEfecto : yAumentaPos = -AltoImagen / VelocidadEfecto ElseIf Efecto = Efectos.Empujar_DiagonalID Then Gr.TranslateTransform(AnchoImagen, AltoImagen) xAumentaPos = -AnchoImagen / VelocidadEfecto : yAumentaPos = -AltoImagen / VelocidadEfecto End If EsPrimera = FalseEnd If'Limpiamos el contenido de bmCopia Gr.Clear(pic.BackColor) 'Dibujamos la imagen con las transformaciónes de ejes. Dim RecEmpuja As New RectangleF(0, 0, AnchoImagen, AltoImagen) Gr.FillRectangle(Brocha, RecEmpuja) Gr.TranslateTransform(xAumentaPos, yAumentaPos) pic.Refresh() 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado VelocidadEfecto + 1 veses terminamos el efecto If Contador = VelocidadEfecto + 1 Then DescargaObjetos() End IfEnd SubEfecto de Empuje Diagonal.Efectos de División.Hay cuatro variantes; dos de ellas dibujan la imagen desde los lados (o los topes) hacia el centrocomo puertas deslizantes que se cierran. Y las otras dos hacen lo opuesto, o sea, dibujandesde el centro hacia los extremos. Lo que vamos a hacer es dibujarde a dos rectángulos al mismo tiempo por iteración aumentándoles el tamaño. Esto lo podemos hacercomo en algunos de los efectos anteriores, mediante lo que se llama DoubleBuffer, que consiste enir dibujando primero en memoria todo para luego mostrarlo, de esta manera se logran efectos más "limpios",o sea, con menos parpadeos y en nuestro caso, también nos sirve para aparentar visualmenteque varios dibujos se crean en el mismo instante.'Genera los efectos de Divición Horizontal Private Sub DivisionH(ByVal Efecto As Efectos)Dim Velocidad As Single= AnchoImagen / VelocidadEfecto 'Si es la primera vez que se llega aquí, establecemos algunas variables If EsPrimera ThenIf Efecto = Efectos.DivisiónH_Entrante Then Aumento = 0 ElseIf Efecto = Efectos.DivisiónH_Saliente Then Aumento = AnchoImagen / 2 End IfEsPrimera = FalseEnd IfDim RecDivision As New RectangleF(Aumento, 0, Velocidad, AltoImagen) Dim RecDivision2 As New RectangleF(AnchoImagen - Aumento, 0, Velocidad, AltoImagen) 'Dibujamos los rectangulos de división Gr.FillRectangle(Brocha, RecDivision) Gr.FillRectangle(Brocha, RecDivision2)pic.Refresh() 'Aumentamos el tamaño de los rectangulos Aumento += Velocidad 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado la mitad de la cantidad de 'diviciones del Ancho + 1 veses terminamos el efecto If Contador = ((VelocidadEfecto + 1) \ 2) + 1 Then DescargaObjetos() End IfEnd Sub'Genera los efectos de Divición Vertical Private Sub DivisionV(ByVal Efecto As Efectos)Dim Velocidad As Single= AltoImagen / VelocidadEfecto 'Si es la primera vez que se llega aquí, establecemos algunas variables If EsPrimera ThenIf Efecto = Efectos.DivisiónV_Entrante Then Aumento = 0 ElseIf Efecto = Efectos.DivisiónV_Saliente Then Aumento = AltoImagen / 2 End IfEsPrimera = FalseEnd IfDim RecDivision As New RectangleF(0, Aumento, AnchoImagen, Velocidad) Dim RecDivision2 As New RectangleF(0, AltoImagen - Aumento, AnchoImagen, Velocidad) 'Dibujamos los rectangulos de división Gr.FillRectangle(Brocha, RecDivision) Gr.FillRectangle(Brocha, RecDivision2)pic.Refresh() 'Aumentamos el tamaño de los rectangulos Aumento += Velocidad 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado la mitad de la cantidad de 'diviciones del Alto + 1 veses terminamos el efecto If Contador = ((VelocidadEfecto + 1) \ 2) + 1 Then DescargaObjetos() End IfEnd Sub
Efecto de División Horizontal.Efectos de Barrido.Este efecto divide la imagen en rectángulos de igual tamaño para luego ir moviendo la mitadde estos rectángulos desde la derecha hacia el centro, y la otra mitad desde la izquierda hacia el centrode manera que al encontrarce se intercalen para formar la imagen completa. (También hay una variantedonde los rectángulos se dibujan de abjo y de arriba hacia el centro)La metodología es similar a la de los efectos de Empuje pero ahoranecesitamos no uno sino dos objetos Graphics para dibujar en la misma imagen ya que vamosa hacer más de una transformación al mismo tiempo. A uno le vamos a aplicar las transformacionesde los ejes de coordenadas hacia un lado y al otro hacia el lado opuesto. Luego mediante el Timermovemos progresivamente el centro de coordenadas a su posición original (La esquina superior izquierda)para los dos objetos Graphics y cada vez dibujamos con un bucle una mitad de los rectángulos con unode los objetos Graphics y el la otra mitad con el otro.'Genera los efectos de Barrido Private Sub Barrido(ByVal Efecto As Efectos)'Creamos el segundo objeto Graphics para dibujar en bmCopia Static Gr2 As GraphicsDim Persiana As SingleStatic xEsquinaPersiana, yEsquinaPersiana As SingleStatic AnchoPersiana, AltoPersiana As Single'Si es la primera vez que se llega aquí, establecemos algunas variables If EsPrimera Then Gr2 = Graphics.FromImage(bmCopia) If Efecto = Efectos.BarridoH Then xAumentaPos = AnchoImagen : yAumentaPos = 0 xEsquinaPersiana = 0 : yEsquinaPersiana = AltoImagen / 20 AnchoPersiana = AnchoImagen : AltoPersiana = AltoImagen / 20 ElseIf Efecto = Efectos.BarridoV Then xAumentaPos = 0 : yAumentaPos = AltoImagen xEsquinaPersiana = AnchoImagen / 20 : yEsquinaPersiana = 0 AnchoPersiana = AnchoImagen / 20 : AltoPersiana = AltoImagen End If 'Movemos el centro del eje de coordenadas la primera vez 'que se ejecuta el evento, para que la imagen se dibuje pero no se vea Gr.TranslateTransform(xAumentaPos, yAumentaPos) Gr2.TranslateTransform(-xAumentaPos, -yAumentaPos)EsPrimera = False End If'Limpiamos el contenido de bmCopia Gr.Clear(pic.BackColor)For Persiana = 0 To 20 'Nº de Persianas (20) 'Las persianas pares las dibujamos con Gr, 'y las impares con Gr2 Dim SupIzquierda As New PointF(Persiana * xEsquinaPersiana, Persiana * yEsquinaPersiana) Dim TamañoPersiana As New SizeF(AnchoPersiana, AltoPersiana)If Persiana Mod 2 = 0 Then Dim RecBarridoPar As New RectangleF(SupIzquierda, TamañoPersiana) Gr.FillRectangle(Brocha, RecBarridoPar) Else Dim RecBarridoImpar As New RectangleF(SupIzquierda, TamañoPersiana) Gr2.FillRectangle(Brocha, RecBarridoImpar) End If Next 'Transladamos los ejes progresivamente Gr.TranslateTransform(-xAumentaPos / VelocidadEfecto, -yAumentaPos / VelocidadEfecto) Gr2.TranslateTransform(xAumentaPos / VelocidadEfecto, yAumentaPos / VelocidadEfecto) 'Contamos las veces que movimos la imágen Contador += 1 'Refrescamos el PictureBox pic.Refresh() 'Cuando el evento se halla ejecutado VelocidadEfecto + 1 'veses terminamos el efecto If Contador = VelocidadEfecto + 1 Then Gr2.Dispose() xEsquinaPersiana = 0 : yEsquinaPersiana = 0 AnchoPersiana = 0 : AltoPersiana = 0 DescargaObjetos() End IfEnd Sub
Efecto de Barrido Horizontal.Efecto de Rueda.Este efecto dibuja la imagen en forma de rueda en sentido de las agujas del reloj.Para lograrlo vamos a usar el método FillPie del Objeto Graphics el cual llena una tortacon el objeto TextureBrush especificado y con un ángulo de giro especificado.O sea que iremos agrandando progresivamente el ángulo de giro hastadar una vuelta completa (360º).Como una imagen obviamente no es una torta sino un rectángulo lo que vamos a haceres llenar con nuestro objeto TextureBrush una torta que sea más grande que el rectángulode la imagen (El diametro de la torta será la diagonal de la imagen) y que este centradaen la imagen, permitiendo dibujar toda la imagen.'Genera el efecto de Rueda Private Sub Rueda() 'La diagonal de la imágen va a ser el diametro. 'La calculamos por Pitagoras. Dim Diagonal As Single= CSng(Math.Pow((AltoImagen ^ 2) + (AnchoImagen ^ 2), 1 / 2)) 'Llenamos una torta con centro en el centro del PictureBox, 'con la textura de la imágen original, 'agregandole trozos de AnguloGiro Gr.FillPie(Brocha, CSng(-(Diagonal - AnchoImagen) / 2), CSng(-(Diagonal - AltoImagen) / 2), Diagonal, Diagonal, -90, AnguloGiro) 'Mostramos el trozo actual pic.Refresh() AnguloGiro += CSng(360 / VelocidadEfecto) 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado VelocidadEfecto + 1 'veses terminamos el efecto If Contador = VelocidadEfecto + 1 Then DescargaObjetos() End IfEnd SubEfecto de Rueda.Efecto con Círculos.Este efecto dibuja la imagen llenando círculos concéntricos con nuestro TextureBrush.Para lograrlo vamos a usar el método FillEllipse del Objeto Graphics el cual llena una elipsecon el objeto TextureBrush especificado. (Recordar que una circunferencia es un caso particular de elipse)Vamos a centrar los círculos en el centro de nuestra imagen y mediante el objeto Timer vamos a irllenando de a un circulo y agrandando el radio para que se dibujen los sucesivos círculos hasta haberpintado toda la imagen. Ya que tenemos que dibujar círculos dentro de un rectángulo para sabercuando dejar de pintar vamos a hacer que el diámetro máximo sea el tamaño de la diagonal del rectángulo.Además, para entender mejor el código recordar que una elipse se dibuja pasándole un rectánguloal método FillElipse en el cual se dibujará la elipse circunscripta en él.'Genera el efecto con Circulos Private Sub Circulos() 'El diametro de los circulos Static Diametro As Single'La diagonal de la imágen va a ser el diametro máximo. 'La calculamos por Pitagoras. Dim Diagonal As Single= CSng(Math.Pow((AltoImagen ^ 2) + (AnchoImagen ^ 2), 1 / 2)) 'Definimos las coordenadas del punto superior 'izquierdo del rectángulo a partir del cual 'se dibujará un circulo circunscripto en él, de modo que 'el centro de el circulo coincida con el centro del PictureBox Dim xEsquina As Single = (AnchoImagen / 2) - (Diametro / 2) Dim yEsquina As Single = (AltoImagen / 2) - (Diametro / 2) Dim MiPunto As New PointF(xEsquina, yEsquina) 'Tamaño del rectángulo donde se dibujará el circulo Dim Tamaño As SizeF = New SizeF(Diametro, Diametro) Dim Rectángulo As New RectangleF(MiPunto, Tamaño) Gr.FillEllipse(Brocha, Rectángulo) 'Mostramos el circulo actual pic.Refresh()Diametro += Diagonal / VelocidadEfecto 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado VelocidadEfecto + 1 'veses terminamos el efecto If Contador = VelocidadEfecto + 1 Then Diametro = 0 DescargaObjetos() End IfEnd SubEfecto con Círculos.Efectos de Empuje y División.Estos efectos son una combinación entre los de Empuje y Divición. Vamos a usar dosobjetos Graphics para dibujar en la misma imagen. Cambiamos el centro de los ejes decoordenadas del primer objeto Graphics con el método TranslateTransform, lo suficientemente haciaun lado para que inicialmente la imagen se dibuje pero no se vea, y hacemos lo mismo con el otroobjeto Graphics pero hacia el lado opuesto .Luego vamos deshaciendola transformación progresivamente y volviendo a dibujar cada vez toda la imagen, la mitad con uno delos objetos Graphics y la otra mitad con el otro.El efecto que se crea es de las dos mitades de la imagen que son empujadas hastaencontrarse en el centro.'Genera los efectos de Empuje con división Private Sub EmpujaDivision(ByVal Efecto As Efectos) 'Creamos el segundo objeto Graphics para dibujar en bmCopia Static Gr2 As Graphics Static Ancho, Alto, xEsquina, yEsquina As Single'Si es la primera vez que se llega aquí, 'Establecemos las transformaciónes iniciales 'según la variante de efecto de Empuje y División If EsPrimera Then Gr2 = Graphics.FromImage(bmCopia)If Efecto = Efectos.Empuja_División_Lados Then xAumentaPos = AnchoImagen / (2 * VelocidadEfecto) yAumentaPos = 0 Ancho = AnchoImagen / 2 : Alto = AltoImagen xEsquina = Ancho : yEsquina = 0 Gr.TranslateTransform(-Ancho, 0) Gr2.TranslateTransform(Ancho, 0) ElseIf Efecto = Efectos.Empuja_División_Topes Then xAumentaPos = 0 yAumentaPos = AltoImagen / (2 * VelocidadEfecto) Ancho = AnchoImagen : Alto = AltoImagen / 2 xEsquina = 0 : yEsquina = Alto Gr.TranslateTransform(0, -Alto) Gr2.TranslateTransform(0, Alto) End If EsPrimera = FalseEnd IfDim RecEmpujaLado As New RectangleF(0, 0, Ancho, Alto) Dim RecEmpujaOpuesto As New RectangleF(xEsquina, yEsquina, Ancho, Alto)'Limpiamos el contenido de bmCopia Gr.Clear(pic.BackColor)'Dibujamos los rectangulos y los lenamos con la imagen Gr.FillRectangle(Brocha, RecEmpujaLado) Gr2.FillRectangle(Brocha, RecEmpujaOpuesto) 'Movemos los ejes de coordenadas Gr.TranslateTransform(xAumentaPos, yAumentaPos) Gr2.TranslateTransform(-xAumentaPos, -yAumentaPos) pic.Refresh() 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado VelocidadEfecto + 1 veses terminamos el efecto If Contador = VelocidadEfecto + 1 Then Gr2.Dispose() Ancho = 0 : Alto = 0 xEsquina = 0 : yEsquina = 0 DescargaObjetos() End IfEnd SubEfecto de Empuje y Divición.Efectos de Rueda con Multiples Ejes.Estos efectos son similares a los de "Rueda" pero vamos a dividir la imagen en varios trozosdefinidos en la enumeración "Ejes" y vamos a ir pintando con el objeto TextureBrushprogresivamente cada trozo hasta llenar la imagen completa.Para lograrlo vamos a usar el método FillPie del Objeto Graphics el cual llena una tortacon el objeto TextureBrush especificado y con un ángulo de giro especificado.Como una imagen obviamente no es una torta sino un rectángulo lo que vamos a haceres llenar con nuestro objeto TextureBrush una torta que sea más grande que el rectángulode la imagen (El diametro de la torta será la diagonal de la imagen) y que este centradaen la imagen, permitiendo dibujar toda la imagen.'Genera los efecto con multiples Ejes Private Sub RuedaMultiple(ByVal Ejes As Ejes)Dim Eje, AnguloInicio, Paso As Integer'Establecemos variables según la variante del efecto seleccionados Select Case Ejes Case Ejes.DosEjes AnguloInicio = -90 : Eje = 2 : Paso = 180 Case Ejes.TresEjes AnguloInicio = -90 : Eje = 3 : Paso = 120 Case Ejes.CuatroEjes AnguloInicio = 0 : Eje = 4 : Paso = 90 Case Ejes.OchoEjes AnguloInicio = 0 : Eje = 8 : Paso = 45 End Select'La diagonal de la imágen va a ser el diametro. 'La calculamos por Pitagoras. Dim Diagonal As Single= CSng(Math.Pow((AltoImagen ^ 2) + (AnchoImagen ^ 2), 1 / 2)) Dim i As Integer'Llenamos una torta con centro en el centro del PictureBox, 'con la textura de la imágen original, 'agregandole trozos de AnguloGiro Dim rec As New Rectangle(CInt(-(Diagonal - AnchoImagen) / 2), CInt(-(Diagonal - AltoImagen) / 2), CInt(Diagonal), CInt(Diagonal))For i = 1 To Eje Gr.FillPie(Brocha, rec, AnguloInicio, AnguloGiro) AnguloInicio += Paso Next AnguloGiro += CSng(Paso / VelocidadEfecto) 'Mostramos los trozos actuales pic.Refresh() 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado VelocidadEfecto + 1 'veses terminamos el efecto If Contador = VelocidadEfecto + 1 Then DescargaObjetos() End IfEnd SubEfecto Rueda Multiple (8 ejes).Efecto Simetrico.Este efecto dibuja la imagen en forma de dos ruedas que parten del mismo lugar, una dibuja unamitad de la imagen en sentido de las agujas del reloj y la otra en sentido opuesto hastacompletar toda la imagen.Para lograrlo vamos a usar el método FillPie del Objeto Graphics el cual llena una tortacon el objeto TextureBrush especificado y con un ángulo de giro especificado.O sea que iremos agrandando progresivamente el ángulo de giro hastadar media vuelta (180º) con cada mitad.Como una imagen obviamente no es una torta sino un rectángulo lo que vamos a haceres llenar con nuestro objeto TextureBrush una torta que sea más grande que el rectángulode la imagen (El diametro de la torta será la diagonal de la imagen) y que este centradaen la imagen, permitiendo dibujar toda la imagen.'Genera el efecto de Simetría Private Sub Simetrico() 'La diagonal de la imágen va a ser el diametro. 'La calculamos por Pitagoras. Dim Diagonal As Single = CSng(Math.Pow((AltoImagen ^ 2) + (AnchoImagen ^ 2), 1 / 2)) 'Llenamos una torta con centro en el centro del PictureBox, 'con la textura de la imágen original, 'agregandole trozos de AnguloGiro Dim rec As New Rectangle(CInt(-(Diagonal - AnchoImagen) / 2), CInt(-(Diagonal - AltoImagen) / 2), CInt(Diagonal), CInt(Diagonal))Gr.FillPie(Brocha, rec, -90, AnguloGiro) Gr.FillPie(Brocha, rec, -90, -AnguloGiro)AnguloGiro += CSng(180 / VelocidadEfecto) 'Mostramos los trozos actuales pic.Refresh() 'Contamos las veces que se ejecutó este evento Contador += 1 'Cuando el evento se halla ejecutado VelocidadEfecto + 1 'veses terminamos el efecto If Contador = VelocidadEfecto + 1 Then DescargaObjetos() End IfEnd SubEfecto Simetrico.'Descarga Gr y Brocha, activa controles y detiene el Timer Private Sub DescargaObjetos() Gr.Dispose() Brocha.Dispose() Tiempo.Stop() btnReproducir.Enabled = True lbEfectos.Enabled = True End SubEnd Class
Fichero con el código de ejemplo (anibal_EfectosTrans.zip - 37.1 KB)