Spanish Cargar imágenes y rotarlas

emvpic

Member
Licensed User
Hola, quiero hacer una simulación de un voltimetro y amperimetro, conseguí que funcione bien cargando y rotando el cuadro del voltímetro que consta de una imagen circular y una imagen con una varilla que va rotando sobre el círculo (como si se tratara de un contador de velocidad de un coche).
El problema viene al cargar otro para de imágenes, una hace de fondo circular(la que marca los amperios), la otra imagen es la varilla que simula la rotación sobre el circulo para señalar los amperios.
Llevo ya varios días intentado darle solución haciendo cambios y buscando por internet pero hasta el momento no lo conseguí.
No se si existe otra forma de hacer lo que quiero.
Al cargar la segunda imagen compuesta del circulo y varilla del amperitro, cuando le doy al boton para que gire no rota la varilla del voltimetro (solo esta escrito el codigo para la varilla del voltimetro, si escribo el codigo para la varilla del amperimetro me da error y no se ejecuta el programa)
B4X:
Sub Process_Globals
Dim temporizador1 As Timer
End Sub

Sub Globals
        Dim fondocanvas As Canvas
    Dim reloj1, aguja1 As Bitmap
    Dim srectfondocanvas, drectcanvas, srectaguja1, drectaguja1 As Rect
 
    Dim centrox As Int   : centrox=100
    Dim centroy As Int   : centroy=600
    Dim angulopaso As Float : angulopaso=6
    Dim angulo As Float  :angulo=-angulopaso
    Dim modo As Boolean  :modo=True
    '''''''''''''''''''''''''''''''''''''''''''
 
    Dim fondocanvasb As Canvas
    Dim reloj1b, aguja1b As Bitmap
    Dim srectfondocanvasb, drectcanvasb, srectaguja1b, drectaguja1b As Rect
 
    Dim centroxb As Int   : centroxb=400
    Dim centroyb As Int   : centroyb=600
    Dim angulopasob As Float : angulopasob=6
    Dim angulob As Float  :angulob=-angulopasob
    Dim modob As Boolean  :modob=True

End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("Layout4")
 
    Dim x, y As Int
    reloj1.Initialize(File.DirAssets,"voltimetro.png")
    aguja1.Initialize(File.DirAssets,"varillavoltimetro.png")
    srectaguja1.Initialize(0,0,aguja1.Width,aguja1.Height)
    x=centrox-aguja1.Width/2
    y=centroy-aguja1.Height/2
    drectaguja1.Initialize(x,y,x+aguja1.Width,y+aguja1.Height)
    srectfondocanvas.Initialize(0,0,reloj1.Width,reloj1.Height)
    x=centrox-reloj1.Width/2
    y=centroy-reloj1.Height/2
    drectcanvas.Initialize(x,y,x+reloj1.Width,y+reloj1.Height)
    fondocanvas.Initialize(Activity)
    temporizador1.Initialize("temporizador1",50)
 
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
 
    ''''posicion inicial de la aguja del voltimetro
    angulo=195
    fondocanvas.DrawBitmap(reloj1,srectfondocanvas,drectcanvas)
    fondocanvas.DrawBitmapRotated(aguja1,srectaguja1,drectaguja1,angulo)
    Activity.Invalidate
    temporizador1_tick
 
 
    'Segundo reloj
    Dim xb, yb As Int
    reloj1b.Initialize(File.DirAssets,"amperimetro.png")
    aguja1b.Initialize(File.DirAssets,"varillavoltimetro.png")
    srectaguja1b.Initialize(0,0,aguja1b.Width,aguja1b.Height)
    xb=centroxb-aguja1b.Width/2
    yb=centroyb-aguja1b.Height/2
    drectaguja1b.Initialize(xb,yb,xb+aguja1b.Width,yb+aguja1b.Height)
    srectfondocanvasb.Initialize(0,0,reloj1b.Width,reloj1b.Height)
    xb=centroxb-reloj1b.Width/2
    yb=centroyb-reloj1b.Height/2
    drectcanvasb.Initialize(xb,yb,xb+reloj1b.Width,yb+reloj1b.Height)
    fondocanvasb.Initialize(Activity)
 
 
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
 
    ''''posicion inicial de la aguja del amperimetro
    angulob=195
    fondocanvasb.DrawBitmap(reloj1b,srectfondocanvasb,drectcanvasb)
    fondocanvasb.DrawBitmapRotated(aguja1b,srectaguja1b,drectaguja1b,angulob)
    Activity.Invalidate
    '''''''''''''''''''''''''''''''''''''
 
End Sub


Sub temporizador1_tick
 
        If angulo=483 Then
     
    Else
    angulo=(angulo+angulopaso) 'Mod 360
    If modo=True Then
        fondocanvas.DrawBitmap(reloj1,srectfondocanvas,drectcanvas)
        fondocanvas.DrawBitmapRotated(aguja1,srectaguja1,drectaguja1,angulo)
     
     
    Else
        fondocanvas.DrawBitmapRotated(reloj1,srectfondocanvas,drectcanvas,-angulo)
        fondocanvas.DrawBitmap(aguja1,srectaguja1,drectaguja1)
     
     
    End If
 
    End If
    Activity.Invalidate
End Sub

Sub btnempezar_Click
 
    If temporizador1.Enabled=True Then
        temporizador1.Enabled=False
        btnempezar.Text="gira"
         
    Else
        temporizador1.Enabled=True
        btnempezar.TExt="para"
             
    End If
End Sub
 
Last edited:

JordiCP

Well-Known Member
Licensed User
Longtime User
Los dos canvas que tienes están sobre el mismo activity.

