Saltar al contenido

Simulaciones genéticas VBA: usar UserForm para pasar variables a una macro y ejecutarla


Recommended Posts

Hola a todos,

sigo con mis macros para simulaciones genéticas. La última que he escrito permite simular el cruce de dos poblaciones. Para ejecutarse necesita que el usuario proporcione información (elegir de entre las poblaciones creadas cuáles son las dos poblaciones a cruzar, cuántos descendientes de cada genotipo se quieren obtener y cómo se va a llamar la nueva población). A parte, se deben de hacer dos comprobaciones previas a la ejecución de la macro (que las dos poblaciones a cruzar tengan el mismo número de genotipos y que no se elija por error dos veces la misma población). Creo que lo más adecuado es utilizar un UserForm para recabar esta información del usuario. El problema es que no se usarlos bien y no se como pasar a la macro las variables que recogen esta información del usuario desde el UserForm. Adjunto un archivo comprimido. En el archivo hay varias hojas. Las dos primeras (Poblaciones y Caracteres) son las que utilizo para generar poblaciones y asignar características a los genotipos respectivamente. La idea es que la macro acabe ejecutándose al pulsar un boton (Cruzamientos específicos) que hay en la hoja Poblaciones. Para comprobar que la macro (Cruzar2Poblaciones, que está en el módulo Reproducción) se ejecuta correctamente he añadido dos poblaciones de ejemplo (HT_P1 y HT_P2) con 5 genotipos cada una. En la macro se han especificado los nombres de estas hojas para trabajar con ellas, pero la idea es que esta información se elija en el UseForm. Para ejecutar la macro, de momento, hay que hacerlo desde la ventana de ejecución de macros no desde el botón. He añadido otra hoja de ejemplo (c3) que es el resultado de aplicar la macro a las dos poblaciones anteriores. En este ejemplo, como lo que queria eran 3 descendientes/genotipo al cruzar las dos poblaciones iniciales, lo que la macro ha hecho es generar 2 pares de gametos/genotipo, generar una nueva hoja de población (c3) y pegar en ella los gametos que ha "cortado" previamente de las dos poblaciones iniciales para la dar la tercera. Finalmente borra en las poblaciones de partida el juego de gametos no usado. La macro funciona bien a falta de añadir la funcionalidad del UserForm. Este (Seleccionar2PoblacionesCruce) lo he empezado a diseñar pero me falta el codigo necesario para que funcione en conjunto con la macro (esto es lo que no se hacer). También me gustaría saber como puedo proteger las dos hojas principales (Poblaciones y Caracteres) para que los usuarios no puedan borrarlas accidentalemente. El fichero es:

https://1drv.ms/u/s!ArSI6ZjR1bGVlNQLYTkasQUbmiR-4A

Espero vuestros cometarios y gracias por vuestra atención. Como la idea principal sigue sindo aprender, se agradecerá mucho cualquier comentario que mejore o simplifique lo que he hecho (seguro que se os ocurren cosas).

PD: En el archivo hay otras macros, si tal como está resulta confuso, decidmelo e intento eliminar cosas.

PD2: @Antoni, espero que te guste como va quedando, he hecho algunas modificaciones a contribuciones anteriores tuyas (creo que no he estropeado nada).

Enlace a comentario
Compartir con otras webs

En 27/10/2018 at 18:03 , Salva Roselló dijo:

El problema es que no se usarlos bien y no se como pasar a la macro las variables que recogen esta información del usuario desde el UserForm

Si el problema es ese, la solución es sencilla. Pongamos que tienes 3 TextBox para esa información (poblaciones, descendientes y nombres) y un botón para llamar a la macro (Ejecutar) y la macro sea "macro" :rolleyes:
 

Private Sub Ejecutar_Click()
Dim poblaciones As String, descendientes As String, nombre As String

macro poblaciones, descendientes, nombre

End Sub
_________________________________

Sub macro(poblaciones As String, descendientes As String, nombre As String)

.....

End Sub

 

Enlace a comentario
Compartir con otras webs

Hola Haplox,

