Autodesk Inventor‎ > ‎Autodesk Inventor VBA.‎ > ‎4. Interacción con el Usuario‎ > ‎

4.2. Selección Interactiva

El segundo método de selección que permite Autodesk Inventor ofrece un mayor control sobre el proceso de selección que se ejecuta desde el mismo programa que utilizará los objetos seleccionados. Esta capacidad se expone a través del objeto InteractionEvents. Este objeto implementa, además de la selección en pantalla, los eventos del ratón y del teclado. La porción de la jerarquía de objetos que corresponde al objeto InteractionEvents se muestra a continuación.

El procedimiento para ejecutar la selección interactiva desde nuestro programa supone los siguientes pasos:

  1. Crear un objeto InteractionEvents.
  2. Definir su comportamiento estableciendo las propiedades necesarias.
  3. Conectar a los eventos soportados por el objeto InteractionEvents.
  4. Conectar a los eventos soportados por el objeto InteractionEvents asociado.
  5. Iniciar el proceso de interacción y responder a los eventos SelectEvents.

El objeto SelectEvents soporta una serie de eventos que se disparan cuando el usuario realiza una selección de geometría desde elementos de la Interfaz de Usuario tales como la ventana gráfica o el Explorador de Objetos. A diferencia de los eventos del ratón (MouseEvents) estos eventos sólo se disparan cuando algo que tiene que ver con la selección de usuario tiene lugar.

Retomando el ejemplo de la clase anterior, queremos ahora permitir la selección desde nuestra macro de lectura de superficies, controlando en el proceso de selección que las entidades seleccionadas sean las correctas. Como hemos dicho, la selección depende de eventos. Normalmente en Visual Basic los eventos se implementan desde un módulo de clase.En las versiones más recientes de Autodesk Inventor tenemos la posibilidad de implementar la interacción sin necesidad de crear el módulo de clase. Pero la creación de este módulo tiene la ventaja de poder encapsular su mecanismo interno exponiendo sólo los aspectos deseados y la facilidad de su reutilización. Posteriormente introduciremos variantes que aprovechan las nuevas posibilidades. Una versión sólo utilizable en la versión 2011 o posteriores se explica en el tema 4.3. Selección empleando el método Pick.

Una clase es una plantilla a partir de la cual se pueden crear objetos. La clase especifica las propiedades y métodos que serán comunes a todos los objetos que son ocurrencias de esa clase. Las clases se formulan en módulos de clase. Un objeto que es una ocurrencia de una clase puede ser creado en un programa mediante un par de expresiones de la forma:

En la sección de Declaraciones Generales:

Private nombreObjeto As nombreClase

En el Procedimiento:

Set nombreObjeto = New nombreClase

En el programa, se puede tener acceso a las propiedades del objeto mediante expresiones cuya sintaxis se muestra en la siguiente tabla:

Tarea Expresión
Asignar valor a una propiedadnombreObjeto.nombrePropiedad = valor
Obtener el valor de una propiedad nombreObjeto.nombrePropiedad
Invocar un método nombreObjeto.nombreMetodo(arg1, ...)
Provocar un eventoRaiseEvent nombreEvento

Ante todo será necesario crear un nuevo módulo de clase para habilitar las funcionalidades de los InteractionEvents y de los SelectEvents. Este módulo de clase lo podremos reutilizar para implementar la selección desde cualquier programa VBA de Autodesk Inventor.

Módulo de Clase:

El módulo de clase que crearemos poseerá dos Propiedades:

Filtro: contiene el valor de enumeración (Enum) del tipo de filtro que deseamos utilizar. Su valor predeterminado será kPartDefaultFilter, el filtro de Parte predeterminado.

