Solo quiero saber si hay alguien que pueda explicarme sencillamente el concepto de modulos de clase, y si no es mucha molestia mostrarme un ejemplo. Gracias. EDUARDO OLAZ ============ Un módulo de clase es un tipo de módulo de código, con el que se pueden crear objetos que luego se pueden utilizar. El módulo de clase en realidad es una estructura que puede almacenar datos (Propiedades o atributos) y procedimientos sub y funciones (Métodos). En un módulo de clase también se pueden definir eventos que generará la clase cuando suceda lo que el programador determine. El módulo de clase en realidad es algo así como los planos y el libro de instrucciones de un objeto. Es decir, la clase define cómo va a ser y cómo se va a comportar el objeto. El objeto no existe hasta que la clase lo crea. El objeto se crea cuando se realiza una "Instancia del mismo". Por ejemplo si tenemos el módulo de clase con el nombre clsMiClase, para usarla desde otra parte del código podemos escribir Dim mcObjeto1 as clsMiClase Con esto hemos reservado una zona de memoria para poder usar la clase clsMiClase El objeto no existe todavía; mcObjeto1 es una variable que "apuntará" al objeto cuando realmente se cree. para crearlo (crear la instancia del objeto) haremos Set mcObjeto1 = new clsMiClase En este momento, ya existe el objeto. Se puede declarar y crear el objeto de forma simultánea. Supongamos que tenemos definida la clase clsCuentaBancaria Si hacemos Dim cbCuenta_001 as new clsCuentaBancaria Dim cbCuenta_002 as new clsCuentaBancaria Dim cbCuenta_003 as new clsCuentaBancaria Hemos creado tres objetos del tipo clsCuentaBancaria (instancias de clsCuentaBancaria) Si la, clase clsCuentaBancaria tiene las propiedades Titular y NumeroDeCuenta, de escritura y lectura, podremos hacer: cbCuenta_001.Titular = "Pepe Camuñas" cbCuenta_001.NumeroDeCuenta = "00000001" cbCuenta_002.Titular = "Pepa Araujo" cbCuenta_002.NumeroDeCuenta = "00000002" cbCuenta_003.Titular = "Lorenzo Parra" cbCuenta_003.NumeroDeCuenta = "00000003" Si por ejemplo la clase clsCuentaBancaria tuviera definido el procedimiento (Método) GrabarDatos, cbCuenta_001.Grabardatos cbCuenta_002.Grabardatos cbCuenta_003.Grabardatos actualizarán los datos de las respectivas cuentas en las tablas correspondientes. Al final conviene destruir los objetos. por ejemplo así set cbCuenta_001= nothing set cbCuenta_002= nothing set cbCuenta_003= nothing Si tuviéramos, por ejemplo la clase clsMiClase, en la que hayamos definido eventos, para poder interceptar los eventos de la clase, al declararla hay que usar WithEvents Por ejemplo Dim WithEvents mcMiMejorClase as clsMiClase Y en otra parte del código escribiremos Set mcMiMejorClase = New clsMiClase Si se declara con eventos no se puede crear el a la vez que se declara la variable objeto. Por ejemplo: Dim WithEvents mcMiMejorClase as New clsMiClase daría error. Las Propiedades de la clase se definen mediante procedimientos Property, que en realidad son Del Tipo Sub, el de escritura y del tipo Function el de lectura. La diferencia es que un procedimiento Property debe tener el mismo nombre para el de lectura y Escritura, y el mismo tipo de parámetro. Por ejemplo mediante el siguiente código: Public Property Let ErrorSinNumeros(ByVal GenerarError As Boolean) BlnErrorSinNumeros = GenerarError End Property Public Property Get ErrorSinNumeros() As Boolean ErrorSinNumeros = BlnErrorSinNumeros End Property Declaramos la propiedad de la clase ErrorSinNumeros, que será del tipo Boolean Property Let ErrorSinNumeros permite asignar el valor a la variable Privada BlnErrorSinNumeros, declarada a nivel del módulo de clase. Lo de tener definidas las variables, que van a guardar las propiedades de la clase, de forma privada es para poder utilizar una de las características de las clases que es la Encapsulación. Con ello el usuario de la clase, para poder asignar el valor a la variable, tendrá que utilizar el procedimiento Property correspondiente, En este procedimiento podremos controlar si el valor pasado como parámetro para la propiedad tiene un valor adecuado. Por ejemplo, si tenemos definida la clase Curso, y en ella la propiedad NumeroDeAlumnos, de tipo long, no tendría sentido permitir que se introdujera un valor negativo, o el valor 12586987. Cuando se define una clase es para utilizarla nosotros u otros programadores en un programa concreto, e incluso para poder reutilizarla en sucesivos programas. La utilización de clases tiene la gran ventaja de que, si están bien definidas, podemos facilitarnos la vida o la del programador que las utilice, así como la posterior depuración o cambios en los programas. En realidad continuamente estamos utilizando clases, por ejemplo el módulo que está asociado a un formulario es un módulo de clase. Aquí te incluyo una clase que adjunté el otro día en mi respuesta a una pregunta de Mario Roman Es una clase que permite extraer de forma sucesiva valores numéricos aleatorios, sin que se repitan, como en el bingo Si observas tenemos definidas en ella las siguientes propiedades públicas: Numeros NumeroInferior NumeroSuperior NumerosExtraidos ReanudarTrasUltimo ErrorSinNumeros Siguiente Tiene definidos los métodos públicos Inicializar Revolver También tiene el evento EventoSorteo que puede enviar un parámetro del tipo TEventoSorteo Depende cuando se genere el evento el parámetro que enviará será csEvtClaseCreada csEvtSerieInicializada csEvtSerieAleatorizada csEvtCambiadoNumeros csEvtExtraidoNumero csEvtExtraidoUltimoNumero csEvtNumerosAgotados csEvtClaseTerminada Cuando se inicializa la clase, por defecto asigna los siguientes valores a las propiedades ReanudarTrasUltimo = True ErrorSinNumeros = False NumeroInferior = 1 Numeros = 90 Estas propiedades podrían ser adecuadas para usarlas en un programa que emulara un juego de Bingo, o de Loto. Si pusiéramos NumeroInferior = 1 Numeros = 40 Nos serviría para un programa de baraja Española Si pusiéramos NumeroInferior = 1 Numeros = 54 Nos serviría para un programa de pócker con 2 comodines Si pusiéramos NumeroInferior = 12763 Numeros = 1412 Nos serviría para un programa que efectuara sorteos con venta de boletos numerados, en el que en rifas anteriores se hubieran vendido 12762 boletos, y en ésta hemos vendido 1412. Como ves, la misma clase sirve para diferentes tipos de programa, sin tener que efectuar cambios en el código de la misma. Aquí te incluyo el código. ____________________________________ Option Explicit ' Número a devolver cuando se terminen ' los número disponibles Private Const conlongMinimo As Long = -2147483648# ' Tipos de evento Public Enum TEventoSorteo csEvtClaseCreada csEvtSerieInicializada csEvtSerieAleatorizada csEvtCambiadoNumeros csEvtExtraidoNumero csEvtExtraidoUltimoNumero csEvtNumerosAgotados csEvtClaseTerminada End Enum ' Tipos de errores Public Enum TErrorSorteo csErsRango = 19000 csErsElementos = 19010 csErsSinNumeros = 19020 End Enum ' Array con los números Dim alngNumeros() As Long ' Valor inferior de los números Dim lngNumeroInferior As Long ' Total de números a sortear Dim lngNumeros As Long ' Total de números extraídos Dim lngExtraidos As Long ' Generación automática Sí/No ' de una nueva serie de números ' al finalizar los números Dim blnReanudar As Boolean ' Indica si se genera un error ' al finalizar los números Dim BlnErrorSinNumeros As Boolean ' la clase genera el evento EventoSorteo Event EventoSorteo(Evento As TEventoSorteo) Private Sub Class_Initialize() ' Inicializa con números tipo al bingo RaiseEvent EventoSorteo(csEvtClaseCreada) ReanudarTrasUltimo = True ErrorSinNumeros = False NumeroInferior = 1 Numeros = 90 Inicializar End Sub Public Property Let Numeros(ByVal Elementos As Long) ' Define el total de números a sortear Select Case Elementos Case Is < 1 Err.Raise csErsElementos, _ "Clase sorteo", _ "Debe haber, al menos, un elemento" Case Is <> lngNumeros lngNumeros = Elementos RaiseEvent EventoSorteo(csEvtCambiadoNumeros) Inicializar Case Else End Select End Property Public Property Get Numeros() As Long Numeros = lngNumeros End Property Public Property Let NumeroInferior(ByVal Numero As Long) lngNumeroInferior = Numero RaiseEvent EventoSorteo(csEvtCambiadoNumeros) End Property Public Property Get NumeroInferior() As Long NumeroInferior = lngNumeroInferior End Property Public Property Get NumeroSuperior() As Long NumeroSuperior = lngNumeroInferior + lngNumeros - 1 End Property Public Property Get NumerosExtraidos() As Long NumerosExtraidos = lngExtraidos End Property Public Property Let ReanudarTrasUltimo(ByVal Reanudar As Boolean) blnReanudar = Reanudar End Property Public Property Get ReanudarTrasUltimo() As Boolean ReanudarTrasUltimo = blnReanudar End Property Public Property Let ErrorSinNumeros(ByVal GenerarError As Boolean) BlnErrorSinNumeros = GenerarError End Property Public Property Get ErrorSinNumeros() As Boolean ErrorSinNumeros = BlnErrorSinNumeros End Property Public Property Get Siguiente() As Long lngExtraidos = lngExtraidos + 1 ' Si ya se habían extraído todos los números If lngExtraidos > lngNumeros Then RaiseEvent EventoSorteo(csEvtNumerosAgotados) ' Si hemos definido que se repita el proceso If blnReanudar Then Inicializar Siguiente = Siguiente() ' Si no se debe repetir el proceso Else ' Si debemos generar el error If BlnErrorSinNumeros Then Err.Raise csErsSinNumeros, _ "Clase sorteo", _ "Los números se han agotado" End If ' Se ha sobrepasado los números a extraer ' sin generar error ' Corregimos los números extraídos lngExtraidos = lngExtraidos - 1 ' Para mostrar la anomalía ' devolvemos el Long más bajo posible Siguiente = conlongMinimo End If Exit Property End If Siguiente = alngNumeros(lngExtraidos) If lngExtraidos < lngNumeros Then RaiseEvent EventoSorteo(csEvtExtraidoNumero) Else RaiseEvent EventoSorteo(csEvtExtraidoUltimoNumero) End If End Property Public Sub Inicializar() Dim i As Long Dim j As Long lngExtraidos = 0 ReDim alngNumeros(1 To lngNumeros) Randomize Timer For i = 1 To lngNumeros alngNumeros(i) = lngNumeroInferior + i - 1 Next i ' Revolvemos los números Revolver ' Generamos el evento para indicar ' que la serie se ha inicializado RaiseEvent EventoSorteo(csEvtSerieInicializada) End Sub Private Sub Class_Terminate() ' Eliminamos el array dinámico Erase alngNumeros RaiseEvent EventoSorteo(csEvtClaseTerminada) End Sub Public Sub Revolver() Dim i As Long Dim j As Long lngExtraidos = 0 For i = 1 To lngNumeros j = Int(Rnd * lngNumeros) + 1 Intercambia alngNumeros(i), alngNumeros(j) Next i RaiseEvent EventoSorteo(csEvtSerieAleatorizada) End Sub Private Sub Intercambia( _ ByRef Numero1 As Long, _ ByRef Numero2 As Long) Dim lngIntermedio As Long lngIntermedio = Numero1 Numero1 = Numero2 Numero2 = lngIntermedio End Sub ____________________________________ Saludos desde la calle Estafeta de Pamplona Eduardo Olaz [Microsoft Access MVP] eduardo@olaz.net