gracias por la ayuda. La verdad es que me falta aprender bastante sobre los UserForms (en la documentación que tengo no los explican con mucha amplitud). Bueno sobre eso y bastantes cosas más. No obstante, por tu respuesta lo que no me queda claro es como le asigno a una variable la selección del textbox (por ejemplo Población1 = ¿?). Entiendo que cuando haga esto bien, lo que tengo que hacer es usar esas variables como argumentos de la macro (tras cambiar la definición actual de la macro en la que no se han indicado argumentos). Por otro lado, según tu esquema esas variables se definen en la zona de código del botón de ejecutar, pero tendrán que estar también en la zona de código de cada uno de los textbox ¿no? (entiendo que es ahí donde se deberia de hacer la asignación de la selección a la variable ¿no?). 

Bueno espero tus comentarios y mientras me voy mirando más cosas sobre UserForms.

Gracias de nuevo.

Saludos.

Enlace a comentario
Compartir con otras webs

Ahora voy a acabar de liarte.

Las variables, en general, pueden ser de tres tipos:

Públicas: Se definen al principio de cualquier módulo como Public y su valor permanece mientras no cierres el archivo o se produzca un error. Puedes usarlas en cualquier lugar. (macro/formulario, ....)

Privadas a nivel de módulo: Se definen al principio del módulo y permanecen mientras se esté ejecutando cualquier macro/función del módulo.

Privadas a nivel de procedimiento (Macro): Se definen dentro del procedimiento y permanecen solamente dentro del procedimiento.

Los controles de formulario son objetos que solo permanecen mientras el formulario esté cargado, por lo que si ejecutas una macro antes de descargar el formulario (Unload), puedes referirte a cualquier control del formulario dentro de la macro, eso si calificando el objeto. Ejemplo, si tienes un formulario con el nombre MiForm y un textbox con el nombre TextBox1, en la macro puedes referirte al valor del control así: MiForm.TextBox1.Value .

Los parámetros en una macro/función son posicionales, o sea, que el nombre de los parámetros es irrelevante.

Vamos a un ejemplo de tu caso, quieres pasar el valor de 2 TextBox como parámetros a una macro, el primero contiene un valor numérico con el que quier hacer operaciones y el segundo, una descripción.

En el formulario haríamos:

  • MiMacro CDbl(Textbox1.Value), Textbox2.Value

Y en un módulo:

  • Sub MiMacro(Valor as Double, Descripción as String)

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

También podrías definir las variables como Public, modificar su contenido en el formulario y prescindir de los parámetros en la macro, así:

En Un módulo:

  • Public Valor as Double
  • Public Descripción as String
  • Sub MiMacro()

En el formulario:

  • Valor = CDbl(TextBox1.Value)
  • Descripción = TextBox2
  • MiMacro

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Y para terminar, comentarte que me estoy ocupando de las validaciones a efectuar dentro del formulario.

Hoy a última hora o mañana te comento algo.

 

Nota: Esto es solo para que veas que yo también puedo enrollarme como una persiana. :lol::lol:;)

 

Enlace a comentario
Compartir con otras webs

Hola @Antoni,

igual es deformación profesional (o defecto de fabricación, no lo sé), pero con mucha frecuencia tengo que lidiar con explicaciones muy detalladas y les he acabado cogiendo cariño ;). Eso no quita que admire sobremanera las explicaciones directas, concisas y precisas (las tuyas y las de Haplox suelen ser un ejemplo recomendable). Pero estarás de acuerdo conmigo en que ese no es un punto de partida, sino de llegada. A mi me queda aún bastante camino por recorrer (al explicarme y al escribir código) :lol:. Estoy en ello, tened paciencia :P.

Respecto a tu "persiana" anterior, me hacía mucha falta y, aunque pueda parecer otra cosa, me has aclarado bastantes cosas (Moltes gràcies!). Dos preguntas: ¿que significa CDbl (esa es la respuesta a una de mis preguntas anteriores)? y  ¿en que parte del formulario defines las variables, o eso es indiferente?

Gracias de nuevo por contribuir a mi formación.

Saludos.

Enlace a comentario
Compartir con otras webs

Hace 13 minutos , Salva Roselló dijo:

CDbl (esa es la respuesta a una de mis preguntas anteriores)

Es una función que convierte a Double un valor numérico. Generalmente para mostrar números con decimales (Long e Integer no permiten decimales)