Mensaje: la cadena de texto que se presentará al usuario en la línea de estado. Su valor predeterminado será "Seleccione una entidad". Expondrá además el método Designa que solicita la intervención del usuario para designar una entidad y devuelve la entidad seleccionada al procedimiento desde donde se invoca. Los pasos a seguir para crear este módulo de clase son los siguientes:

  1. Crear el nuevo Módulo de Clase

    1. Para insertar un nuevo módulo de clase. Se puede emplear el menú contextual del explorador de proyectos.

    2. Dar al nuevo módulo un nombre significativo, por ejemplo clsSelecc. Es conveniente emplear un prefijo que corresponda al tipo, en este caso, cls para denotar "Clase".

    3. Declarar los objetos de evento, Interacción y Selección:
      Private WithEvents oEventosInteracc As InteractionEvents Private WithEvents oEventosSelecc As SelectEvents
      Obsárvese que una vez declarados los objetos de evento los mismos aparecerán en la lista desplegable izquierda de la ventana de código correspondiente al módulo de Clase.
  2. Propiedades:

    1. Declarar las propiedades: Se declararán dos variables Private, es decir, no accesibles desde fuera del objeto. Estas variables estarán destinadas a contener el valor del filtro y del mensaje y se suelen conocer en la terminología de la programación orientada a objetos como variables miembro. Por ese motivo las identificaremos con el prefijo m_.
    2. Private m_Flt As SelectionFilterEnum
      Private m_Msj As String
    3. Añadir los procedimientos destinados a leer (Get) y a escribir (Let) el valor de estas propiedades.
      En el menú Insertar (estando el foco en la ventana de código de la clase) seleccionar Procedimiento:
      Teclear "Filtro" en la casilla de texto Nombre, seleccionar Propiedad en el recuadro Tipo y pulse Aceptar. Las siguientes líneas de código aparecerán en la ventana del módulo de clase:
      Cambiaremos algunos elementos de este código predefinido para obtener lo siguiente:
      Public Property Get Filtro() As SelectionFilterEnum
      Filtro = m_Flt
      End Property
      Public Property Let Filtro(ByVal eFiltro As SelectionFilterEnum)
      m_Flt = eFiltro
      End Property
    4. Se procederá de igual manera para crear los procedimientos de lectura y escritura para la propiedad Mensaje. El resultado se muestra a continuación:
      	
      Public Property Get Mensaje() As String
      Mensaje = m_Msj
      End Property
      Public Property Let Mensaje(ByVal sMensaje As String)
      m_Msj = sMensaje
      End Property
    5. Los valores predeterminados se establecerán en el momento de crear el nuevo objeto basado en la clase. Al crearse éste se dispara el evento Initialize.
      En la lista desplegable de eventos correspondientes a la clase seleccionamos Initialize, con lo que se crea el marco del procedimiento que se ejecutará al disparase ese evento. En ese procedimiento se incluirán las expresiones destinadas a dar los valores predeterminados a estas propiedades. En estas expresiones se asignan los valores predeterminados a las propiedades Filtro y Mensaje:
      Filtro = kPartDefaultFilter
      Mensaje = "Seleccione una entidad"
    6. Se declarará además un indicador booleano para controlar el fin del proceso de selección:
      Private bolEnSeleccion As Boolean
      El valor de esta variable se establecerá como True en el procedimiento que implementa la selección.

    7. El valor de bolEnSeleccion será cambiado a False en el momento que esa selección concluya. Esto será determinado a través del evento OnSelect del objeto oEventosSelecc. Para ello escribimos el código del correspondiente procedimiento. Para ello seleccionamos en la lista desplegable izquierda el objeto oEventosSelecc y en la derecha el evento OnSelect: Al seleccionar el procedimiento OnSelect se creará la estructura básica para el procedimiento que restituirá el valor de bolEnSeleccion a False. Al seleccionar en la lista izquierda oEventosSelecc se habrá creado de manera automática el procedimiento para su evento predeterminado, OnPreSelect. Podemos eliminar este procedimiento, pues no lo necesitaremos.
      Private Sub oEventosSelecc_OnSelect _
      (ByVal JustSelectedEntities As ObjectsEnumerator, _
      ByVal SelectionDevice As SelectionDeviceEnum, _
      ByVal ModelPosition As Point, _
      ByVal ViewPosition As Point2d, _
      ByVal View As View)

      bolEnSeleccion = False
      End Sub
      La variable de control bolEnSeleccion permitirá establecer dentro del método que ejecutará la selección, que en nuestro caso denominamos Designa (ver siguiente epígrafe), un bucle que espere a que el usuario haga su selección. El procedimiento es sencillo:
      bolEnSeleccion = True
      Do While bolEnSeleccion
      DoEvents
      Loop
      DoEvents pasa el control al sistema operativo hasta que se termine el procesamiento de los eventos.

    Queremos hacer notar que el cambiar a False el valor de la variable de control al producirse cualquier selección por parte del usuario significa que saldremos del bucle en el momento que designemos algo. Por eso estaremos limitados a elegir un solo objeto.

    Para permitir selecciones múltiples debemos establecer otro sistema para terminar la selección, por ejemplo habilitando un botón Aceptar en un formulario no modal, o reproduciendo el comportamiento usual en aplicaciones como AutoCAD, donde la interacción concluye al pulsar la tecla INTRO. Las selecciones múltiples son el tema del próximo ejercicio.

  3. Implementar el Método Designa:

    Ahora describiremos los pasos necesarios para implementar el método de selección dentro de nuestra clase. Daremos a este método el nombre Designa. Este método recibirá un argumento que servirá como filtro de selección que nos permita definir el tipo de objeto que queremos obtener y devolverá el objeto seleccionado. Los pasos a seguir son:

    1. Crear una nueva función dentro de nuestro módulo de clase clsSelecc a la que daremos el nombre de Designa. Esta función la definiremos como Public y del tipo Object:
      Public Function Designa() As Object
      ...
      End Function
    2. Establecer el valor de bolEnSeleccion a True - ver pasos 2.v y 2.vi.
    3. Crear un objeto InteractionEvents utilizando el método CreateInteractionEvents del objeto CommandManager de la aplicación. La referencia a este objeto será creada a partir de la variable oEventosInteracc.
      Set oEventosInteracc = _
      ThisApplication.CommandManager.CreateInteractionEvents
    4. Asegurarnos que está habilitada la interacción.
      oEventosInteracc.InteractionDisabled = False
    5. Escribir un mensaje en la línea de estado indicando la acción a seguir por el usuario. Para ello se empleará la propiedad StatusBarText del objeto InteractionEvents. El mensaje es el asignado a la propiedad Mensaje, guardado en la variable m_Msj. Una vez concluida la operación se deberá borrar el mensaje sustituyéndolo por una cadena vacía ("").
      oEventosInteracc.StatusBarText = m_Msj
    6. Establecer una referencia a los eventos de selección.
      Set oEventosSelecc = oEventosInteracc.SelectEvents
    7. Establecer el filtro segán el valor asignado a la propiedad Filtro que se guarda en la variable m_Flt.
      oEventosSelecc.AddSelectionFilter m_Flt
    8. Iniciar el objeto InteractionEvents. Este método inicia la operación del objeto InteractionEvents en Autodesk Inventor. Los eventos de los objetos InteractionEvents, MouseEvents, SelectEvents,y KeyboardEvents comienzan a dispararse después de invocar el método Start. El método Start hará que se dispare el método OnActivate del objeto InteractionEvents.
      oEventosInteracc.Start
    9. Esperar hasta que está realizada la selección. Ver lo expuesto en los pasos  2.v y 2.vi.
         
      Do While bolEnSeleccion
              DoEvents
          Loop

    10. Recuperar la entidad designada. Para ello será necesario crear una referencia al objeto ObjectsEnumerator (enumerador genérico para un grupo de objetos). Este objeto expone las propiedades Count, Item y Type.
      Dim oEntsSelecc As ObjectsEnumerator
      A este objeto se le asignará lo seleccionado:
      Set oEntsSelecc = oEventosSelecc.SelectedEntities
      Todo lo seleccionado corresponderá a lo especificado mediante el filtro de selección que se le pasó como argumento a la función Designa. Aunque según lo dicho más arriba esta implementación devolverá una sola entidad es recomendable comprobar si realmente hay algo seleccionado (mediante el valor de la propiedad Count).

    11. En caso de haber algo seleccionado se devolverá como resultado de la función la entidad designada:
      Set Designa = oEntsSelecc.Item(1)
    12. Ya terminada la selección será necesario detener InteractionEvents:
      oEventosInteracc.Stop
    13. Y eliminar las referencias creadas a los objetos SelectEvents e InteractionEvents.
      Set oEventosSelecc = Nothing
      Set oEventosInteracc = Nothing
  4. Invocar el módulo de Clase desde una Macro:

    Para utilizar este mádulo de clase será necesario definir un procedimiento en un módulo normal. En ese procedimiento debemos:

    1. Declarar una variable de tipo clsSelect:

      Dim oSelecc As New clsSelecc

    2. Declarar una variable del tipo de objeto que deseamos procesar en nuestro programa, por ejemplo, para una cara:
      Dim oCara As Face
    3. Establecer el valor de las propiedades Filtro y Mensaje a los valores deseados en este caso:
      oSelecc.Filtro = kPartFaceFilter
      oSelecc.Mensaje = "Seleccione una Cara"
    4. Invocar el método Designa del objeto oSelecc:

      Set oCara = oSelecc.Designa

    5. Procesar el objeto devuelto según los objetivos de nuestro programa.

