Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.


Mensajes - NEBIRE

Páginas: [1] 2 3 4
1
Visual Basic 6 / Re:Posicionar el cursor del mouse en un textbox
« en: Marzo 02, 2020, 01:08:19 pm »
No. No es lo adecuado.
Cuando se trata de un texto plano, no queda otra que buscar el punto deseado.

Tratándose de un entorno de programación, debes tener en cuenta que se utiliza una tabla de símbolos, donde constan todas las funciones con la información precisa para ser tratada.
Cuando haces doble clik, el IDE primero verá cual es la opción por defecto (en caso de diseño hablamos), típicamente ir a un módulo de inicialización del componente, si no se localiza ne la tabla, irá al primero que encuentre relacionado con dicho control (imagina que has puesto código para un Command1_KayDown, pués a ese y si no hay ningún método almacenado, entonces hará una entrada en la tabla para el método por defecto para dicho control, cual es el método por defecto, para cada control no sabría decirte, para un programador que actúa como usaurio dle IDE carece de importancia.

En realidad dichas entradas en la tabla, aparecen listadas en el código en sendos combobox, a la izquierda la de los componentes (general para los que no son componentes) y a la derecha los métodos del componente elegido (se localizan en la tabla y se añaden a dicho combo).

Entonces, por debajo lo que hace es simplemente preguntar a la tabla cuantas línea socupa el método (si existe) y en que línea está (aunque también puede crear dinámicamente al instante la imagen, me consta que no es el modo que usa VB6, tiene preferencia por 'dibujar el listado del módulo donde está en una imagen, pero el nº de línea le sirve para saber de modo instantáneo donde se localiza el punto exacto deseado, sin tener que buscarlo (pués eso sería lento e ineficiente siendo que está obligado a mantener una tabla de símbolos a la que preguntar donde está cada ocurrencia de cualquier cosa buscada).

De hecho si te das cuenta, el editor tiene un ancho fijo por defecto prefijado al implementarlo en 1024 caracteres, que es el largo máximo de una línea de código. Lo que denota que en efecto, lo renderiza como imagen, así aunque cambies el ancho de la ventana, el texto no ocupa ni más ni menos líneas (no se adapta, requiere scroll), pués esa adaptación exigiría renderizar de nuevo la vista (que es algo muy rápido, pero no si has renderizado  todo el documento completo, y no solo lo que se ve en la vista).

Aún así, me temo que es un poquito más complejo, pero eficiente y elegante a la vez. Me explico... en realidad renderiza de una sola vez el código dentro de cada función y las mantiene como imágenes sueltas (en el orden que las editas), así renderizar, supone solo 'pegar' cada una de las que aparecen en la vista, y por tanto el editor tiene solamente que vérselas a cada rato exclusivamente con la función que estás editanto en ese momento, lo que simplifica enormemente la tarea.

...y después de tanta perorata, espero que entiendas que no localiza un string "Command1_Click" en el tocho del texto, si no "Command1" en la tabla de símbolos (seguramente sea una tabla hash) que le da un puntero a los métodos que tenga, ahí de nuevo buscará  "Click1" y devolverá un puntero a los datos que almacene dicha función. Fijo que su texto y algunos datos más como número d elíneas que ocupa y posición absoluta (esta seguramente se recalcule, sumando las línea que ocupen todas las funciones previas, porque no es plan que con cada línea añadida o eliminada deba actualizarse dicho dato para cada función). Probablemente tenga también algo como un buleano que señale si existe una imagen renderizada del fragmento de código que ocupa la función,  tal que si es que sí la pegue y si es que no la genere al instante... respecto del "Click", podrá devolverlo solo sí: es el primero, el por defecto, o el único que tenga... ese es un detalle interno sin importancia al caso. Entonces una vez encontrado el método a mostrar, borra el contenido del editor, pega la imagen que corresponde a dicha función (que como he dicho seguramente tenga ya renderizada o se renderice al instante) y si no completa la página añade el siguiente o siguientes, por supuesto debe actualizar el scroll como convenga, pués otra cosa que debe mantener es cuantas líneas ocupa cada función y que índice ocupa en el total, y con esos datos es muy sencillo y rápido actualizar el scroll e indicar el número de línea al posicionar el cursor.

Aunqe las funciones búsqueda hoy día sean muy rápidas, la búsqueda en una tabla hash, toma un tiempo 1... es decir no requiere búsqueda, está localizada y por tanto tarda lo mismo esté la primera o la última, haya 5 entradas en la tabla o 500 millones.


Por supuesto, para el texto de un textbox, simplemente hay que buscar, no haya palabras clave que uno pueda decir 'se usa siempre estas 400, que le lleven a uno a querer meterlo en uan tabla hash, por cuestión de eficiencia, total un textbox tendrá un texto limitado y además sin un formato predefinido como sucede con el código fuente de un lenguaje.

2
Añde un ítem vacío (o los que precises) al objeto en la posición que corresponda.

3
Un addin sería también una opción plausible. Yo en cambio he tirado por otro derrotero... he creado un interlinker...

Para que sea útil para cualquiera, lo he subido y publicado en este link:
http://leandroascierto.com/foro/index.php?topic=3356.0

El addin de vbadvance, en realidad soluciona lo que necesitas, aunque en 2 pasos, primero para generarlo y luego para ejecutarlo.
La solución que yo te he puesto, solo te requiere compilarlo (la primera vez tendrás que activar la opción de 'autoejecutar' en el programa... en lo sucesivo ya cuando compiles arrancará (siempre puedes cambiar dicha opción). Cuandop generas el proyecto o el grupo de proyecto, lo compila y si la opción está activada y es un ejecutable lo abre, tal como quieres...

Aunque ahora que lo pienso, solo lo he probado con generar un proyecto, no con un grupo de proyectos...

4
Códigos - Aportes - Recursos / Inter-Linker
« en: Octubre 24, 2017, 10:45:56 am »
Un iterlinker, es un sencillo programa que se interpone entre el editor (en este caso vb6) y el compilador (en este caso el linker de MS).
Cuando desde el editor se reclama la compilación, el programa recibe el comando de vb6 y lo envía al linker, y antes de ello o después de ello puede hacerse lo que se necesite hacer.
 
Para ello, el programa (compilador, linker) debe ser renombrado, ya que su nombre lo tomará el interlinker, quién a su vez llama al compilador/linker original, por lo que éste debe conocer su nombre. No es buena que el interlinker, realice el cambio del nombre de forma automática, sin conocimiento del usuario, ya que de alguna manera eso supone alguna intrusión.
---------------------------------------------------------------------------------------------------------

En este caso, lo que el programa hace simplemente si compila correctamente y la opción está activa ejecuta el programa tras ser compilado (surge como respuesta del siguiente hilo: http://leandroascierto.com/foro/index.php?topic=3353.0 )
El resto de funcionalidad son comprobaciones de existencia, con un mínimo registro de actividad (si se activa la opción se guarda a fichero, si no solo se muestra en la ventana).
También guarda en un fichero (Linker.ini), las opciones activas elegidas por el usuario.

El programa para no ser intrusivo se cierra automáticamente tras 6 segundos de completar las tareas pedidas, dando tiempo a cambiar las opciones según interese.
---------------------------------------------------------------------------------------------------------

Instalación (no requiere registro):
0 - Abrir la carpeta donde se localiza VB6.exe y Link.exe
1 - Cambiar el nombre del linker (Link.exe) de microsoft al nombre LinkMS.exe
2 - Descomprimir éste programa y mover a la carpeta donde se encuentra VB6.exe
---------------------------------------------------------------------------------------------------------

Uso:
El programa solo funcionará correctamente si se localiza en la misma carpeta donde yace VB6.exe y el linker de MS. ya que no usan rutas globales, los 3 ejecutables deben estar en la misma carpeta:
VB6.exe
Link.exe (éste interlinker)
LinkMS.exe (el linker de MS, renombrado).

Cuando desde el entorno de vb6, pulsemos compilar un programa, el programa será compilado y al término ejecutado, si dicha opción se ha activado en el programa.
El programa permanece abierto unos 6 segundos para que dé tiempo a modificar las opciones.
---------------------------------------------------------------------------------------------------------

Un vistazo de la interfaz y un link de descarga:


https://workupload.com/file/WgZLJtD (30Kb. aprox)




5
Como dice Leandro, con las API siempre suele resolverse con píxels.

De todos modos, si en diseño pones siempre tus usercontrol en píxels (Scalemode = 3, vbpixels) y los formularios también, serán pocas ocasiones donde no se obtengan dichos valores.
Los valores siempre son devueltos en el scalemode del contenedor. Luego cambiar en tiempo de ejecución el 'sacalemode', suele generar problemas salvo que recurras a usar las propiedades 'ScaleLeft, ScaleTop, ScaleWidth y ScaleHeight'... junto con el método Scale, para generar tu propio sistema de cordenadas (que no interesa salvo que realmente se desee generar un sistema de cordenadas específico).

Pero nota que por ejemplo para imagenes el scalemode 'por defecto' suele ser vbHimetric (ni siquiera vbTwips)...

Aunque poseer una referencia de escalas es muy útil, casi toda esa funcionalidad en vb6 es un lastre si no se sabe utilizar y resulta confuso, porque no está bien documentado.


Otro modo es poner las funciones/propiedades en el propio usercontrol, para reclamar la escala...
(con esto debes dejar el scalemode en twips durante diseño, es decir no cambiarlo, ya que si lo pones en vbpixels, luego traduciría el valor de pixels a pixels, es decir no traduciria nada, erróneamente).

Código: (VB) [Seleccionar]
]
Public Function EscalarXToPx(ByVal Medida As Single) As Single
   EscalarXToPx = UserControl.ScaleX(Medida, UserControl.ScaleMode, vbPixels)
End Function
    Public Function EscalarXFromPx(ByVal Medida As Single) As Single
       EscalarXFromPx = UserControl.ScaleX(Medida, vbPixels, UserControl.ScaleMode)
    End Function

Public Function EscalarYToPx(ByVal Medida As Single) As Single
   EscalarYToPx = UserControl.ScaleY(Medida, UserControl.ScaleMode, vbPixels)
End Function
    Public Function EscalarYFromPx(ByVal Medida As Single) As Single
        EscalarYFromPx = UserControl.ScaleY(Medida, vbPixels, UserControl.ScaleMode)
    End Function

[/code]

Determinada funcionalidad es provista por el contenedor para sus propios controles. Ya que por sí mismo los controles no tienen forma clara de proveerla o bien el propio contenedor le basta tener una copia para manejarlo convenientemente haciendo inutil que el propio control la posea. Dichas propiedades y métodos son las llamadas 'extender'... Left, Top, Width, Height, Move son parte de ellas, provistas por el contenedor, algunas de ellas, solo aparecen durante diseño, otras todavía están disponibles en ejecución. Ergo otra solución es crear tu mismo tales propiedades, obviando las que provee el contenedor e invocando por dentro al contenedor...
Aquí un ejemplo para Left:
Código: (VB) [Seleccionar]
' Valores devueltos y entregados en píxels...
' ...pero el usercontrol mantiene el scalemode en twips (u otro valor)
Public Property Get LeftUc() As Single
    LeftUc = UserControl.ScaleX(UserControl.Extender.Left, UserControl.ScaleMode, vbPixels)
End Property
    Public Property Let LeftUc(ByVal x As Single)
        UserControl.Extender.Left = UserControl.ScaleX(x, vbPixels, UserControl.ScaleMode)
End Property

' TopUc
'WidthUc
'HeightUc



Finalmente otras funciones que te ayuden a entender la diferencia:
Código: (VB) [Seleccionar]
' Valores a entrar en el scalemode que tenga el control.
Public Sub MoveInTwips(ByVal Left As Single, Optional ByVal Top, Optional ByVal Width, Optional ByVal Height)
    With UserControl.Extender
        If (IsMissing(Top)) Then Top = .Top
        If (IsMissing(Width)) Then Width = .Width
        If (IsMissing(Height)) Then Height = .Height
       
        Call .Move(Left, Top, Width, Height)
    End With
End Sub

' Valores a entrar en píxeles
' (internamente se converten a la escala que contiene (vbtwips))
Public Sub MoveInPixels(ByVal Left As Single, Optional ByVal Top, Optional ByVal Width, Optional ByVal Height)
    With UserControl.Extender
        Left = Me.EscalarXFromPx(Left)
   
        If (IsMissing(Top)) Then
            Top = .Top
        Else
            Top = Me.EscalarYFromPx(Top)
        End If
       
        If (IsMissing(Width)) Then
            Width = .Width
        Else
            Width = Me.EscalarXFromPx(Width)
        End If
       
        If (IsMissing(Height)) Then
            Height = .Height
        Else
            Height = Me.EscalarXFromPx(Height)
        End If
       
        Call .Move(Left, Top, Width, Height)
    End With
End Sub

' Valores en el scalemode que tenga el control.
Public Sub Size(ByVal Width As Single, Optional ByVal Height As Single)
    If (IsMissing(Height)) Then Height = UserControl.Height
   
    Call UserControl.Size(Width, Height)
End Sub


Desde el formulario podrías probarlo con algo como:
Código: (VB) [Seleccionar]
    Dim m As single
   
    Me.Print CStr(UserControl1.EscalarXToPx(UserControl1.Left))
   
    Me.Print CStr(UserControl1.Left)
    Me.Print CStr(UserControl1.LeftUc)

    ' Valores son twips
    Call UserControl1.Move(800, 150, 180, 240)
   
    ' Valor dado es píxel, que se convierte a twips, elresto de parámetros mantiene su valor actual.
    Call UserControl1.MoveInPixels(150)
    ' Estas medidas en píxels se convierten a twips
    Call UserControl1.MoveInPixels(120, 150, 180, 240)
   
    ' Ahora los valores son twips, resultando como con 'Move'...
    Call UserControl1.MoveInTwips(800, 150, 180, 240)

   
    UserControl1.Left = 200
    UserControl1.LeftUc = 200

6
Aunque nunca lo he probado, vb6 tiene su propia opción...

Si vas al menú: Herramientas -> Opciones -> ficha general -> Frame 'Compilar', aparece la casilla:  "Compilar a petición" ("Compile On Demand" si lo tienes en inglés).
- Estando activa implica que vb6 compila el programa SÓLO cuando se lo indicas expresamente desde el menú.
- Estando desactivada implica que que vb6 compila el programa SIEMPRE tras pulsar 'ejecutar'. Es decir lo compila primero y luego lo ejecuta (que parece ser lo que tu quieres).

Si no te funciona, me comentas y miro de hacerte un ejecutable para interponerlo delante del linker...

7
Visual Basic 6 / Re:Centrar texto con objeto printer para un ticket
« en: Abril 16, 2017, 11:18:13 pm »
Citar
no se como decirle que mi ancho de hoja sera de
Pués cambia el papel... así se le indica el tamaño del papel (hay unas constantes predefinidas)

Código: (VB) [Seleccionar]
    Dim pr As Printer
   
    Set pr = VB.Global.Printer ' impresora por defecto...
    MsgBox pr.PaperSize ' comprueba que tamaño de papel tiene
    pr.PaperSize = 1 ' Este es el valor para 8.5", pero no 8cm (no sé si realmente querías poner 8cm, u 8pulgadas. 
    MsgBox pr.PaperSize ' verifica que el cambio fue aceptado...

Si al final realmente quires que sean 8 cm de ancho, entonces deberás definir el valor 256 (definido por el usuario).
Código: (VB) [Seleccionar]
    Dim pr As Printer
 
    Set pr = VB.Global.Printer ' impresora por defecto...
    with pr
        MsgBox .PaperSize ' comprueba que tamaño de papel tiene
       
        .PaperSize = 256 ' Este es el valor para indicarle un tamaño definido por el usuario. 
        '   esto fuerza a que tengas que definir las medidas que tiene el papel, estableciendo el ancho y alto para el objeto printer.
        .width = .scaleX(800, vbmillimeter, .scalemode) ' depende de qué scalemode tengas puesto en la impresora, puedes o no pasar el valor directamente o a ScaleWidth, etc... si no te aclaras deberás probar. Este modo lo soluciona más fácilmente, lo recomendado es que para la impresora tengas el scalemode al valor 5 (vbInches).
        .Height = .scaleY(???, vbmillimeter, .scalemode)
       
        MsgBox .PaperSize
    end with

8
Visual Basic .NET / C# / Re:textbox solo mayuscula en vb.NET
« en: Marzo 21, 2017, 05:28:47 pm »
En el evento Validate (Validating), puedes hacer las gestiones que tratan de asegurar que el contenido de un control de entrada del usuario es como se espera que sea, o bien es el momento de modificarlo como toque...

El código es tan sencillo como esto:
Código: (VB) [Seleccionar]
Private Sub TextBox1_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating
        TextBox1.Text = TextBox1.Text.ToUpper ' lo convierte a mayúsculas.
End Sub

El evento Validating, ocurre cuando un control pierde el foco en favor de otro. Si por ejemplo tras meter un texto se debe pulsar un botón, justo cuando pulsa el botón y antes de cambiar el foco al botón, se produce dicho evento... ...esto es más eficaz que hacerlo continuamente cada vez que el texto cambia (como sucedería en el evento "Changed").

En el ejemplo (usando el evento validating), si acontece algo que no debe permitirse, puede devolverse 'cancelar', en el argumento e, tras informar al usuario del asunto...
También es útil si resultare que no hay ningún botón y deba ser cambiado por el usuario (si la operación fuera algo más compleja), aquí un código de ejemplo:

Código: (VB) [Seleccionar]
Private Sub TextBox1_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating
        Dim k As UInt32
        Dim chr() As Char = TextBox1.Text.ToCharArray
        Dim charsInvalidos As String = "abcdefghijklmnñopqrstuvwxyzáéíóúü"

        For k = 0 To chr.GetLength(0) - 1
            If (charsInvalidos.Contains(chr(k)) = True) Then
                MsgBox("Cambie la letra '" & chr(k) & "' a mayúsculas, no se permiten minúsculas " & vbNewLine & "( Y de paso cambie el resto de letras minúsculas que existan).")
                e.Cancel = True
                Exit For '
            End If
        Next

        'TextBox1.Text = TextBox1.Text.ToUpper
 End Sub

9
Hoy he dispuesto de bastante tiempo y pude terminar de comentar un control de usuario que hice el mes pasado y de paso, he realizado otro similar.

El primero es un displayLCD numérico de 7 segmentos.
El segundo es un displayLCD alfanumérico de 5x7 puntos.

Ambos comparten muchas propiedades en común, aunque cada uno dibuja de manera distinta.
Una vez descargado el proyecto del link que se adjunta, y descomprimido en el lugar deseado y abierto el proyecto, podeis trastear con ambos controles. el proyecto consta de dos formuarios y en cada uno se opera sobre un tipo de control...

El displayLCD numérico, por ejemplo posee una propiedad "DisplayHora", que por sí misma lo convierte en un reloj. Este control, posee también una propiedad llamada "Numeración", tal que filtra que caracteres puede mostrar: Octal, decimal, hexadecimal. La propiedad solo filtra los caracteres que no admite, aunque se ha provisto también una función "convertir", para pasar un valore de una base de numeración a la otra...

Se adjunta una captura de las propiedades de ambos controles (ordenados por categorías, todas las que afectan al display, se han marcado como 'Display')... Como se ve, el display numérico, tiene más propiedades que el alfanumérico, aunque el alfanumérico, tiene más funciones que el numérico y además ocupa más tamaño, debido a la cantidad de datos para almacenar cada gráfico.




Se podría añadir mucha más funcionalidad, e incluso animaciones, pero mi tiempo libre es escaso, así que será para otra ocasión...
El display alfanumérico, solo se han proporcionado gráficos para los caracteres ASCII entre el 32 y el 129... por ello se ha provisto también una función para asignar gráficos personalizados e incluso para reasignar el gráfico de un carácter a otro, también una función que restablece los gráficos.

Aquí una captura de ambos controles sobre el proyecto de prueba:


Solo queda el link de descarga... Descargar, descomrpimir, abrir y trastear:
http://workupload.com/file/paaKCRS 102Kb.
MD5 (del rar): 64E9BD7345DA2FB487E4CD30604CFF3E
Podeis usar libremente el control en vuestros proyectos sin ningún tipo de límites.



10
Perdona, pero no te entiendo...
Lo primero que hice cuando me registré en el foro, fue leer las normas... soy de los que lee siempre la letra pequeña y los EULa de cabo a rabo...
Y bueno, he vuelto a leerlas por tu recomendación, por si había olvidado algo, y...no, no creo saltarme ninguna norma. Ya me dirás tú cual...

11
Acabo de ver tu mensaje sobre como mostrar y ocultar un label con un timer, de forma intermitente...
Deduzco pués que tu nivel es más bien de principiante y quizás te haya 'exigido demasiado', en mi mensaje previo...

Así que te pongo un código que te funcione perfectamente, en la línea de lo que tienes... pero eso sí, al menos sin la colección, basta un array (al menos son más rápidos). Te valdrá para pequeñas cantidades de permutaciones. Pero si te acercas o superas las 500.000-1.000.000 de permutaciones será muy lento.

Más arriba, te proponía apuntar a métodos que calculan 5-15 millones (según la potencia de tu equipo) en una décima de segundo, naturalmente sin almacenarlas, pero te hace falta más dominio...

Aún así, para lo que puedas necesitarlo te valdrá perfectamente el siguiente código. Todavía hay zonas que puedes optimizar, yo he dejado el código sencillo, para que te sea fácilmente entendible... (si lo ejecutas paso a paso (tecla F8) viendo como cambian las variables, podrías llegar a entenderlo perfectamente)
...observa al menos, como es el bucle externo el que a cada ciclo, va construyendo todas las secuencias de 2, 3, 4,5 6,... caracteres. La función te permite no sólo generar todas las permutaciones de tamaño del alfabeto, si no también de un tamaño menor.

Dado que usas cadenas (en vez de arrays de bytes), todo el proyecto, lo he dejado igual, con arrays de cadenas. La lista monaria, se genera antes del bucle, con un simple split, de ahí que el alfabeto, requiera un separador entre caracteres...

Tu ya, modifica a tu gusto...

Enlace de descarga:
http://workupload.com/file/Ze3cy9M  - 4'18Kb.

p.d.: Nota también que he modificado ligeramente la función "CalculaNumPermutas", que te poníamás arriba, para permitir calcular el número de permutaciones, para secuencias de un tamaño menor que el alfabeto. Es decir aunque el alfabeto tenga 8 caracteres, tu podrías querer solo secuencias de 5 caracteres. La modificación hecha a la función ahora lo permite, para adaptarse al algoritmo que también lo permite así.

12
Bien... he reactivado una extensión VPN y efectivamente VBForums sigue ahí... se ve que era un bloqueo geolocalizado que incluía mi IP...

Finalmente he podido leer la página a la que me derivabas. Y tras leer la funcionalidad, el propio  "Schmidt", aclara que no funciona con los OCX, sólo sirve para las librerías. Y alega que la razón, es que los OCX, requieren toda la implementación de: "OLEInPlaceSitting", que básicamene aloja el control en el contenedor.

En el mensaje nº7, lo explica en respuesta a alguien:
"From my point of view, yes - though OCXes are currently not supported by this method
(because there's a bit more complexity involved with them, due to "siting requirements".
For OCXes I'd use SxS-manifests, which should work from XP onwards too."

---------------
Sin embargo, no tienes que preocuparte demasiado del asunto. Si todavía pretendes no compilarlos en tu aplicación y no registrar tus controles OCX, es posible hacerlo. Hay sin embargo un requisito.
El OCX debe permanecer en la misma carpeta que la aplicación (no valen subcarpetas). Si es así, funciona correctamente aunque el control no esté registrado en el sistema.
Esto funciona debido a la forma en que Win2, trata a las librerías. Cuando una aplicación trata de obtener una instancia de un control, primero mira si la propia aplicación la incluye, si no es así, mira si en la carpeta donde yace la aplicación, existe dicho control, si tampoco es así, busca en la carpeta del sistema (...windows\system32\*.ocx), si no existe, busca si en el registro hay una entrada  para el mismo, y si sigue sin aparecer, es cuando te canta el error.

El caso para las DLLs, es igual, salvo que en ellas además puedes usar 'getobject', que exige la ruta explícitamente o 'CreateObject', que lo localiza directamente en el registro (en estos dos casos, se obvia la búsqueda anterior, ya que se proporciona un método implícito de localización, tal que si no se encuentra en esa localización marca error, sin buscar en parte alguna adicional...

La pega de este sistema (que tiene solución), es que si pretendes que tu control valga para muchos otros proyectos, no va a ser muy útil, hacer una copia del control en cada aplicación que generes. Entonces en ese caso, será adecuado moverlo a la carpeta del sistema...  y no hace falta registrarlo. Ahí está disponible para todas las aplicaciones que usen ese control
Si un cliente solo va a tener una aplicación que incluya tal o cual control, entonces es mejor que esté en la propia capeta del programa, y si va a tener varias aplicaciones que usan el mismo control es preferible ponerlo en la carpeta del sistema.
Fuera de esas dos ubicaciones (aparte de incorporarlo en la propia aplicación), es obligado registrarlo...

13
Bien... si prefieres seguir como lo tienes, puedes ver que l proyecto que te he puesto, porta el usercontrol en el propio proyecto, y puedes hacer Setparent sobre él y sobre el form2 y sus eventos funcionan correctamente.

Sin más detalles, me pregunto , si el problema no estará en el propio formulario. Ten en cuenta que si no cargas el formulario, tampoco se cargan sus controles.

Piensa que aunque un proyecto sea grande y extenso, no necesitas cargar todos los formularios en memoria, creas y destruyes formularios según los necesites:
Código: [Seleccionar]
' en vez de hacer
call form2.show(1)
' puedes hacer:
dim f as form
set f=new form2
call f.show (1)
set f=nothing

' de este modo, form2 nunca está cargado, pero creas instancias de él, que luego destruyes cuando ya no los necesites. Así mantienes a raya los recursos que utiliza tu programa, aunque sea un proyecto grande....


---------------------------------------
Respecto de VBForums:
Vaya. Y puedes entrar ahora?. A ver si mi ISP lo tuviera bloqueado... hace algunos meses, que esa web, siempre me aparece fuera de combate, incluso creo recordar que tiempo atrás lo miré en WHOIS, y ponía que el sitio había caducado (ahora me haces dudar y quizás fuera otra, pero si que sé que hace tiempo que no tengo acceso).

Me edito: He cambiado las DNS de mi ISP por otras y tampoco  tengo accso, quizás sea el sitio que tenga bloqueado un rango que incluya IPs de mi proveedor... lo miraré cuando acuda a casa de algún amigo o familiar que tenga otro proveedor, a ver si desde allí hay acceso...


14
Las permutaciones sin repetición se construyen de la siguiente forma:

Dado un alfabeto (ejemplo): "ABCDEF"
0 - Se van tomando los elementos uno a uno: A, B, C, D, E, F . Esto, es un bucle externo... y genera las variaciones monarias.
1 - Cada elemento así formado es un grupo (0-5). Y tras cada elemento, se añade el resto:
 AB,  AC, AD, AE, AF (es decir estos se añaden al grupo 0, luego serían 01, 02,03,04,05) y serían las variaciones binarias de la primera variación monaria.
2 - De nuevo a cada grupo así formado, se añade de nuevo otro elemento de los que aún no tienen, es decir nos centramos en el grupo 01+x
ABC, ABD, ABE, ABF,
3 - Un nuevo ciclo, añade otra de las letras restante, al grupo 012+x
ABCD, ABCE, ABCF
4 - De nuevo se añade otro ítem al primer grupo: 0123+x
ABCDE, ABCDF
5 - Finalmente cuando solo queda 1 ítem, acaba. Es decir cuando tenemos el tamaño del alfabeto,  si es limitado a un tamaño, acaba en algún punto previo.
Añadidmos el elemento que resta: 01234+x (x en este caso solo puede ser 5).
ABCDEF.

Cada línea, si lo miras bien es un bucle, porque solo estamos cogiendo el primer item del grupo que se genera en la etapa anterior.
Para que sea efectivo y no limitado a un tamaño fijo o con un alfabeto concreto, lo acertado es usar recursión, así el código es totalmente válido e independiente y además es mucho más sencillo.

A una clase de permutación, deberías añadir siempre como mínimo, la siguiente funcionalidad:

A - Una propiedad (aunque solo sea de lectura), llamada Alfabeto, y que contempla la cadena de caracteres con la que se trabaja.
Código: [Seleccionar]
private p_Alfabeto() as byte ' fíjate que no lo dejo en una cadena de texto, si no como un array de bytes.
public property get Alfabeto as string
   Alfabeto= Strconv(p_alfabeto, VBtounicode)
end property

B - Una propiedad de solo lectura llamada por ejemplo: Tamañoalfabeto/SizeAlfabeto...
Código: [Seleccionar]
private p_Sizealfabeto as byte

public property get SizeAlfabeto as byte
    Sizealfabeto = p_sizealfabeto
end property
C - Una propiedad de solo lectura lllamada por ejemplo: NumPermutaciones, y que como su nombre indica entrega el número de permutaciones sin repetición que ofrece dicho alfabeto.
Código: [Seleccionar]
private p_NumPermutaciones as variant
public property get NumPermutaciones as variant
     Numpermutaciones = p_NumPermutaciones
end property

D -  Una función que precalcule la cantidad de permutaciones sin repetición: En el caso presente, es tan fácil como hacer un bucle:
Código: [Seleccionar]
private sub CalculaNumPermutas
dim x as byte

p_NumPermutas = cdec(p_NumPermutas) ' lo convertimos al tipo Decimal... que maneja números gigantes sin decimales....
p_NumPermutas=1
For x=2 to p_SizeAlfabeto
    p_NumPermutas= (p_NumPermutas*x)
next

' ejemplo: ABCDE= 1*2*3*4*5= 120 permutaciones sin repetición

E - Una comprobación que examine el alfabeto y verifique que no hay caracteres repetidos.
Código: [Seleccionar]
Private funcion ValidarAlfabeto(byref Ab() as byte) as boolean
    dim k as integer
    dim By(0 to 255)
   
    For k= 0 to p_SizeAlfabeto
         if by(Ab(k))>0 then exit function
         by(Ab(k))= 1
    next
    ValidarAlfabeto = true
end function

F - Una función que verifique que si el alfabeto es del mismo tamaño que el actual, no recalcule las permutaciones, que tan solo remplace valores. Esto es, si el alfabeto actual es: XYZ, y luego se recibe permutar el alfabeto ABC (o incluso el mismo en desorden ZYX). Es más rápido remplazar en todas las permutaciones X por A;  Y por B y Z por C, que volver a calcular de nuevo todas las permutaciones. Esto sin embargo es relativo, como te anoto más adelante (no hay necesidad de almacenar todas las permutaciones posibles)...

Tanto A, como B, C, D, E, F se pueden establecer desde la función pública Permutar, justo antes de iniciar las permutaciones.
Código: [Seleccionar]
public function Permutar(byref Alfabeto as string....)
    dim k as long
    dim Ab() as byte

    k = len(alfabeto)
    If (k>0) then
          ab= strconv(Alfabeto, vbfromUnicode)
          if (ValidarAlfabeto(Ab)= false) then
              msgbox "el alfabeto tiene al menos un carácter repetido. Todas sus caracteres deben ser únicos."
              exit function
          end if

          'if (k= p_Sizealfabeto) then
          '      call RemplazarPermutaciones(Alfabeto)
          'else
           p_Alfabeto=ab
           p_SizeAlfabeto = k
                call CalcularNumPermutas
                call PermutarAlfabeto
          'end if
    end if
end function
Otros consejos en el sigiuente apartado...

Inténtalo, a ver si te sale, si pasado unos días sigue sin salirte, coloca el código y te comento/corrijo...
-----------

Respecto de tu código actual, de un vistazo simple resulta muy ineficiente.
De entrada, usar una colección vale si la cantidad de permutaciones es muy limitada. Si no, no interesa almacenar las permutaciones (por ejemplo todas las permutaciones posibles para un alfabeto de 26 caracteres, con palabras de 5 letras tendría: 26^5 permutaciones distintas = 11.881.376, que  (12 millones) no son muchas aún, pero si aumentamos las palabras a 8 caracteres por ejemplo, ya se nos va a : 208.827.064.576  (209mil millones), que ya es intolerable, porque además debes multiplicarlo por los bytes que ocupa cada permutación: es decir por 16, si se guardan en unicode (8 caracteres por permutación, por 2 bytes por carácter).

Entonces qué?.
No las guardes, es preferible calcularlas sobre la marcha. Ejemplo:
Código: [Seleccionar]
public enum EstadosDePermutar
   ESTADO_PERMUTA_FINAL =-1  ' se llegó a la última secuencia.
   ESTADO_PERMUTA_INACTIVO = 0 ' no se ha recibido un alfabeto correcto o está presente, pero no se ha reclamado permutar.
   ESTADO_PERMUTA_SIGUIENTE=1 ' se reclama calcular la siguiente secuencia.
   ESTADO_PERMUTA_CALCULAR_SECUENCIA =2 ' se reclama calcular la siguiente secuencia que sigue a la recibida.
   ESTADO_PERMUTA_INICIO =3  ' se ha reclamado regresar a la primera secuencia (reset).
end enum

private p_Estado as estadosdePermutar
private p_Secuencia as string '  () as byte

public function Permutar(byref Alfabeto as string, optional [b]byref [/b]Estado as EstadosDePermutar) as string
    static n as variant
    dim p as variant

     Select case Estado
           case EstadosDePermutar.SIGUIENTE
               ' calcular la siguiente secuencia tras p_Secuencia.
               Permutar= CalcularSiguiente
               n= (n +1)
               if (n= pNumPermutas) then p_Estado = FINAL                   
           case  EstadosDePermutar.FINAL
                msgbox "Ya se alcanzó el final de las secuencias, reinicie las secuencias o cambie el alfabeto"
           case EstadosDePermutar.CALCULAR_SECUENCIA
                p = OrdenDeSecuencia(Alfabeto) ' si algún error devovler -1
                if (p >=0) then
                    p_Secuencia =Alfabeto
                    Permutar= Permutar("", SIGUIENTE) ' se reinvoca a sí misma
                    n=(p+1)
                else
                      raiseerror "La secuencia recibida no pertenece a este alfabeto" ' o msgbox...
                      exit function
                end if
           case else
               if (IniciarAlfabeto(Alfabeto)= True) then ' calcularía la primera secuencia
                   p_Estado= SIGUIENTE                   
               else
                  ' error con el alfabeto, quizás no fue validado, o su longitud era 0 (una cadena vacía9.
                   p_Estado= INACTIVO
               end if
               n=0
    end select

    Estado = p_Estado
end function
El código está escrito sobre la marcha, así que necesita corrección y claridad...

Por la misma razón, una función de 'Existe' es más que innecesaria, inaceptable... de entrada porque no interesa almacenar las secuencias, luego porque puesto a almacenarlas, si la cantidad es discreta, es preferible usar una tabla hash, para localizarla y no tener que recorrer toda la colección para ver si existe. Más aún, ni siquiera es necesario una tabla hash, para saber si una secuencia dada 'existe' en ese alfabeto, basta verificar que todas las letras de dicha secuencia existen en el alfabeto y que ninguna se repite dos o más veces... si se cumplen esas dos condiciones existe... y por tanto es inecesario buscarla. Y por lo mismo, si insistes en ponerla deberías cambiarle el nombre a la función a: Contiene
Código: [Seleccionar]
Private p_Alfabeto()       As Byte
Private p_SizeAlfabeto      As Byte

Public Function Contiene(ByRef Secuencia As String) As Boolean
    Dim k As Integer
    Dim by() As Integer, Sec() As Byte

    If (Len(Secuencia) = p_SizeAlfabeto) Then
        ReDim by(0 To 255)
        Sec = StrConv(Secuencia, vbFromUnicode)
         
        ' Asignar la secuencia a una tabla de cuenta.
        For k = 0 To p_SizeAlfabeto - 1
            by(Sec(k)) = by(Sec(k)) + 1
        Next
        '  verificar que no hay 2 letras repetidas
        For k = 0 To 255
            If by(k) > 1 Then Exit Function ' si tiene más de 1, implica que está repetido, se concluye que dicha secuencia no está contenida.
        Next
         
        ' invertir la tabla de cuenta, ahora descontamos.
        For k = 0 To p_SizeAlfabeto - 1
            by(p_Alfabeto(k)) = by(p_Alfabeto(k)) - 1
        Next
        ' verificar que todas las letras forman parte del alfabeto
        For k = 0 To 255
            If by(k) <> 0 Then Exit Function ' Si no quedó a 0, implica que un carácter en alfabeto no se encontró en la secuencia.
        Next
         
        ' si todas las letras de alfabeto actual, pusieron a 0 las de la tabla de cuenta, implica que cad a letra en el alfabeto se corresponde una a una con las de la secuencia. Está contenida...
        Contiene = True
    End If
End Function

' Probando la función previa....
Private Sub Form_Load()
    p_Alfabeto = StrConv("ABCD", vbFromUnicode)
    p_SizeAlfabeto = 4
       
    MsgBox Contiene("CDBAZ") ' false ' tiene más letras que lo que señala el alfabeto
    MsgBox Contiene("CD")    ' false tiene menos letras que lo que señala el alfabeto (si se exige tamaño de palabra=al alfabeto).
    MsgBox Contiene("CDDA")  ' false hay un carácter repetido, no están todos.
    MsgBox Contiene("XDBA")  ' false hay un carácter no presente en el alfabeto.
    MsgBox Contiene("CDBA")  ' true OK: aparecen todos una sola vez y ningún caracter más.
End Sub
Este código es enormemente más eficaz que tu función 'Existe' que reclama recorrer toda una colección para encontrar si existe o no dicha secuencia. En esta función a lo sumo se recorre en un array 256*2 + Sizealfabeto * 2, (poco más que 550 iteraciones de un array , que siempre es más rápido el acceso que a una colección), garantizas si existe o no...  de hecho esas iteraciones ( 256*2 + Sizealfabeto * 2) son las necesaria si existe, si no existe serán menos.
Muy lejos de tener que revisar miles, cientos de miles, millones o miles de millones de secuencias almacenadas en una colección, que además siendo texto, la comparación es mucho más lenta. En esta función se opera con un array de integers y 2 arrays de bytes.

Siempre que trates con cadenas de forma intensiva, es preferible usar bytes (un array), ya que será enormemente más veloz.

Y por último, si aún decides usar cadenas (para uso no muy intensivo de cadenas), recuerda que Mid$, no sólo devuelve una subcadena, también existe una función del mismo nombre ara asignar una subcadena dentro de otra; ejemplo:
Código: [Seleccionar]
    Dim dia1 As String, dia2 As String

    dia1 = "Miercoles"
    dia2 = "Domingo"

    Mid$(dia2, 3, 5) = Mid$(dia1, 5, 5)

    MsgBox dia2

' ojo: si en dia2 el punto de inserción + cantidad a pegar spera el tamaño se corta el pegado allí donde acaba. Ejemplo:
    dia1 = "Miercoles"
    dia2 = "Domingo"

    Mid$(dia2, 5, 5) = Mid$(dia1, 4, 6)  ' no cabe "rcoles" a partir de "go" (de "dominGO"), luego solo se insrtan los caracteres que caben  esto es 2, y el resultado será: domi+rco

    MsgBox dia2
No está documentada esta funcionalidad, así no es extraño que la gente no la use porque lo desconoce...
Es más rápido que crear nuevas variables temporales para reasginar valores que luego se vuelven a reasignar... además ahorra declarar variables.


15
A ver... si lo que necesitas es instanciar controles sin registrarlos en el equipo huésped, puedes hacerlo sin registrarlos. A cambio deben ir en el código fuente en TU proyecto... no en otro proyecto, porque eso fuerza a compilarlo como OCX.
Así, los controles se compilan JUNTO A la aplicación y no de forma independiente.

La página de VBForum, creo que desapareció hace ya algunos meses... no puedo ver a qué te refieres exactamente.

Páginas: [1] 2 3 4