Debes tener en cuenta que lo que introduces en un TextBox, siempre, siempre se pasan a la macro como STRING

Hace 15 minutos , Salva Roselló dijo:

¿en que parte del formulario defines las variables, o eso es indiferente?

Es indiferente. :). Generalmente dentro de cada rutina o procedimiento como dice antoni), sus propias variables. SI la vas a utilizar en más de una rutina, al principio del todo del código como Public

Ejemplo:
 

Public fila As long, nombre As String
________________________________________________

Private Sub Button1_Click()
Dim i%, j% '<-- SOLO SON VÁLIDAS PARA ESTE PROCEDIMIENTO '

fila=Range("A" & Rows.COunt).End(xlUp).Row '<-- YA PERMANECE ACTIVA MIENTRAS EL FORMULARIO ESTÉ ABIERTO '

 

Enlace a comentario
Compartir con otras webs

Por alusiones, CDbl, forma parte de las funciones de conversión de tipos de dato.

Excel es capaz de "reconocer" los tipos mas usuales, números, fechas,....., pero Visual Basic no, salvo raras excepciones.

Como ha explicado Haplox, los textbox, combobox y demás controles que admiten introducción de datos, son de tipo alfanúmerico, es decir String.

Si en una macro con parámetros defines un parámetro como tipo Double(Número que puede contener decimales), te has de asegurar que el parámetro pasado sea de tipo Double, porqué de lo contrario te dará error, de ahí la necesidad de convertir al tipo adecuado al tipo definido.

Visual Basic proporciona una serie de funciones para realizar la conversión de un tipo de datos a otro, eso si, te has de asegurar que el contenido de la variable a convertir tiene un contenido adecuado al tipo de conversión que se desea.

Te recomiendo la lectura de este link:

 

 Visual Basic-Funciones de conversión de tipos

 

,  

Enlace a comentario
Compartir con otras webs

Hola @Haplox,

muchas gracias por las aclaraciones. 

No os lo vais a creer, pero me acabo de dar cuenta de que estaba bastante despistado con la ubicación del código en los Formularios :ph34r:. Como entraba al código pinchando sobre un elemento del formulario con el botón derecho y diciendole que me mostrara el código, no se por qué asumia que habia un espacio de código separado para cada elemento :blink:. No sé como demonios se me ha ocurrido esa tontería. Con tus comentarios me he dado cuenta la metedura de pata y de que la respuesta a la pregunta de donde ubicar el código en el formulario estaba implicita en la "la clase magistral" de @Antoni. Todo el código de Formulario está junto con una estructura parecida a la de los módulos (:wacko:). Es lo que tiene estar aterrizando aún en el mundo de la programación VBA. 

Lo dicho antes, tened paciencia conmigo (mucha).

Gracias.

Enlace a comentario
Compartir con otras webs

En el adjunto:

Sobre este comentario:

Cita

También me gustaría saber como puedo proteger las dos hojas principales (Poblaciones y Caracteres) para que los usuarios no puedan borrarlas accidentalmente

He protegido sin contraseña las hojas POBLACIONES Y CARACTERES, en esta última se permite la selección porqué si no, todo el tema de colorines se va al traste, pero no se permite modificar. ¿Problema? que hay que desproteger  antes de cualquier acción y volver a proteger después, eso se consigue con los métodos .Unprotect y .Protect del objeto Sheet y es lo que he hecho en todas las macros del módulo AignarCaracteres.

En cuanto al formulario Seleccionar2PoblacionesCruce, lo he adaptado a lo que he entendido que quieres, solo tienes que completar la llamada a las macros en el evento clic del botón CommanButton1.

He añadido unas cuantas hojas mas para probar el funcionamiento del formulario.

Ya contarás que tal va.

Poblaciones y Caracteres

Enlace a comentario
Compartir con otras webs

Hace 1 hora, Salva Roselló dijo:

Gracias @Antoni,

lo miro y te cuento.

Menos mal que teneis paciencia conmigo (mucha):D

 

 

Por la ciencia, lo que sea y recuerda: "Vale mas caer en gracia, que ser gracioso", es un placer colaborar cuando el que consulta sabe lo que quiere, aunque a veces sea algo densa la consulta. :)

Enlace a comentario
Compartir con otras webs