Ejercicio:

Modificar el Ejercicio propuesto en el capítulo 4.0 incluyendo la selección interactiva tal como ha sido descrita en los párrafos anteriores. Los resultados se mostrarán en el formulario indicado más abajo.

Figura 1. Formulario.

Código para los eventos del formulario.

Option Explicit

Dim oDoc As PartDocument
Public oCara As FACE
Private Sub cmdSeleccion_Click()
    Dim oSelecc As New clsSelecc
    oSelecc.Filtro = kPartFaceFilter
    oSelecc.Mensaje = "Seleccione una cara"
    Me.Hide
    Set oCara = oSelecc.Designa
    lblResultado.Caption = "Pulse Calcular para ver el resultado"
    Me.Show
End Sub
Private Sub cmdAceptar_Click()
    Set oDoc = ThisApplication.ActiveDocument
    Dim Area As Double
    Area = oCara.Evaluator.Area
    'tenemos el area en cm2 pasamos a mm2
    Dim eUnidad As UnitsTypeEnum
    eUnidad = oDoc.UnitsOfMeasure.LengthUnits
    Dim sUnidad As String
    sUnidad = oDoc.UnitsOfMeasure.GetStringFromType(eUnidad)
    Dim sUnidadArea As String
    sUnidadArea = sUnidad & "^2"
    Dim sArea As String
    sArea = _
    oDoc.UnitsOfMeasure.GetStringFromValue(Area, sUnidadArea)
    'ya tenemos en mm2 ahora mostramos el resultado
    lblResultado.Caption = "Area =" & sArea
End Sub
Private Sub CmdCerrar_Click()
    Unload Me
End Sub

Puede descargar el presente proyecto desde el enlace que aparece al final de la página.

Reinaldo Togores Fernández,
14 mar 2011, 14:14
v.1