none
Control personalizado falla RRS feed

  • Pregunta

  • Muy buenas tardes:

    Estoy tratando de crear un control personalizado, de est forma:

    El código que uso es este:

    ''' <summary>
    ''' Control personalizado para mostrar gráficos vectoriales.
    ''' </summary>
    Public Class Canvas
    
        Inherits System.Windows.Forms.UserControl
    
    #Region "Constructor"
    
        ''' <summary>
        ''' Constructor predeterminado del control de usuario.
        ''' </summary>
        Public Sub New()
    
            ' Esta llamada es exigida por el diseñador.
            InitializeComponent()
    
            ' Agregue cualquier inicialización después de la llamada a InitializeComponent().
    
            'Se asigna ciertas propiedades de inicio para el control.
            '---------
    
            'El control se mostrará acoplado al panel donde se desee insertar.
            Me.Dock = DockStyle.None
            'Dado que es un control para dibujar, se adiciona la propiedad de DoubleBuffer para reducir el parpadeo.
            Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
            Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
            Me.SetStyle(ControlStyles.UserPaint, True)
            Me.Cursor = Cursors.Cross
        End Sub
    
    #End Region
    
    #Region "Variables"
        ''' <summary>
        ''' Verifica si un botón del Mouse se ha presionado dentro de un control.
        ''' </summary>
        Private _mousePress As Boolean = False
        ''' <summary>
        ''' Variable que guarda posición del Mouse en el evento Down de un control. Esto
        ''' ocurre cuando se presiona un botón del Mouse en un control.
        ''' </summary>
        Private _mouseDown_Location As PointF
        ''' <summary>
        ''' Posición actual del mouse cuando se activa el evento MouseMove.
        ''' </summary>
        Private _mousePositionMove As PointF
        Private _TraslationX_Graphics_old As Single = 0F
        Private _TraslationY_Graphics_old As Single = 0F
        ''' <summary>
        ''' Variable para guardar el valor que debe trasladarse el Objeto Graphics en el eje X, durante el Zoom
        ''' para que siempre el foco del zoom sea de acuerdo a la posición del punntero del Mouse.
        ''' </summary>
        Private _TraslationX_Graphics As Single = 0F
        ''' <summary>
        ''' Variable para guardar el valor que debe trasladarse el Objeto Graphics en el eje Y, durante el Zoom
        ''' para que siempre el foco del zoom sea de acuerdo a la posición del punntero del Mouse.
        ''' </summary>
        Private _TraslationY_Graphics As Single = 0F
        ''' <summary>
        ''' Escala de zoom que debe aplicarse en ScaleTransform del Graphics, el cual se aciva con el evento MouseWheel.
        ''' </summary>
        Private _zoom As Single = 1.0F
        ''' <summary>
        ''' Escala del zoom inmediatamente anterior del que ahora tiene la variable zoom. Esta variable siempre se calcula
        ''' en el evento MouseWheel.
        ''' </summary>
        Private _zoom_old As Single = 1.0F
        ''' <summary>
        ''' Incremento del zoom que se realiza en el evento MouseWheel.
        ''' </summary>
        Const _zoom_increment As Single = 0.1F
        ''' <summary>
        ''' Mínimo zoom que se puede aplicar a los dibujos.
        ''' </summary>
        Const _zoom_min As Single = 0.1F
        ''' <summary>
        ''' Máximo zoom que se puede aplicar a los dibujos.
        ''' </summary>
        Const _zoom_max As Single = 5.0F
    
    
    #End Region
    
    #Region "Eventos"
    
        Protected Overrides Sub OnPaint(e As PaintEventArgs)
            MyBase.OnPaint(e)
    
            Dim g As Graphics = e.Graphics
    
            'Envío el objeto Graphics, para que dibuje teniendo en cuenta las transformaciones.
            TransformarGraphics(g)
            DrawLineReferencieMouse(Me._mousePositionMove, g)
    
        End Sub
    
        Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
            MyBase.OnMouseDown(e)
            'Se obtiene la posición actual del Mouse.
            Me._mousePositionMove = e.Location
    
            'Se verifica que ha presionado el botón izquierdo del Mouse.
            If e.Button = MouseButtons.Left Then
                '
                'Se verifica que no se tiene g
                If Not Me._mousePress = True Then
    
                    Me._mousePress = True
                    '
                    'Obtiene las coordenadas del puntero del Mouse cuando se presionó el Mouse.
                    Me._mouseDown_Location = e.Location
                    Me._TraslationX_Graphics_old = Me._TraslationX_Graphics
                    Me._TraslationY_Graphics_old = Me._TraslationY_Graphics
                End If
    
    
                Me.Invalidate(False)
    
            End If
    
        End Sub
    
        Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
            MyBase.OnMouseMove(e)
    
            'Se obtiene la posición actual del Mouse.
            Me._mousePositionMove = e.Location
    
            'Se verifica que ha presionado el botón izquierdo del Mouse.
            If e.Button = MouseButtons.Left Then
                '
                'Se cambia el icono del cursor.
                Dim ms As MemoryStream = New MemoryStream(My.Resources.hold_1)
                Me.Cursor = New Cursor(ms)
                '
                'Posición actual del puntero del mouse.
                Dim mousePosNow As PointF = e.Location
                'Variable para saber cuanto debe desplazarse el objeto gráfico de acuerdo a la 
                'posición guardada en el evento MouseDown y la actual en este evento.
                Dim deltaX, deltaY As Single
                'Se halla los valores de desplazamiento.
                deltaX = mousePosNow.X - Me._mouseDown_Location.X
                deltaY = mousePosNow.Y - Me._mouseDown_Location.Y
                '
                'Se obtiene DE NUEVO el desplazamiento que debe realizarse en el Objeto Graphics, teniendo en cuenta
                'el valor pasado de dichos traslados obtenidos en el el evento MouseDown+ el nuevo delta de desplazamiento
                'teniendo en cuenta de dividir dicho valor con el valor actual del zoom.
                Me._TraslationX_Graphics = (Me._TraslationX_Graphics_old + (deltaX / Me._zoom))
                Me._TraslationY_Graphics = (Me._TraslationY_Graphics_old + (deltaY / Me._zoom))
                '
                '
    
    
    
                'Obligo a redibujar el control.
                Me.Invalidate(False)
    
            End If
    
        End Sub
    
    
        Protected Overrides Sub OnMouseUp(e As MouseEventArgs)
            MyBase.OnMouseUp(e)
            '
            'Este evento ocurre cuando el puntero del Mouse se encuentra sobre el control
            'y soltó un botón del Mouse.
            '
            'Se indica que ya no se encuentra presionado el botón del Mouse.
            Me._mousePress = False
            'Se cambia el icono del cursor, cuando se suelta el botón del mouse que actualmente se presionaba.
            Me.Cursor = Cursors.Cross
            Me.Invalidate(False)
        End Sub
    
        Protected Overrides Sub OnMouseWheel(e As MouseEventArgs)
    
            MyBase.OnMouseWheel(e)
            '
            'Actualizo el valor del zoom actual, antes de que se calcule el nuevo en este evento.
            Me._zoom_old = Me._zoom
    
            'Verifico que el paso de la muesca del mouse se hace hacia arriba.(>zoom).
            If e.Delta > 0 Then
                '
                'Se incrementa el zoom, de acuerdo a la variable constante de la clase. Se
                'tiene en cuenta que no se sobrepase del mayor valor del zoom.
                Me._zoom = Math.Min(Me._zoom + _zoom_increment, _zoom_max)
            Else
                '
                'Para el caso de disminución del Mouse, establezco un mínimo valor para no tener 
                'problemas de OverFlow. El mínimo valor del zoom
                Me._zoom = Math.Max(Me._zoom - _zoom_increment, _zoom_min)
            End If
            '
            'Se obtiene la posición actual del Mouse.
            Dim mousePosNow As PointF = e.Location
            'Variables para saber el valor de los deltas entre la posición actual del mouse
            'y la ubicación de la parte superior izquierda del PictureBox.
            Dim deltaX, deltaY As Single
            deltaX = mousePosNow.X - Me.Location.X
            deltaY = mousePosNow.Y - Me.Location.Y
            'Variable que guardan el valor teniendo en cuenta el zoom inmediatamente
            'anterior de los desplazamientos que sufrió el Graphics.
            Dim oldGraphicsX As Single
            Dim oldGraphicsY As Single
            oldGraphicsX = ((deltaX / Me._zoom_old))
            oldGraphicsY = ((deltaY / Me._zoom_old))
            'Variable para guardar los nuevos desplazamientos que debe sufrir el Graphics,
            'para que el centro del foco del Zoom sea la ubicación actual del Mouse.
            Dim newGraphicsX As Single
            Dim newGraphicsY As Single
            newGraphicsX = ((deltaX / Me._zoom))
            newGraphicsY = ((deltaY / Me._zoom))
            '
            'Los nuevos valores de Traslado del objeto Graphics se obtiene.
            Me._TraslationX_Graphics = newGraphicsX - oldGraphicsX + Me._TraslationX_Graphics
            Me._TraslationY_Graphics = newGraphicsY - oldGraphicsY + Me._TraslationY_Graphics
    
            'Se obtiene la posición actual del Mouse.
            Me._mousePositionMove = mousePosNow
    
    
    
            'Se obliga a redibujar el control.
            Me.Invalidate(False)
    
    
        End Sub
    
    
    
    
    
    #End Region
    
    #Region "Métodos"
    
        ''' <summary>
        ''' Realiza las transformaciones del Canvas, en este un escalamiento(zoom) y un traslado
        ''' de coordendas para que el zoom sea respecto a una posición en específica.
        ''' </summary>
        ''' <param name="canvas"></param>
        Private Sub TransformarGraphics(canvas As Graphics)
    
            'Borramos la superficie de dibujo y aplicacmos un color de fondo.
            canvas.Clear(Color.Black)
            'Suavizado de los pixeles para disminuir el parpadeo al redibujar.
            'canvas.PixelOffsetMode = Drawing2D.PixelOffsetMode.Half
            'canvas.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
            canvas.SmoothingMode = Drawing2D.SmoothingMode.HighSpeed
            '
            'Se aplica el escalado actual del onjeto gráfico. Este valor se ajusta en el evento MouseWheel del Control de dibujado.
            canvas.ScaleTransform(Me._zoom, Me._zoom)
            '
            'Se traslada el origen de las coordenadas, para que el centro del zoom coincida 
            'con la posición del mouse actual.
            canvas.TranslateTransform(Me._TraslationX_Graphics, _TraslationY_Graphics)
            '
            'Pindel para dibujado de los objetos.
            Dim pen As New Pen(Color.Red)
            'Establezco un ancho de la línea siempre de 1.5 pix, sin importar el zoom.
            pen.Width = 1.0F / Me._zoom
            'Patrón del tipo de línea a usar del Pen, con 20 pix de línea espaciadas cada 10 pix.
            Dim tipo_linea() As Single = {20, 10}
            'Asigno el tipo de línea personalizada.
            pen.DashStyle = Drawing2D.DashStyle.Custom
            'Asigno el tipo de línea.
            pen.DashPattern = tipo_linea
            pen.LineJoin = Drawing2D.LineJoin.Bevel
            'Dibuja un rectángulo.
            canvas.DrawRectangle(pen, 100, 150, 500, 400)
    
            Me.Invalidate(False)
    
        End Sub
    
        Private Sub DrawLineReferencieMouse(positionMouse As PointF, graphics As Graphics)
    
            graphics.PageUnit = GraphicsUnit.Pixel
    
            Dim pencil As New Pen(Color.White)
            Dim tipolinea As Single() = New Single() {10, 15}
            pencil.Width = 1 / Me._zoom
            pencil.ScaleTransform(Me._zoom, Me._zoom)
    
            pencil.DashPattern = tipolinea
            Dim width As Single = graphics.ClipBounds.Width
            Dim heigth As Single = graphics.ClipBounds.Height
    
    
            'Se dibuja la linea vertical
            graphics.DrawLine(pencil, (positionMouse.X) / Me._zoom - Me._TraslationX_Graphics, -Me._TraslationY_Graphics, (positionMouse.X) / Me._zoom - Me._TraslationX_Graphics, heigth - Me._TraslationY_Graphics)
            'Se dibuja la linea HORIZONTAL
            graphics.DrawLine(pencil, -Me._TraslationX_Graphics, positionMouse.Y / Me._zoom - Me._TraslationY_Graphics, width - Me._TraslationX_Graphics, positionMouse.Y / Me._zoom - Me._TraslationY_Graphics)
    
            Me.Invalidate(False)
    
        End Sub
    
    #End Region
    
    
    End Class

    El problema es que cuando intetno correr el control personalizado en el proyecto de creación, no me muestra las propiedades a mano derecha y empieza a parpadear. Sé que esto pasa por el evento Paint, pero pues no se conceptualmente como solucionarlo.

    De igual forma pasa, cuando intento usar el control en un proyecto de prueba, al agregarlo en el Form, se observa que parpadea, y cuando intento correr el Test, ni si quiera arranca.

    Podrían ayudarme a solucionar esto. Mi idea es crea posteriormente un control para dibujar con GDI+ con sobre él, y quiero es mostrar unas reglas en dicho control en unidades varias, hacer el zoom y el pan, éstos dos últimos que ya funcionan en el ejemplo que acabé de pasar.

    ¿Podrían guiarme para crear dicho control personalizado, de una forma correcta?

    Muchas gracias.


    Harold Alonso Quintero Pineda Ingeniero Civil Universidad Francisco de Paula Santander Ocaña Correo: haroldpineda1401@outlook.com Cel: 3158700970


    jueves, 6 de julio de 2017 20:14

Respuestas

  • "Harold Quintero Pineda" escribió:

    > El problema es que cuando intetno correr el control personalizado en el proyecto
    > de creación, no me muestra las propiedades a mano derecha y empieza a parpadear.

    Hola, Harold:

    Lo de "parpadear", no lo puedo reproducir, pero sí lo que comentas sobre que "no me muestra las propiedades a mano derecha", es decir, en la ventana de Propiedades de Visual Studio.

    Fíjate en la instrucción Inherits:

        Public Class Canvas
    
            Inherits System.Windows.Forms.UserControl

    Lo más seguro es que tengas DUPLICADA la instrucción Inherits, tanto en el archivo Canvas.vb como en su archivo de diseño (Canvas.Designer.vb).

    Si el control de usuario llamado Canvas lo has creado mediante la opción del menú Proyecto --> Agregar control de usuario..., Visual Studio te genera tres archivos: Canvas.vb, Canvas.Designer.vb y Canvas.resx, donde los dos últimos suelen estar ocultos, y no los podrás ver en la ventana Explorador de soluciones hasta que pulses sobre su icono Mostrar todos los archivos.

    Pues bien, la instrucción Inherits ya se encuentra declarada en el archivo Canvas.Designer.vb dentro de la clase parcial Canvas que automáticamente habrá creado Visual Studio:

        <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
        Partial Class Canvas
    
            Inherits System.Windows.Forms.UserControl

    Por tanto, no puedes DUPLICAR la declaración Inherits, por lo que tendrás que eliminar una de las dos, que yo te aconsejaría que eliminaras la que has añadido manualmente a la clase Canvas.

    > De igual forma pasa, cuando intento usar el control en un proyecto de prueba,
    > al agregarlo en el Form, se observa que parpadea, y cuando intento correr el
    > Test, ni si quiera arranca.

    Insisto en que yo no puedo reproducir el parpadeo. Y efectivamente, cuando intento correr el proyecto donde he insertado el control Canvas éste no arranca, siempre y cuando se encuentre en primer plano la vista de diseño del formulario que contiene el control Canvas. Si en el entorno de diseño de Visual Studio se encuentra en primer plano otro archivo de código fuente u otro formulario diferente, entonces no tendrás problemas para iniciar la depuración del proyecto pulsando la tecla F5.

    En estos momentos no sabría indicarte exactamente el motivo para que ello suceda, pero para salir del paso, procura que cuando pulses la tecla F5 no se encuentre en primer plano el formulario que contiene el control Canvas.

    Un saludo


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    viernes, 7 de julio de 2017 17:29
    Moderador

Todas las respuestas

  • "Harold Quintero Pineda" escribió:

    > El problema es que cuando intetno correr el control personalizado en el proyecto
    > de creación, no me muestra las propiedades a mano derecha y empieza a parpadear.

    Hola, Harold:

    Lo de "parpadear", no lo puedo reproducir, pero sí lo que comentas sobre que "no me muestra las propiedades a mano derecha", es decir, en la ventana de Propiedades de Visual Studio.

    Fíjate en la instrucción Inherits:

        Public Class Canvas
    
            Inherits System.Windows.Forms.UserControl

    Lo más seguro es que tengas DUPLICADA la instrucción Inherits, tanto en el archivo Canvas.vb como en su archivo de diseño (Canvas.Designer.vb).

    Si el control de usuario llamado Canvas lo has creado mediante la opción del menú Proyecto --> Agregar control de usuario..., Visual Studio te genera tres archivos: Canvas.vb, Canvas.Designer.vb y Canvas.resx, donde los dos últimos suelen estar ocultos, y no los podrás ver en la ventana Explorador de soluciones hasta que pulses sobre su icono Mostrar todos los archivos.

    Pues bien, la instrucción Inherits ya se encuentra declarada en el archivo Canvas.Designer.vb dentro de la clase parcial Canvas que automáticamente habrá creado Visual Studio:

        <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
        Partial Class Canvas
    
            Inherits System.Windows.Forms.UserControl

    Por tanto, no puedes DUPLICAR la declaración Inherits, por lo que tendrás que eliminar una de las dos, que yo te aconsejaría que eliminaras la que has añadido manualmente a la clase Canvas.

    > De igual forma pasa, cuando intento usar el control en un proyecto de prueba,
    > al agregarlo en el Form, se observa que parpadea, y cuando intento correr el
    > Test, ni si quiera arranca.

    Insisto en que yo no puedo reproducir el parpadeo. Y efectivamente, cuando intento correr el proyecto donde he insertado el control Canvas éste no arranca, siempre y cuando se encuentre en primer plano la vista de diseño del formulario que contiene el control Canvas. Si en el entorno de diseño de Visual Studio se encuentra en primer plano otro archivo de código fuente u otro formulario diferente, entonces no tendrás problemas para iniciar la depuración del proyecto pulsando la tecla F5.

    En estos momentos no sabría indicarte exactamente el motivo para que ello suceda, pero para salir del paso, procura que cuando pulses la tecla F5 no se encuentre en primer plano el formulario que contiene el control Canvas.

    Un saludo


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    viernes, 7 de julio de 2017 17:29
    Moderador
  • Muy buenaas tardes señor Montejo;

    Muchas gracias, como siempre por responderme. Si, hice eso de la Herencia y me ayudó mucho, además le quité la línea de Código de Me.Invalidate del método DrawLineReferencieMouse, pues estaba haciendo un Paint cíclico y por eso cuando agregaba el control en un proyecto de prueba observaba el parpadeo en tiempo de diseño en Visual Studio.

    Muchas gracias por todo. Dios me lo bendiga.



    Harold Alonso Quintero Pineda Ingeniero Civil Universidad Francisco de Paula Santander Ocaña Correo: haroldpineda1401@outlook.com Cel: 3158700970

    domingo, 9 de julio de 2017 17:49