Hola @Antoni,

He adaptado el formulario para que ejecute la macro. Funciona bien. Quiero probar un par de cosas y generalizar el uso de la macro al caso de que no importe el número de genotipos de las poblaciones a cruzar. También tengo algunas dudas que preguntaros. Pero lamentablemente tengo a mi padre ingresado con problemas cardiacos. Me llevará unos dias (no se cuantos) poder hacer esto. 

Seguire informando.

Gracias.

Enlace a comentario
Compartir con otras webs

Hace 52 minutos , Salva Roselló dijo:

Hola @Antoni,

He adaptado el formulario para que ejecute la macro. Funciona bien. Quiero probar un par de cosas y generalizar el uso de la macro al caso de que no importe el número de genotipos de las poblaciones a cruzar. También tengo algunas dudas que preguntaros. Pero lamentablemente tengo a mi padre ingresado con problemas cardiacos. Me llevará unos dias (no se cuantos) poder hacer esto. 

Seguire informando.

Gracias.

Te deseo que tu padre tenga una pronta recuperación. Un abrazo. Antoni.

Enlace a comentario
Compartir con otras webs

Hola a todos,

Ya estoy de vuelta a la normalidad.

Respecto a la macro de cruzar poblaciones. Como os comenté, adapté el formulario que completó @Antoni, definiendo las variables necesarias como Public, modificandolas desde el formulario y ejecutando la macro desde allí. Posteriormente amplie la macro para que pueda cruzar dos poblaciones independientemente del número de genotipos que tengan. También modifiqué ligeranmente las comprobaciones del formulario que preparó @Antoni para que no comprobaran número de genotipos de la población. La macro se ejecuta y hace lo que tiene que hacer. Pero..... es muy lenta la ejecución. Supongo que mi forma poco depurada de escribir código es la culpable. Sin embargo, cuando pruebo el código por partes no se ejecuta tan lento. La verdad es que no se a que puede ser debido. Os agradecería mucho sugerencias o cambios para que esta macro se ejecute de forma más rápida ya que ahora para cruzar por ejemplo 2 poblaciones de 14 genotipos y obtener 4 descencientes/genotipo le cuesta media hora aproximadamente (una eternidad). 

Otra de las dudas que tengo con respecto al formulario es que no entiendo para que se definen las líneas de código que están marcadas con flechas (agradeceria explicación):

'Asignamos los datos que recoge el formulario a cada una de la variables publicas que necesita la macro para trabajar

Poblacion1 = ListBox1.Value
Sheets(ListBox1.Value).Select '<=======
[A1].Select '<======

Poblacion2 = ListBox2.Value
Sheets(ListBox2.Value).Select '<=======
[A1].Select '<=======

NombrePoblacion = TextBox3.Value

NumeroDescendientesGenotipo = TextBox4.Value

NumParesGametos = Application.WorksheetFunction.Round((NumeroDescendientesGenotipo / 2), 0)

'Llamamos a la macro de cruzamiento
Cruzar2Poblaciones

Unload Me

End Sub

 

Os adjunto el fichero comprimido:

https://1drv.ms/u/s!ArSI6ZjR1bGVlNgcJUO5CAu1E5tzzA

Os recuerdo que:

 el formulario es: Seleccionar2PoblacionesCruce 

La macro se ejecuta pulsando el botón Cruzamientos específicos de la hoja Poblaciones

Si quereis ver el código la macro  es Cruzar2Poblaciones y está en el módulo Reproducción 

 

Muchas gracias por vuestra atención.

 

Enlace a comentario
Compartir con otras webs

Cita

Otra de las dudas que tengo con respecto al formulario es que no entiendo para que se definen las líneas de código que están marcadas con flechas (agradecería explicación):

Esas líneas creo que ya estaban estaban en tu formulario original, en principio pueden eliminarse.

En cuanto a la lentitud, debes tener en cuenta que la cantidad de procesos a realizar es enorme.

He eliminado Application.SvreenUpdating = True de todos los procedimientos y he realizado una prueba de cruce con dos poblaciones de 25 genotipos cada una y 4 descendientes y no me ha llegado a 3 minutos.

Prueba y comentas, pero poco queda por hacer tal como está diseñado el sistema.