Prueba de hacerlo todo con el mismo canvas. Es decir, no inicialices el segundo (fondocanvasb) y todas las referencias a "fondocanvasb" las pasas a "fondocanvas"
 

emvpic

Member
Licensed User
Ahora funciona, muchas gracias JordiCP.
He probado a mover la varilla del amperímetro pero me da error, probare a meter el código dentro de otro timer que creare.
 

JordiCP

Well-Known Member
Licensed User
Longtime User
Me alegro:)

No creo que dependa del timer. Lo mas seguro es que en la rutina del timer donde replicas el dibujo para el amperimetro sigas teniendo alguna referencia a "fondocanvasb" o alguna cosa no inicializada

Debería ser (añadido debajo del bloque "if" equivalente del voltimetro), y suponiendo que el "angulo" sea el mismo...
B4X:
If modo=True Then
   fondocanvas.DrawBitmap(reloj1b,srectfondocanvasb,drectcanvasb)
   fondocanvas.DrawBitmapRotated(aguja1b,srectaguja1b,drectaguja1b,angulo)
Else
  fondocanvas.DrawBitmapRotated(reloj1b,srectfondocanvasb,drectcanvasb,-angulo)
  fondocanvas.DrawBitmap(aguja1b,srectaguja1b,drectaguja1b)
End If
 

emvpic

Member
Licensed User
Es correcto todo lo que has dicho, ahora ya me funciona bien. :)
Muchas gracias.
Espero que le sirva a muchos este ejemplo de como hacer girar una manecilla en un circulo para indicar, la hora, velocidad, rpm, voltios, amperios...
 

emvpic

Member
Licensed User
Cuando muestro las imagenes, estas me aparecen en el fondo, de forma que se quedan por debajo de los botones, labels, etc.
¿Que puedo hacer para que estas imágenes aparezcan arriba de los botones, labels, etc?
 

JordiCP

Well-Known Member
Licensed User
Longtime User
Hay diferentes maneras de hacerlo.

Puedes hacer "desaparecer" lo que no te gusta con la propiedad ".Visible = False" y modificarlo cuando quieras que vuelva a ser visible

También, en el momento de crearlos (sea con el designer o por código), lo último que vayas añadiendo siempre se irá poniendo encima de lo existente

De todas maneras, si son como diferentes "pantallas" o partes de "layouts" que quieres mostrar a veces si y a veces no, yo los agruparía en diferentes paneles y aplicaría la propiedad Visible=True/False a los que en cada momento tenga sentido en vez de hacerlo por elementos individuales.
 

emvpic

Member
Licensed User
No se si entendí lo que me has explicado, voy a explicarlo de otra forma.
Digamos que tengo varios botones y labels, creados en el designer, pues quiero cargar una imagen con el codigo que tengo ahi arriba y que esta imagen se desplace por la pantalla por encima de los botones y labels que tengo. Sin tener que poner la propiedad .Visible en false, porque quiero que se vean los botones y labels pero que estos se queden por debajo de la imagen que quiero que se deslice por encima de estos.
No se si me explique bien, espero que me puedas ayudar, si no, de todas formas muchas gracias, ya me has ayudado mucho.
 

JordiCP

Well-Known Member
Licensed User
Longtime User
Si la imagen que tienes es por ejemplo una ImageView, puedes hacer

B4X:
  Dim IV as ImageView
  '....
  IV.BringToFront
  '...

Y si no añades nada mas, quedará encima de todo
 

emvpic

Member
Licensed User
La imagen la muestro en pantalla mediante el objeto canvas y su propiedad DrawBitmap.
No encuentro que tenga una propiedad tipo BringToFront.
¿Se podría usar el objeto imageview como un canvas?
Voy a ir probando cosas.
El objeto ImageView me parece que sería la solución.
 

JordiCP

Well-Known Member
Licensed User
Longtime User
Si, el canvas es la herramienta de dibujo con la que vas dibujando. El ImageView es el "contenedor" de este dibujo
Por eso normalmente se inicializa un canvas (herramienta) sobre un contenedor que es un View. Puede ser un ImageView, o en el caso de tu ejemple del amperímetro y voltímetro, lo has inicializado sobre una "Activity" (una Activity a su vez tiene una componente "View")

El unico problema de inicializar un canvas sobre una activity, es que la misma, por definicion, siempre queda al fondo (ya que todos lo elementos que añades a una activity siempre quedan encima del fondo de la misma).

O sea, en tu caso, deberías sustituir la inicializacion de tu canvas sobre la activity, por la inicializacion del canvas sobre una imageview que ocupe toda la pantalla. Y como tu dices, con esta imageview sí que puedes hacer el "BringToFront"

O sea, añadir la definición y tachar la linea indicada añadiendo las de abajo (no probado)
B4X:
Sub Globals
   Dim IV as ImageView
End Sub

Sub Activity_Create
   '....
   'fondocanvas.Initialize(Activity) '<--- BORRAR Y AÑADIR LO DE ABAJO
   IV.Initialize("")   'Deja las comillas vacias, si no al estar encima el imageview se llevaria los eventos del click de los labels que hay debajo
   Activity.AddView(IV,0,0,Activity.Width,Activity.Height) 'Añadimos el imageview
   fondocanvas.Initialize(IV)
   fondoCanvas.DrawColor(Colors.Transparent) 
   IV.BringToFront
   '...

Ens Sub
 
Last edited:

emvpic

Member
Licensed User
El código que has puesto es perfecto para mis necesidades.
Me has dejado con la boca abierta. :)
Un millón de gracias.
 
Top