Enlace a comentario
Compartir con otras webs

Hola @Antoni,

gracias por los comentarios. Respecto al formulario, igual lo tomé de otro y no me acordaba. Quitaré esas líneas. 

Respecto a la lentitud. La prueba que has hecho y el tiempo que te ha costado me parece razonable. No entiendo porque ayer resultaba tan lento en mi ordenador. Aplicaré los cambios que comentas y lo volveré a probar.

Otra pregunta importante. Cómo habrias diseñado el sistema tú? Ya sabes que soy novato programando y entra dentro de lo normal no ser muy eficaz con el diseño, pero me interesa aprender y tener en cuenta otros puntos de vista.

Gracias.

Enlace a comentario
Compartir con otras webs

Hola de nuevo @Antoni,

He hecho la misma prueba que tú (dos poblaciones de 25 genotipos cruzadas para obtener 4 descendientes/genotipo) y le ha costado casi 50 minutos. Sinceramente no sé que está pasando. Todo esto realizado en un ordenador con procesador i7, 8GB RAM y el archivo está en un SSD. Excel 365 de 32bits. Si me saliera en menos de tres minutos como a ti estaría contentisimo. Que puede estar pasando?

Respecto al diseño. En el caso concreto de cruzar dos poblaciones la macro no tiene que evaluar celda a celda colores, porque los genotipos ya estan definidos y solo genera combinaciones de rangos ya existentes, los copia (por columnas) y los pega en otros sitios. Recuerda que aquí no ha hecho ninguna evaluación. Además cuando he ido probando el código por partes, no le constaban tanto. Aquí el problema tiene que ser otro. Sobre todo porque lo mismo a ti te sale en menos de tres minutos :blink:.

Soy consciente que el uso de colores como unidad de información ralentiza algunos procesos, pero como lo quiero para un uso docente tiene que ser así. Los colorines hacen muy visual la explicación de conceptos complejos. Hace años intenté hacer algo parecido a esto utilizando otro lenguaje (R) muy usado para analisis estadístico y que permite escribir funciones de usuario. Este lenguaje maneja con mucha facilidad el cálculo matricial. A la complejidad de conceptos genéticos se unia la complejidad de usar matrices llenas de números y con salidas en formato texto. Para mis alumnos era peor que mis densas parrafadas. Lo acabe abandonando. Al ver que con Excel y VBA podia reunir dos mundos, el visual, al colorear celdas, y el de programación, para simular procesos biológicos, pensé en retomar mis simulaciones. Ese es el motivo del diseño. Con lo que llevo hecho (definir poblaciones y generar gametos) he resuelto una parte de ejemplos de forma sencilla para los alumnos. Si puedo completar la simulación de cruces, podré hacer algunas prácticas simulando procesos que en la vida real ocupan varias generaciones y no les puedo "hacer ver"en un semestre.

Espero que podamos encontrar la "tonteria" que hace que la macro en mi equipo vaya de pena y en el tuyo muy bien.

Saludos.

 

 

Enlace a comentario
Compartir con otras webs

@Salva Roselló, no sé si he usado el archivo bien, pero sin tener un maquinón (bueno, algo mejor que el de @Antoni :rolleyes:), me ha tardado  1 minuto eligiendo en el formulario las 2 poblaciones que dices y 4 descendientes :huh:

Te dejo el fichero con la población que he creado, que se llama "mia", a ver si lo hice bien. He usado el archivo "tal cuál" lo has subido

Fichero Haplo

Enlace a comentario
Compartir con otras webs

Hola @Haplox, si que lo has hecho bien. Y el tiempo que te ha tardado es muy bueno para mi (con eso me conformo de sobra). Lo único que se me ocurre para explicar el retraso brutal de la ejecución de la macro en mi ordenador es que haya interferencias con otras Add-Ins de Excel que tengo instaladas. Ya no se me ocurre nada más. Lo probaré en otro ordenado que no sea mio por ver si es eso. Gracias por la confirmación de que el código no está mal (si a ti y a  @Antoni se os ejecuta bien el problema está en mi máquina).

Enlace a comentario
Compartir con otras webs

Archivado

Este tema está ahora archivado y está cerrado a más respuestas.

  • 96 ¿Te parecen útiles los tips de las funciones? (ver tema completo)

    1. 1. ¿Te parecen útiles los tips de las funciones?


      • No
      • Ni me he fijado en ellos

  • Ayúdanos a mejorar la comunidad

    • Donaciones recibidas este mes: 0.00 EUR
      Objetivo: 130.00 EUR
  • Archivos

  • Estadísticas de descargas

    • Archivos
      177
    • Comentarios
      90
    • Revisiones
      27

  • Crear macros Excel

  • Mensajes

    • Buenas noches quisiera hacer esta formula auto incremental    =SI(INDIRECTO("'Casos de Prueba'!I1")="Resultados Ciclo 1"; SI(CONTAR.SI(INDIRECTO("'Casos de Prueba'!I:I"); "OK")=0; 0; CONTAR.SI(INDIRECTO("'Casos de Prueba'!I:I"); "OK")); 0)      para que cada vez que copiase y pegase la celda con la formula  se incrementara la letra en este caso la I pasara a J ,como el numero perteneciente a Resultados Ciclo pasando en este caso del 1 al 2.   Tengo también esta formula =CONCATENAR("CP";TEXTO(MAX((SI((ESNUMERO(HALLAR("CP";A$1:A1)))*(A$1:A1<>"");VALOR(EXTRAE(A$1:A1;3;3));0))+1);"000")&" - "&B2) quisiera que no tuviera los 3 ceros si no que fuera por ejemplo CP1 y se fuera incrementando. Gracias un saludo.
    • Con el diseño así como lo tiene en su libro, una fórmula de BUSCARV con COINCIDIR debería ser de utilidad =C5*BUSCARV($C$1,Tabla1[#Todo],COINCIDIR($D5,Tabla1[#Encabezados],0)) Es con lo que participaría en su consulta. Lo que resta es definir que hacer si no encuentra la OT porque así como esta le devolvería error en ese caso, o si tiene condiciones que haya podido omitir también le afectarían el resultado.
    • He cambiado mi macro a este: Sub repetir() Set a = Sheets(ActiveSheet.Name) uf = a.Range("C" & Rows.Count).End(xlUp).Row 'ultima fila con datos ActiveCell.Select ActiveCell.Offset(1, 0).Select   'Application.OnTime Now + TimeValue("00:00:10"), "repetir", , True End If End Sub   Lo que no se es como detenerlo al llegar a la ultima fila con datos de la columna C. Muchas gracias
    • Buenas tardes a todos. Tengo un problema que preciso de vuestra ayuda.  Tengo que controlar los gastos de la oficina que trabajo y he de repartir unos gastos a % según una OT y unos tipos de gastos. Envío un archivo adjunto. Lo que necesito es que lo que aparece en la columna en amarillo lo haga automáticamente, teniendo en cuenta los datos de la tabla a la derecha. Por ejemplo, el primer gasto tiene una cuota de 1477 euros y teniendo en cuenta que es un gasto de tipo Común y que la OT es la 12810234, le corresponde un gasto de 605,57 euros ya que según la tabla de la derecha su % a imputar es de un 41%. ¿alguien me puede ayudar con la formula? He de añadir muchas más líneas y más hojas con el resto de OT y en el futuro cambiar más datos, así que necesito automatizarlo con una formula Excel. Gracias. Control de gastos.xlsx
    • Hola buenas tardes: Por favor me pueden ayudar a realizar lo siguiente. ejecutar una macro después de un tiempo, que recorra una columna a partir de la celda activa hacia abajo. Es una lista extensa, que filtro desde la columna B. y solo me muestra las filas que me interesan. ejemplo: Si mi celda activa es la C23 ejecutar la macro y baje una celda y repite la macro después de 20 segundos y lo vuelve hacer(Simpre bajando una celda), y que este se detenga hasta la ultima fila que este visible en el filtro. Ya que puedo tener muchos datos mas.   Gracias   Prueba filtro y avance.xlsm
  • Visualizado recientemente

    • No hay usuarios registrado para ver esta página.
×
×
  • Crear nuevo...

Información importante

Echa un vistazo a nuestra política de cookies para ayudarte a tener una mejor experiencia de navegación. Puedes ajustar aquí la configuración. Pulsa el botón Aceptar, si estás de acuerdo.