• Viernes 19 de Abril de 2024, 16:52

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 5 ... 29
51
Si alguien no se ha acabado de enterar muy bien de las propiedades puede abrir el grupo de proyectos ir al código que escribimos seleccionar la palabra property 1 pulsar la tecla F1 que nos lleva a la ayuda, naturalmente se explicará bien incluso mejor que yo el significado y declaración de la propiedad aunque todo el intríngulis de las propiedades no aparece... pero entre la ayuda y mis indicaciones creo que todo el mundo podría saciar sus dudas.

En el apartado de ayer se explicó gran parte de las propiedades y también se explicó la persistencia (preservación) de los valores de las propiedades. Hoy avanzaremos con más propiedades de nuestro control y se indicarán más detalles acerca de las propiedades a medida que surja cada caso.

Quedamos en que íbamos a requerir determinadas propiedades: ColorTapiz (BackColor), ColorTexto (ForeColor), el propio Texto del botón (Caption o Text), alinear el texto, un Icono,  una Imagen autoajustable al botón... pués hoy procederemos con el código para estas propiedades y de fondo otras característica sobre el Usercontrol...

El código para la propiedad ColorTexto (ForeColor)
Código: Visual Basic
  1.  
  2. Public Property Get ColorTexto() As OLE_COLOR
  3.      ColorTexto = UserControl.ForeColor
  4. End Property
  5.     Public Property Let ColorTexto(ByVal ct As OLE_COLOR)
  6.         If ct <> UserControl.ForeColor Then
  7.             UserControl.ForeColor = ct
  8.             UserControl.PropertyChanged "ColorTexto"
  9.             ' añadidos posteriores
  10.         End If
  11.     End Property
  12.  
  13.  
Vemos que prácticamente podemos copiar el código del Backcolor y hacer manualmente los cambios (de hecho yo lo he hecho así). ColorTexto es lo que nos va a permitir cambiar el color al texto que se escribe en el botón, de momento no hemos realizado la propiedad texto, por lo que aparece también la línea comentada 'añadidos posteriores. Lo dicho ayer sobre Usercontrol.BackColor  es aplicable también sobre Usercontrol.ForeColor, es una propiedad también sobre la que delegamos ya que la 'plantilla' que se nos presenta del contrl la trae, estas propiedades sobre las que podemos delegar pueden verse sobre la ventana depropiedades de la ventana de la interfaz del control. Igualmente si por defecto deseamos que la aplicación cliente tenga nada más cargar una instancia en un formulario un color determinado es en esa ventana donde debemos designarlo. Yo lo dejo en negro.

Debe quedar claro desde ya que todas las propiedades que vayamos a añadir y que el control posee delegaremos sobre ellas, salvo  que la funcionalidad sea totalmente distinta a la que realiza la plantilla... si surge un caso así ya se explicará.

Es conveniente (no obligatorio) que cada vez que añadimos una propiedad hagamos los propio para su persistencia, añadiendo las entradas correspondientes en los métodos Readproperties y Writeproperties... Yo copio una entrada anterior, pego y luego la modifico... entonces ya tendremos esto:
Código: Visual Basic
  1.  
  2. Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  3.     With PropBag
  4.         UserControl.BackColor = .ReadProperty("ColorTapiz", Ambient.BackColor)
  5.         UserControl.ForeColor = .ReadProperty("ColorTexto", Ambient.ForeColor)
  6.        
  7.     End With
  8. End Sub
  9.  
  10. Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
  11.     With PropBag
  12.         .WriteProperty "ColorTapiz", UserControl.BackColor, Ambient.BackColor
  13.         .WriteProperty "ColorTexto", UserControl.ForeColor, Ambient.ForeColor
  14.        
  15.     End With
  16. End Sub
  17.  
  18.  
Es decir ayer pusimos la del color tapiz ahora metemos la del color texto.... en lo sucesivo sólo pondré la línea concreta como recordatorio, ya vosotros sabeis donde debe añadirse (a continuación de la anterior y dejamos una nueva línea para la siguiente entrada... bueno esto al gusto).

Ahora vamos con la siguiente propiedad; Texto. Vemos que el control no tienen una propiedad Text ni Caption, esto significa que no podemos delegar en ella sino que la tenemos que contruir completamente. Al hacerlo se entenderá fácilmente su lógica y se explicará como se le cede su primer valor.
Código: Visual Basic
  1.  
  2. ' esta línea de código debe ir arriba del todo, por encima de cualquier declaración de propiedades y funciones...
  3. Private p_Texto As String   ' el texto del botón se almacena en esta variable internamente.
  4.  
  5. ' esta línea podemos ponerla a continuación (debajo de) la propiedad ColorTexto.
  6. Public Property Get Texto() As String
  7.     Texto = p_Texto
  8. End Property
  9.     Public Property Let Texto(ByVal t As String)
  10.         If t <> p_Texto Then
  11.             p_Texto = t
  12.             PropertyChanged "Texto"
  13.             ' añadidos posteriores
  14.         End If
  15.     End Property
  16.  
  17.  
Como se puede ver, el valor de la propiedad realmente la almacenamos en una variable (p_Texto) declarada privada, por tanto  no es accesible desde fuera y debe verse como lógicamente la hemos declarado de tipo string. Surge una pregunta lógica de parte del aprendiz, porqué no guardamos directamente la propiedad sobre la variable p_Texto ?. De hecho podríamos hacerlo, pero entonces si tenemos algo como esto:
Código: Visual Basic
  1.  
  2. public TextoBoton as string
  3.  
  4.  
...Es realmente una propiedad con todas las de la ley, pero presenta unos inconvenientes para determinadas situaciones: 1º Si utilizamos una propiedad así, no hay forma de saber cuando el cliente ha cambiado su valor, por tanto tampoco sabemos cuando debe actualizarse lo que deba actualizarse.
2º Si necesitamos garantizar que el valor que introduce el cliente (el cliente en este caso es el programador que utiliza el control compilado) cumpla ciertos requisitos no tenemos forma de hacerlo porque como se indicó antes no sabemos cuando se introduce un nuevo valor.

Al expresarse las propiedades en forma de 2 funciones, una que entrega el valor y otra que lo recibe, la que lo recibe cuenta con 2 notificaciones, a) que se recibe un valor, B) si lo deseamos podemos comprobar si ese valor es distinto del actual, es decir si cambia de valor. Hasta ahora si os fijais en el código de las 3 propiedades que llevamos hasta el momento, en los 3 casos hemos verificado si el valor que se introduce es distinto del actual, ya se explicó ayer porque hacemos esa comprobación, no siempre la haremos como severá más adelante, básicamente cada vez que una comprobación se amás engorrosa o conlleve más tiempo que hacer las operaciones que un cambio supone.

Hemos creado la propiedad texto, pero sabemos que cuando se declara una variable antes de usarse su valor es el que VB asigna por defecto, en el caso de los números (byte, long,etc...) siempre valen 0 y en el caso de los tipo string valen "" es decir una cadena vacía. Naturalmente nosotros podemos querer que ya de entrada cuando se cree una instancia sobre el formulario del cliente éste texto (y en general casi todaslas propiedades), tenga ya un valor concreto y determinado por nuestro interés, etc... bien esto se llama inicialización de variables y nos interesa que sólo ocurra una vez, justo cuando se ha creado la instancia, luego ya sabemos que writepoprties guardará el valor  y que readproperties lo recuperará, además si el cliente cambia el valor entonces el que se guardará y luego se leerá será ese valor y no el que nosotros inicialmente le dimos, para que este funcionamiento sea así, por tanto este valor debe ejecutarse una sola vez, justodurante la creación por primera vez de la instancia. es preciso saber que el evento initialice ciertamente crea la instancia, sin embargo cuando se pasa al modo ejecución se destruye y es vuelta a crear es decir  se  vuelve a ejecutar initialize, parece pués un buen sitio para colocar ese código, pero claro si  se carga y descarga 10 veces el formulario, también 10 veces se ejecuta initialize y por tanto 10 veces le estamos asignando nuestro valor 'de capricho' siendo que luego 10 veces también se ejecutará el readproperties... no sería más útil que sólo se ejecutara 1 única vez ?.... pués esto es precisamente lo que hace un procedimiento del usercontrol.... ponemos el código (puede encontrarse el método en la lista de procediemientos de eventos cuando en la lista de la izquierda tenemos seleccionado el usercontrol, si tenemos seleccionado general, aparecerán las propiedades y funciones que vayamos creando ):

Por tanto en la lista izquierda seleccionamos usercontrol y en la lista derecha desplegamos hasta encontrar 'InitProperties'
Código: Visual Basic
  1.  
  2. Private Sub UserControl_InitProperties()
  3.     p_Texto = UserControl.Extender.Name
  4. End Sub
  5.  
  6.  
En este código hemos asignado el valor que tomará justo cuando el cliente inserta una instancia del control, sólo en esa ocasión ocurre el evento initproperties, por tanto en efecto se ejecutauna sola vez, aunque siempre sucede (cuando sucede) justo después del evento initialize (que de momento no lo tenemos presente, porque de momento no le hemos asignado código).
Hay nuevamente que recordar que hemos añadido una línea comentada, que está destinada a poner algó de código más adelante, de momento podemos cambiar el valor del texto, pero en nuestro botón no aparece el texto, esa línea comentada es justo donde le indicaremos cuando dónde y cómo dibujarse, pero esto loharemos cuando tengamos más elementos de juicio para dibujarlo, concretamente cuando decidamos como funcionará el alineamiento, ya que pensamos también incluir un icono, es lógico que el texto no quede cubierto por dicho icono... justo cuando describamos esas 2 propiedades pasaremos a dibujar el texto, porque ya tendremos definido todos los elementos que afectan al texto.

Ahora comentamos la línea de código: p_Texto = UserControl.Extender.Name
Podríamos haber puesto p_Texto = "Viva Yo y mi botón", y eso sería lo que siempre saldría cuando un cliente pusiera una nueva instancia del control sobre un formulario. Sin embargo lo lógico (y que estamos acostumbrado) es que cuando creamos un boton de microsoft , éste se llama Command1 y si ponemos otro este se llama Command2 y el nombre es precisamente el texto que contiene el botón. Esto es coherente y en esa coherencia nos movemos. Entonces que significa la parte derecha de la igualdad de p_Texto ?. Bien digamos que mientras se crea el control, VB crea y mantiene unas propiedades siempre vinculadas a cada control, esas propiedades están almacenadas en un objeto llamado VbControlExtender y de la que el usercontrol mantiene una instancia a través de la propiedad extender. Para curiosos decir que estas propiedades son aquellas que son propias e intrínsecas del control PERO DE las que el contenedor, realiza un seguimiento.

Ayer hablamos de otro objeto que es una propiedad del usercontrol Ambient. Conviene no confundir uno con otro. Extender, Por ejemplo además del nombre del control, mantiene la propiedad de posición  Left, Top y de tamaño Width y Height... si quereis saber con exactitud cuantas y cuales son las propiedades alojadas en el objeto extender, ir al formulario, seleccionad el control en el formulario y mirad las propiedades que tiene el control en la ventana de propiedades, si está en modo ejecución, pués son todas excepto las que nostros hemos creado hasta el momento, y si el control está en modo diseño (rayado) todas esas propiedades nosotros no las hemos creado, es el propio VB quien se encarga de crearlas para cada control y son aquellas que los contenedores deben tener acceso...  al contenedor no le importa ni necesita saber si yo tengo una propiedad llamada Icono ó Realte ó AlineaciónTexto... pero si necesita saber la posición del control, para saber si está parcialmente tapado o no, igual que la propiedad visible, etc... Hay también que decir que algunas de estas propiedades son de sólo lectura...
Podemos por tanto decir que un control se compone de 4 tipos de propiedades:
1 - Las que trae la propia plantilla del usercontrol (BackColor, Forecolor, Font, Picture, etc...) estas podemos usarlas o no, son opcionales no estamos obligados a usarlas si no las necesitamos.
2 - Las que se proveen a través de la propiedad Extender (del objeto VBControlExtender del que el usercontrol tiene una instancia accesible a través de la propiedad Extender) estas son obligadas y por tanto las provee el propio VB, como ya dije, Left, Top TooltipText, Name, Tag... ).
3 - Las que provee el contenedor y que tenemos acceso a ellas a través de la propiedad Ambient (del objeto AmbientProperties, como ), estas son todas de sólo lectura para el control.
4 - Y finalmente las que nosotros implementamos, ColorTapiz, ColorTexto, Texto, AlineacionTexto, Icono...

Tanto extender como Ambient no sólo proveen propiedades sino también funciones y eventos.

Finalmente, como hemos hecho con las otras propiedades, nos aseguramos de su  persistencia en el tiempo:
Código: Visual Basic
  1.  
  2. ' en el evento readproperties
  3. p_Texto = .ReadProperty("Texto", UserControl.Extender.Name)
  4.  
  5. ' en el evento writeproperties
  6. .WriteProperty "Texto",p_Texto, UserControl.Extender.Name
  7.  
  8.  
En lo sucesivo  ya no se comentará donde irá cada línea de persistencia de la propiedad... nos debe quedar claro donde corresponde cada una. Si pondré cada línea para que no se nos olvide...

Ahora deberíamos avanzar con una propiedad relacionada directamente con el texto AlineacionTexto:
Código: Visual Basic
  1.  
  2. ' declaramos la variable que contendrá el valor.
  3. Private p_Alineacion As TiposDeAlineacion  'AlignmentConstants  ' Guarda el valor de alineación del texto.
  4.  
  5. ' Creamos una enumeración para los valores posibles. Este código debe ir arriba del todo, incluso por encima de la declaración de variables.
  6. Public Enum TiposDeAlineacion
  7.     ALINEACION_IZQUIERDA = 0
  8.     ALINEACION_CENTRADA = 1
  9.     ALINEACION_DERECHA = 2
  10. End Enum
  11.  
  12. '  la declaración de la propiedad, la pondremos debajo de la última declaración de propiedad que pusimos
  13. Public Property Get AlineacionTexto() As TiposDeAlineacion
  14.     AlineacionTexto = p_Alineacion
  15. End Property
  16.     Public Property Let AlineacionTexto(ByVal at As TiposDeAlineacion)
  17.         If at <> p_Alineacion Then
  18.             p_Alineacion = at
  19.             PropertyChanged "AlineacionTexto"
  20.             ' añadidos posteriores
  21.         End If
  22.     End Property
  23.  
  24. ' el establcecimiento inicial de la propiedad dentro del evento initproperties, que ahora va quedando así...
  25. Private Sub UserControl_InitProperties()
  26.     p_Texto = UserControl.Extender.Name
  27.     p_Alineacion = ALINEACION_IZQUIERDA
  28.    
  29. End Sub
  30.  
  31. ' y finalmente el código de persistencia, cada línea donde corresponde ya debeis saber cual en cual...
  32.         p_Alineacion = .ReadProperty("AlineacionTexto", TiposDeAlineacion.ALINEACION_IZQUIERDA)
  33.         .WriteProperty "AlineacionTexto", p_Alineacion, TiposDeAlineacion.ALINEACION_IZQUIERDA
  34.  
  35.  
Ahora comentamos el código... Vemos que esta propiedad tampoc  delega el en objeto usercontrol, por lo que hemos declarado una variable para contener su valor  (yo a las variables de apoyo a la propiedades siempre les doy un nombre como p_nombrepropiedad , aunque no suelo poner el nombre de la propiedad completa, aldecidir un nombre de propiedad debe pensarse que debe resultar intuitivo al cliente su significado, por lo que no demos escatimar letras, si pusieramos alineación, el cliente podría tener dudas si se refiere al icono, o al control, pero con alineacionTexto, no da lugar a confusión, como internamente el cleinte no tiene acceso y sólo tengo una propiedad que tenga alineación, en la variable privada no me complico, un sencillo comentario al final de cada declaración, nos puede ayudar a recordar para qué se usa.

Se puede ver que hemos creado una enumeración para los 3 valores de la alineación, realmente vb, tiene una enumeración equivalente llamada AlignmentConstants, pero henmos desistido de usarla por 3 razones:
1º Nos sirve de excusa para aprender a usar enumeraciones como tipo de datos para cuando necesitemos variables.
2º La enumeración de windows no es correlativa de derecha a izquierda, nosotros tenemos izquierda, centro, derecha, con valores 0,1 y 2. Vb usa izquierda, derecha y centro que al menos a mi me parece  menos coherente.
3º Mantenemos en mente que estamos creando nuestro control en español (que se jodan los estadounidenses  :devil:  :devil:  :devil: así les damos algo de su propia medicina ... es broma).

En vez de una enumeración realmente para la declaración de la variable podríamos haber usado un tipo de datos byte, pero si usamos la enumeración mientras escribamos código el intellisense, nos ayudará sugiriéndono cual delos valores usar, con ello adelantamos al escribir y tampoco nos obliga a memorizar, esto limita en algo un posible error por ese problema de no haber recordado bien el valor... De modo consecuente, también se ha optado por usar el tipo de datos enumeración para la propiedad, porque así en la ventana de propiedades cuando el cliente decida cambiar el valor se despliega una lista precisamente exponiendo los nombres que les hemos dado a nuestras constantes de alineación.

Respecto de la alineación, nosotros sólo realizaremos una alineación horizontal, queda como ejercicio para el interesado cambiarlo por una alineación también vertical. A este respecto VB tiene otra enumeración AlignConstant, que usa valores semejantes a los anteriores pero que además añade top y bottom.

El código de la propiedad no está realmente bien terminado, si el lector es avispado hace rato que debería estar rondándole en la cabeza lo que vamos a describir a continuación...
Puesto que la alineación sólo tiene 3 posibilidades, que le impide al cliente introducir un valor de por ejemplo 25 ?. Realmente si así lo hiciera ahoraese valor sería introducido y si nuestro cálculo de reposicionamiento del texto estuviera ya listo, nos arrojaría un error, nos falta por tanto un 'hervor' en el código de la asignación de la propiedad.
Ese hervor es controlar que valor se introduce, y al efecto sólo debemos permitir que se introduzca uno de los 3 valoresposibles. Hay 2 formas (coherentes) de resolver esto, si el control es para nosotros, (como lo es) lo solucionaremos de una manera 'llana y sencilla' porque conocemos los detalles y sabemos que entenderemos laforma de funcionar que le vamos a dar, ahora bien si el control fuera un encargo de una empresa, lo que deberíamos hacer realmente es marcar un error cuando se introdujera un valor incorrecto, con ello el cleinte sabría que ha introducido un valor noadmitido y se supone que acabaría por 'conocer' bien el control. Pondremos ambos ejemplos de código.

' el código para un encargo de empresa:
Código: Visual Basic
  1.  
  2. Public Property Let AlineacionTexto(ByVal at As TiposDeAlineacion)
  3.         If at <> p_Alineacion Then
  4.            If (at < 0) or (at > 2) Then
  5.                Raise Error(380) ' el error 380 tiene asignado el significado de: Se ha asignado a una propiedad un valor incorrecto
  6.            else
  7.                 p_Alineacion = at
  8.                 PropertyChanged "AlineacionTexto"
  9.                 ' añadidos posteriores
  10.             End If
  11.         End If
  12.     End Property
  13.  
  14.  

El código, más inteligente, para gente más inteligente:
Código: Visual Basic
  1.  
  2. Public Property Let AlineacionTexto(ByVal at As TiposDeAlineacion)
  3.         If at <> p_Alineacion Then
  4.             If at < 0 Then
  5.                 at = 0 'ALINEACION_IZQUIERDA
  6.            ElseIf at > 2 Then
  7.                 at = 2 ' ALINEACION_DERECHA
  8.            end if
  9.  
  10.             p_Alineacion = at
  11.             PropertyChanged "AlineacionTexto"
  12.             ' añadidos posteriores
  13.        End If
  14.     End Property
  15.  
  16.  

En este caso hemos optado por no señalar un error, sino que cualquier valor por encima de 2 lo hacemos igual a 2 y cualquier valor menor que 0 lo hacemos = a 0. Cyuando el cliente está en modo de diseño y escribe una propiedad, se pasa el valor al procedimiento de propiedad, lapropiedad actúa, como no marcamos error, el valor queda correctamente almacenado en la variable p_Alineacion,pero partimos de que el cliente introdujo por ejemplo un valor de 37, entonces qué ocurre ?. a continuación (estando en diseño como hemos dicho),  el entorno de vb una vez termina el procedimiento let realiza una llamada (de forma transparente) al procedimiento get, para actualizar el valor en la ventana de propiedades, con lo que en efecto al leer el valor de p_Alineacion, le entregará el valor 2 que sustituirá al 37 que introdujo el cliente.

Todavía podría decir que a la propiedad alineacionTexto le falta un hervor más, pero en este caso no se aplica del todo, así que lo dejamos para más adelante cuando una propiedad lo justifique y si vamos terminando el control y no ha sucedido pués aprovechando esta propiedad locomentaríamos y dejaríamos puerta libre para que qien qiera lo aplicara o no.

Sobre la propiedad alineación sólo nos resta decir que al igual que las propiedades anteriores hemosdejado un comentario como recordatorio de que ahí va algo de código, que mañana cuando por fin pongamos el código para los gráficos se añada el código faltante en estas propiedades.

Ahora vamos a añadir una propiedad Font, para que nuestro cliente pueda decidir que tipo de letra se pone al texto del botón, este es el sitio adecuado para introducirlo (la posición).
Código: Visual Basic
  1.  
  2. ' el código de la propiedad fuente (Font)
  3. Public Property Get Fuente() As IFontDisp
  4.     Set Fuente = UserControl.Font
  5. End Property
  6.     Public Property Set Fuente(ByRef f As IFontDisp)
  7.         Set UserControl.Font = f
  8.          PropertyChanged "Fuente"
  9.         ' añadidos posteriores
  10.     End Property
  11.  
  12.  
  13.  
  14.  
Comentamos el código para esta propiedad. Esta propiedad es una propiedad de ambiente, por lo que también el usercontrol la contiene, por tanto delegamos en ella para contenerla. Ayer hablamos de que había 3 procedmientos de propiedad y que uno de ellos era para cuando el tipo de datos era un objeto. Este es el caso presente, Font es un objeto, por tanto no puede usarse 'property let' sino que deb usarse 'property Set', véase igualmente como la asignación de objeto utiliza Set para almacenarlo en la variable, el procedmiento Get, igualmente debe usarse un set y el cliente necesariamente deberá alamcenar este objeto en una variable que él designe como objeto sino obtendrá un error.
Luego hemos usado la interfaz Ifontdisp, del mismo modo y razón por la que usamos OLE_COLOR para las propiedades de color, ya que así VB presenta el cuadro de diálogo para que el cliente elija la fuente deseada así como sus propiedades (size, Bold, etc...)
Podríamos dividir la asignación de fuente en cada una delas propiedades del objeto, por ejemplo FontSize por un lado y fontName por otro, FontBold,etc... esto sólo interesa si por ejemplo queremos limitar al usuario de una de dichas características, aunque también en lapropiedad Fuente que hemos declarado, podríamos incluir código para hacer lo mismo, es cuestión de gustos, yo prefiero poner una sola propiedad fuente  en vez de varias, que llenen la ventana de propiedades... Finalmente hemos elegido pasar el dato por referencia y no por valor, aunque realmente VB hace una copia de la fuente, ya que si no un cambio originaría un cambio de donde procede, es decir el contenedor.

Ahora como ya habeis aprendido, a asignar un valor por defecto para la propiedad y también darle persistencia:
Código: Visual Basic
  1.  
  2. Private Sub UserControl_InitProperties()
  3.     p_Texto = UserControl.Extender.Name
  4.     p_Alineacion = ALINEACION_IZQUIERDA
  5.     Set UserControl.Font = Ambient.Font         ' no es estrictamente necesario, ya que esto sucede automáticamente
  6.    
  7. End Sub
  8.  
  9. ' persistencia:
  10.         Set UserControl.Font = .ReadProperty("Fuente", UserControl.Ambient.Font)
  11.         .WriteProperty "Fuente", UserControl.Font, UserControl.Ambient.Font
  12.  
  13.  


 A continuación, crearemos una propiedad icono y damos por terminado esta parte de hoy.
 
Código: Visual Basic
  1.  
  2. ' en la sección de declaración de variables....
  3. Private p_Icono As IPictureDisp ' icono que se presenta alineado enla izquierda
  4.  
  5. ' debajo de todas las propiedades hasta el momento....
  6. Public Property Get Icono() As IPictureDisp
  7.     Set Icono = p_Icono
  8. End Property
  9.     Public Property Set Icono(ByRef i As IPictureDisp)
  10.         Set p_Icono = i
  11.         PropertyChanged "Icono"
  12.         ' añadidos posteriores
  13.     End Property
  14.  
  15. ' persistencia.
  16.         Set p_Icono = .ReadProperty("Icono", Nothing)
  17.         .WriteProperty "Icono", p_Icono, Nothing
  18.  
  19.  
Esta propiedad es fácil y rápido de comentar... al como pasó para el color y la fuente usamos un tipo de datos que nos mostrará una ventana de propiedades como cuadro de diálogo para localizar y elegir la imagen deseada que se usará como icono. Hay que señalar que por defecto el icono es... ninguno, es decir si el cliente no elige un icono, no dibujamos nada. Por ello en el evento initproperties no le asignamos nada, ya es nothing...

Ahora guardar todo y podeis probar los añadidos realizados, claro que al ejecutar de momento sólo nos resulta tangible el colorTapiz ya que de momento no hacemos nada gráfico...

Mañana nos centramos en graficar todo lo que tenemos hasta ahora y que se pueda plasmar en el control. Veremos que alinear el texto tiene consecuencias según exista o no un icono, así mismo decidiremos un margen entre el control y el icono, ya que todavía nos falta una propiedad que realice un relieve sobre el contorno del control...

52
Visual Basic para principiantes / Re: Como alinear el texto de un ListBox?
« en: Lunes 6 de Septiembre de 2010, 05:26 »
Bueno trabajando sobre el control listbox esa es la solución, poco efectiva.

Precisamente las limitaciones de algunos controles son los que te impulsan a diseñar tus propios controles. Diseñando tu propio listbox se podría hacer de modo mucho más eficiente. El control listbox de Microsoft es muy ineficiente, si tienes una fichero de texto pongamos de 20Mb. lo estás recorriendo para buscar determinadas entradas que vas añadiendo al listbox, y pongamos que acabarás añadiento 10.000 elementos será una operación excesivamente lenta, porque microsoft se empeña en crear en la lista los 10.000 elementos.

Podría diseñarse un control que tuviera un cuadro de lista con una propiedad VisibleItems que indicara cuantos ítems quiere verse en la lista (desde luego limitado como máximo a los que quepan en la vertical de la pantalla o mas sencillo al tamaño de un byte (255), luego con apoyo de una clase, sería esta quien tendría una estructura que contuviera el texto de la lista y el ancho que ocupa el texto. Al presentar o hacer scroll en la lista sólo dibujaríamos los que caben en la lista aunque nuestra lista constara de 10.000 items, presentar, o actualizar los que caben (en la lista, a la vista) nunca llevaría más de 1 décima de segundo...

Cuando acabemos con el control del botón si quieres hacemos uno de tipo listbox con estas ideas en mente.

53
Bueno, vamos por la siguiente parte.

Ya hemos creado los archivos necesarios del proyecto, por tanto ahora abrimos el entorno desde el archivo Group1.vbg que como señalé es el que mantiene unido ambos proyectos el del control y el de prueba.

Este tramo inicial podía haberla añadido al final de la parte de ayer , pero bueno....
 
Hay que señalar que cuando hay un grupo de proyectos, sólo uno es el 'proyecto inicial', el que se va a ejecutar cuando se arranque el proyecto para su ejecución, en este caso el proyecto inicial es el de prueba ya que el del control actúa como secundario dentro del proyecto de prueba... justo cuando se inicializa el formulario (cuando se carga los controles ya deben haberse cargado, de hecho se carga justo cuando el último control constituyende del formulario se ha cargado) se invoca la carga de todos y cada uno de los controles que lo integran. Para hacer la prueba vayamos al código del formulario y escojamos el procedimiento de evento del formulario initialize, este sería su código :
Código: Visual Basic
  1.  
  2. Private Sub Form_Initialize()
  3.     MsgBox "Formulario inicializando"
  4. End Sub
  5.  
  6.  
Acto seguido vamos a la ventana de código del control, también en su procedimiento de evento initialize.... este sería su código:
Código: Visual Basic
  1.  
  2. Private Sub UserControl_Initialize()
  3.     MsgBox "Control inicializando"
  4. End Sub
  5.  
  6.  

Para verificar lo que se ha dicho finalmente exponemos código en el load del formulario:
Código: Visual Basic
  1.  
  2. Private Sub Form_Load()
  3.     MsgBox "formulario inicializado  y cargando..."
  4. End Sub
  5.  
  6.  

Ahora ejecutamos paso a paso el grupo de proyectos (tecla F8).. veremos que vamos al procedimiento initialize del formulario, luego al initialize del control y finalmente al load del formulario.

Para el diseño del control esto no tiene mucha importancia, pero es precisamente lo que nos ayudará a entender la cascadade sucesos de arranque del control. Si se piensa bien el evento initialize del formulario ocurre una sola vez, en cambio el evento load del formulario puede ocurrir varias veces durante la vida del mismo, esto mismo sucede con el control, aunque más adelante se detallará esta cuestión. Ahora lo que nos importa es saber si el proyecto de inicio fue exitosamente el de prueba. si fue el del control debemos ir al 'explorador de proyectos' (CTRL + R)  y fijarnos cualo de los dos proyectos aparece en negrita, eso marca el proyecto inicial, si es necesario, por tanto pulsamos click sobre el proyecto de prueba y sobre el menú emergente pulsamos en 'establecer como inicial'.

Ya borramos todo el código introducido anteriormente y guardamos el proyecto. Ahora empezamos realmente esta 2ª parte.
____________________________________-
Cuando vamos a crear un control, previamente es conveniente hacer una descripción sobre un papel de que funcionalidad es la que esperamos que tenga, evidentemente siempre en medio del proyecto podremos hacer añadidos y de hecho los haremos a propósito para ver como afecta los añadidos a última hora. Sin embargo cuanto mejor tengamos explicitado  lo que queremos que haga en mejores condiciones estaremos para proveer lo que precisa...

Vamos pués a proceder a dar una somera descripción de lo que pretendemos crear... es habitual que la razón por la que queramos construir un control es que determinado existente no tenga tal o cual característica/s por lo que nuestro modelo podría ser una copia en cierto modo similar a otro ya existente pero con algunos cambios.... por ejemplo, a mi nunca me gustó que los botones de microsoft no tuvieran una propiedad 'forecolor', por narices siempre es negro (se puede cambiar empleando APIs, pero no hay una propiedad), si queremos cambiar el color del fondo debemos cambiar la propiedad estilo a 'graphical', sólo entonces toma el color que hayamos designado a la propiedad backcolor, ese comportamiento también nos parece 'idiota', otra cuestión es que por ejemplo admite una imagen, pero se pega al tamaño real, también debe estar establecido estilo a graphical (Command1.style=1: Command1.picture= loadpicture(ruta...)) . Para colmo incluso creando una imagen justo a la medida del botón, si es oscurapor abajo nos 'tapa' el texto del botón... en fin como puede sentirse, hay razones que ya justifican nuestro botón y ya de entrada tenemos unas descripciones de lo que tiene que ser...

El control debe poder cambiar el color del fondo, el color del texto, alinear el texto horizontalmente, admitir una imagen ajustada en todo momento al fondo, tener capacidad para un icono alineado siempre a la izquierda y poseer un borde perimetral que de momento no definimos como se comportará (podría ser fijo o que se hunda al pulsar y se eleve al soltar), debe tener algunas propiedades típicas, activo (enabled), font, etc...

Es una descripción pequeña, pero para empezar a contruirlo nos vale, luego a medida que vayamos diseñando y probando terminaremos de definir tal vez nuevas propiedades o cambios de funcionalidad... esto debe entenderse como algo lógico y razonable, tampoco es estrictamente necesario tener una descripción exhaustiva del mismo, siendo como es para nosotros... A medida que uno se familiariza creando controles bastantes ideas de la descripción están ya en la cabeza y no necesitamos tener que plasmarlas por escrito, en cambio si conviene dejar escrito esas funcionalidades específicas que pretendíamos para el control ya que si no, cabe la posibilidad de que tras algún tiempo sin retomar el proyecto se nos haya olvidado por completo la misma, la funcionalidad que lo haría diferente de otros modelos previos que ya hayamos realizado, por ejemplo puede que este nuevo botón se deba a que queramos unir varios botones en línea y columna formando una tabla y por ello queramos redefinir la forma en que se dibuja el relieve de los mismos... o podríamos querer en un nuevo botón que tenga una pequeña animación cuando se pasa el ratón por encima, o simplemente añadir un sonido cuando se oprime y suelta elbotón... estas 2 últimas funcionalidades las utilñizaremos como un añadido de última hora cuando se dé al control por terminado...

El mejor sitio para dejar escrito la funcionalidad (las ideas de como debe operar) es usar un archivo de texto en la misma carpeta que el control, así siempre estará disponible.

Por tanto empezaremos definiendo propiedades bastante conocidas: Backcolor, forecolor, enabled, Text... pero a mi particularmente me gusta usar el español que es mi idioma, por tanto todas las propiedades y demás se reflejarán en lo posible en español... hay una razón más o menos poderosa para dejarlo en inglés, que ya para el final se indicará si no me olvido, y si me olvido me lo recordais (me refiero al final de la elaboración del control).

Las propiedades pueden usarse tanto en clases como en formularios y por supuesto en los controles que es donde más lo vemos. Las propiedades son un trío de funciones realmente pero que el entorno de VB lo enmascara como si fueran algo distinto de funciones, de hecho podríamos olvidar las propiedades y tratarlas como funciones pero nos perderíamos ciertas funcionalidades del entorno, como mostrar los valores de las propiedades del control en la 'Ventana de propiedades'.

Las propiedades como digo son un trío, una devuelve un valor y las otras 2 entregan un valor. de estas 2 una se utiliza cuando se usa un tipo de datos genérico y la otra cuando se usa como tipo de datos un objeto.
A continuación iremos poniendo código y explicando...
Código: Visual Basic
  1.  
  2. Public Property Get ColorTapiz() As OLE_COLOR
  3.      ColorTapiz = UserControl.BackColor
  4. End Property
  5.     Public Property Let ColorTapiz(ByVal ct As OLE_COLOR)
  6.         If ct <> UserControl.BackColor Then
  7.             UserControl.BackColor = ct
  8.             UserControl.PropertyChanged "ColorTapiz"
  9.             ' añadidos posteriores
  10.         End If
  11.     End Property
  12.  
  13.  
Acabamos de definir la propiedad ColorTapiz (colorFondo, BackColor) para el control, analicemos cada parte...
GET: es como una función, devuelve un valor, se usaría así en el formulario: dim X as long: x= CtlBoton1.Colortapiz : msgbox x
Public: porque queremos que esta propiedad sea legible, si quisiéramos que no se pudiera leer pondríamos private y sería una propiedad sin derecho a lectura.
LET: es la asignación de la propiedad, puede verse que es como una función tiene un parámetro que es por donde se recibe el valor, a dicho parámetro le hemos lamado, ct (abreviatura de Colortapiz, yo suelo usar esta convención), este parámetro no es visible desde fuera, luego no importa el nombre que se le dé. Let también se declaró public, si lo hubiéramos declarado private la propiedad estaría privada de escritura, es decir sólo podría invocarse para ser leída pero nunca podría escribirse.
Más adelante se mostrará que es posible dar más de un parámetro a las propiedades, sin embargo debe quedar claro que 1º no es obligatorio el par de procedimientos de la propiedad, puede usarse sólo el get y no aparecer el let, o al revés. 2º si aparecen ambos deben ser congruentes en el tipo de datos y en la cantidad de parámetros, veremos que siempre LET tiene un parámetro más que GET, 3º en las propiedades del control (en el formulario) sólo aparece una propiedad si aparecen ambos métodos y también ambos son públicos, si uno de los 2 es privado no aparece en las propiedades del control. (conviene que luego se pruebe a cambiarlos a private uno de ellos y se verá como deja de aparecer).

La propiedad almacena un color que a fin de cuentas es un tipo de datos long, porqué lo hemos declarado del tipo OLE_COLOR ?, porque cuando se declara de esa manera el entorno de VB nos despliega una 'página de propiedades'  para elegir visualmente el color, si utilizamos un tipo de datos long, desde el entorno sólo podríamos introducir valores numéricos desde el teclado. Los controles pueden poseer páginas de propiedades que es casi un pequeño mundo lo mismo que los controles pero que una vez conocidos los controles son más sencillos de conocer, el uso de páginas de propiedades para los controles facilita al programador poder cambiar cómodamente algunas propiedades incluso a varios controles a la vez, la contrapartida es que diseñar una página de propiedades nos lleva más tiempo y hace al control más pesado (el control una vez compilado pesa más)... si al final hay ganas podríamos crear una sencilla página de propiedades.

 Véase que usando una propiedad en vez de 2 funciones, ambos métodos se llaman iguales, usando funciones por necesidad cada uno debería tener un nombre distinto)... Ahora ponemos un ejemplo de como se asigna la propiedad del control en el formulario.... Dim x as long : x= 1234567: CtlBoton1.ColorTapiz = x .Aquí escritura y antes dimos un ejemplo de lectura de la propiedad. Antes de seguir, podemos probar ya esta nueva propiedad, para ello debemos ir al formulario y pulsar en el control, en las propiedades del control veremos que aparece la propiedad ColorTapiz y podemos ver como tiene el color que le asignamos (el tipo Ole_color hace que el entorno nos muestre el color visualmente en vez de un número y podemos cambiar el color y ver como el cambio se refleja en el control...por ejemplo cambíalo a azul... IMPORTANTE: si el control en el formulario aparece 'rayado diagonalmente', tal como se dijo ayer es porque está en modo diseño, para poder probarlo en el formulario es preciso ponerlo en modo ejecución, y para ponerlo en modo ejecución tenemos que cerrar la ventana del control (no la de código si no la de la interfaz del control)... esto no lo voy a repetir más veces, debe quedar claro YA.

Sólo nos queda describir el código introducido en los métodos de la propiedad ColorTapiz... para el get le decimos que colortapiz es igual a un valor que el propio control ya mantiene una variable... (Cada contenedor provee determinada funcionalidad, disponible para los objetos insertados en él y los contenedores del entorno de VB proveen propiedades como Backcolor,y algunas otras que se irán describiendo, al objeto Usercontrol, nuestra instancia. Por tanto la línea 'ColorTapiz = UserControl.BackColor' le está diciendo que  entregue la propiedad almacenada en la variable Backcolor que provee ya el control.
En cuanto al código de la asignación LET, lo primero que hacemos es verificar si el color recibido es el mismo, y sólo si es distinto se lo asignamos a la propiedad backcolor del usercontrol. La razón de esto es doble por un lado más adelante tenemos que añadir funcionalidad al final del código de este método, dicho código queremos que sólo se ejecute si realmente el color asignado cambió si no estaremos ejecutando cosas para que quede todo como estaba antes. La otra razón es que ahora el valor del color se guarda en la propiedad backcolor del control (en el que hemos delegado), pero si (cambiamos el color del tapiz a azul como se sugirió más arriba al probar y cerramos el entorno y volvemos a abrirlo, volverá a ser rojo, es decir el cambio no se ha mantenido, justo para eso está la siguiente línea: PropertyChanged "ColorTapiz", esta línea le  dice al entorno que esta propiedad ha cambiado, sin embargo esta línea no trabaja sola sino que trabaja en conjunto con 2 métodos del control, uno se encarga de guardar a fichero el cambio registrado (cuando le demos al botón de guardar cambios en el proyecto), y la otra funcionalidad se encargará de volver a leer el valor cambiado cuando arranquemos el proyecto, o se ponga en modo de ejecución el proyecto.

La última línea de código del método LET es una línea comentada, más adelante tenemos que introducir código ya que el cambio del color del fondo, implica que nos borrará el resto del contenido gráfico del control, por lo que se añadirá una línea que salte a una función que vuelva a dibujar todo lo que teníamos y que se ha borrado. Como ese método aún no lo tenemos, dejamos una línea comentándolo.

Justo ahora describiremos estos métodos que ayudan a almacenar de forma permanente las propiedades y que permiten luego al ejecutarlo volver a leer ese valor guardado y lo dejamos por hoy, mañana iremos más rápido con las siguientes propiedades una vez que hemos comprendido de forma general acerca de las propiedades, faltan detallesque se irán presentando según surjan los casos.

Para probar que el color no permanece, vayamos al modo ejecución y cambiemos el color del fondo... y acto segudio pulsemos la tecla F5, veremos que aparecerá el formulario pero con el color que le asignamos en la propiedad backcolor de la ventana de propiedades de la interfaz del control.

Ahora añadamos este código al control (abajo del todo):
Código: Visual Basic
  1.  
  2. Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
  3.     With PropBag
  4.         .WriteProperty "ColorTapiz", UserControl.BackColor, Ambient.BackColor
  5.    
  6.     End With
  7. End Sub
  8.  
  9. Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
  10.     With PropBag
  11.         UserControl.BackColor = .ReadProperty "ColorTapiz", Ambient.BackColor
  12.        
  13.     End With
  14. End Sub
  15.  
  16.  
Estos métodos pueden localizarse en la ventana de código del control sobre la lista de procedimientos del control (usarcontrol), por tanto elparámetro éste de propbag, lo provee el entorno de VB, este es un objeto interno de VB cuya funcionalidad procede de una interfaz cuyo objetivo es precisamente la de almacenar y recuperar valores de propiedades que se han asignado durante el diseño (impronta), es algo así como si compras un vehículo, cuando se fabrica es metal y debe ser pintado para evitar que se oxide, aunque a los vehículos se los elige el color y se piden se nosenvía cuando la fábrica dispone de una demanda suficiente de ese color para cambiar los tambores de pinturas en el proceso en cadena, por ejemplo para pintar 200 vehículos seguidios de ese color. sin embargo aquí en VB es como si todos salieran con una capa antióxido gris (que en el entorno se llama  Ambient.Backcolor y que es el contenedor quien decide ese color, de hecho es el color del contenedor, es como si la fábrica fuera azul por defecto todos los vehículos salieran azules), luego para asignar el color que actualmente hay guardado el objeto Propbag (Bolsa de propiedades) le dice asigna a la variable (Usercontrol.Backcolor) leyendo en las propiedades guardadas ( .Readproperties) el valor de la propiedad ColorTapiz  que se guardó bajo ese mismo nombre en el fichero, y si no se encuentra en el fichero un valor guardado tomamos el valor almacenado en usercontrol.backcolor actualmente.

Es decir el método readproperties se compone de 3 partes la asignación (usercontrol.Backcolor =), la invocación  del método del objeto pararecuperar el valor (propbag.Readproperties), pero que como usamos with, nos ahorramos escribir en cada línea el nombre del objeto), y los parámetros que necesita esta invocación, que al caso son 2, el nombre de la propiedad guardada y un valor que se asigna por defecto si tal propiedad no se encuentra: UserControl.BackColor = .ReadProperty ("ColorTapiz", Ambient.BackColor) igualmente en vez de poner por defecto el color del contenedor podríamos poner un color específico, por ejemplo: .ReadProperty( "ColorTapiz", vbBlue) o incluso un valor numérico: .ReadProperty ("ColorTapiz", 234567)

El método readproperties ocurre 1 única vez (realmente es un evento que se dispara para el usercontrol) y es cuando el control entra en modo de ejecución, una vez leídas las propiedades ya no se vuelve a invocar dicho método.

Writeproperties, es el método que usa el control para que se guarden las propiedades y ocurre también una sola vez, justo antes de que el control sea descargado de memoria. Esto sólo sucede mientras la 'aplicación cliente' está en diseño, es decir el control está en modo de ejecución, ya que en modo diseño lo que se guarda es el valor de la propiedad que nosostros le dimos en la ventana de propiedades del control, pero ese no es accesible a nosotros. Es decir nosotros hemos diseñado que cada vez que un cliente utilice el control éste aparecerá cuando se cargue por primera vez la instancia el color rojo, sin embargo el cliente querrá y podrá cambiar  que cuando su aplicación se ejecute el control aparecerá con el color que él eligió, es ese valor el que nosotros guardamos en writeproperties, los cambios que el cliente introduce cuando está diseñando la aplicación.

Este método consta de un parámetro más que el método readproperties del objeto propertybag: guarda a fichero (writeporperties) una propiedad con el nombre "ColorTapiz", cuyo valor actual está en la variable: Usercontrol.Backcolor (la variable que actalmente contiene su valor) y si el valor no se encuentra o no es válido entonces asigna éste por defecto (Ambient.Backcolor, el del contenedor donde se halleel control). Igualmente que para readproperties podría asignar un valor directo, como vbBlue ó 56789. Conviene en cualquier caso que en ambos sitios el color asignado por defecto sea el mismo en ambos casos

Bien ahora que ya hemos descrito como se logra que las propiedades permanezcan entre sesiones, podemos volver al formulario cambiar el color a uno que no hayamos usado (por ejemplo un violeta) y guardar el proyecto para que ocurra un evento writeproperties y efectivamente se guarden, luego pulsamos la tecla F5, con lo que ahora se crea el control (recordemos el evento initialize que probamos al principio de esta parte) y luego se invoca el evento readproperties, que asigna las propiedades que hemos guardado. en el evento initialize el color será rojo, pero ahora tras el readproperties será el que le dimos la última vez (violeta)...
Y finalmente por hoy ya que hemos guardado el color violeta para esta instancia veamos como al añadir una nueva instancia del control al formulario el color del fondo de éste es el rojo. Ahora debería quedar claro que valores son los que se guardan en writeproperties y se leen con readproperties Y también debería quedar claro el significado del método propertychanged.
También podemos probar a cambiar la propiedad del control por código, no sólo desde la ventana de propiedades de los objetos del formulario. Por ejemplo añade un botón microsoft y escribe código, para que cuando se pulse cambie nuestro control de color o nos diga el color actual.

Después hacer todas las pruebas que queramos, conviene dejar sólo una instancia del control (del que estamos diseñando) en el formulario para no liarnos cuando mañana continuemos...

Mañana ahondaremos en las propiedades y crearemos bastantes más ahora que se ha explicado como crearlas. También mañana explicaremos como se soportan propiedades que ni siquiera existen, backcolor lo posee el usercontrol y enabled, por lo que en estos caso podemos delegar en elas aunque como hemos visto podemos cambiarle el nombre por el camino...

No lo he revisado ya que sale un tocho largo y me llevaría más tiempo, espero que no se me haya escapado ningún gazapo...

54
Visual Basic 6.0 e inferiores / Re: Control Cwgraph en visual basic 6.0
« en: Sábado 4 de Septiembre de 2010, 08:10 »
El soporte para licencias permite a un control cuando se compila, añadir sobre él una clave de licencia que protege todos los controles que forman parte de él.

Hay 2 tipos de archivos de licencia (en Microsoft), si el destino es usarse en páginas Html tiene una extensión .lpk (como éste no es tu caso lo omitimos), cuando el destino es usarse en aplicaciones de escritorio se crea un archivo de extensión .vbl cuando se compila  el archivo .ocx , luego, cuando se crea un empaquetado para distribución ambos archivos son incluídos automáticamente. Finalmente, cuando se instala el control se pasa la clave de licencia al registro del equipo, en el cual entonces se permite el uso del control. En cambio si sólo se copia el archivo .ocx a otro equipo y se registra no queda vinculación de la licencia, por lo que el control no podrá funcionar.

Un usuario final no puede usar un control con licencia si no ha instalado (y previamente adquirido) el control.

En los controles de usuario existe la contrapartida, contra la que se valida dicho código y que por tanto verifica que la clave de licnecia .vbl (que consta sobre el registro) corresponde con dicho control. Luego cuando se crea una instancia de control que requiere una licencia es en ese momento cuando verifica este punto.

Cuando se adquiere un control que tiene licencia, dicho control tiene que ser 'instalado' desde por ejemplo un archivo .cab y que por tanto suele ser residente en el equipo donde se instaló el control. Al formatear dicho ordenador requerirá forzosamente volver a instalar el control. tienes por tanto que localizar el archivo de instalación para ese control. Si como dices no es una versión de evaluación por alguna parte debe 'andar'... localízalo e instálalo sobre el equipo en el que vas a desarrollar...

Espero que te haya quedado más o menos claro.

55
Diseño de Algoritmos / Re: Algoritmo Clasificacion de Materiales
« en: Sábado 4 de Septiembre de 2010, 06:29 »
Cita de: "sishco"
Hola.

Tengo que hacer una funcionalidad en una Base de Datos y tengo un problema con lo siguiente.

Por una parte tengo una tabla con relaciones de padres e hijos.
La tabla tiene los campos IdPadre, IdHijo ademas de  alguno mas.

El caso que con esta clasificacion por ejemplo me podria quedar una cosa como esta:
..... ..........

esa lista. La lista seria H1H2H3H4H5H6H7H8H9 y podria crear o P1,P4 o P2,P3.

......

La verdad que ahora mismo no se por donde cojerlo.
Alguna idea??
Tal como yo entiendo que te has expresado, siempre que una lista de hijos parece completa justifica crear un padre, si esto es así, entonces con la lista H1H2H3H4H5H6H7H8H9 , realmente tienes que crear P1, P2, P3 y P4 porque todos tienen ahí sus hijos.

Una forma de realizar el algoritmo sería tal que así:

Código: Text
  1. Si cada padre necesita la lista complea de hijos para crearse el padre, entonces no puede fallar ningún hijo, luego creo un árbol, con tantos nodos como padres hay y a cada nodo le   agrego tantos nodos como hijos  tiene con el correspondiente valor del hijo. Tengo por tanto un árbol con una proofundidad de 2 nodos más la raíz.
  2.  
  3. ...luego cuando se recibe una lista verifico por cada nodo hijo del raíz, recorro los subnodos y trato delocalizarlos en la lista recibida si uno de los nodos en el árbol no encuentra correspondencia en la lista ese padre no será creado (de hecho paro este recorrido tan pronto como un nodo hijo no se encuentra reflejado en la lista recibida y salto a comprobar el caso para el siguiente padre), si todos los nodos hijos de ese padre se localizan en la lista  entonces se crea el padre.
  4.  
Ovbiamente esto te irá bien si entendí correctamente tu planteamiento de que para crear un padre es necesario que en la lista aparezcan todos sus hijos.

56
Visual Basic para principiantes / Re: Como alinear el texto de un ListBox?
« en: Sábado 4 de Septiembre de 2010, 06:01 »
No hay ninguna propiedad para ello, puedes hacerlo manualmente controlando el ancho de cada ítem, hasta encontrar el mayor y repartir este respecto del ancho del control (incluso ajustar el ancho del control al ancho del mayor) luego añadir espacios a izquierda (según la alineación deseada, izquierda,derecha o centrado) a cada item hasta completar el ancho del mayor.

Es costoso en tiempo, así que yo no te recomendaría hacerlo en listados muy largos. Nota que al hacerlo estarás cambiando el texto de cada ítem, por lo que si debes evaluarlo en algún momento no olvides el:
Código: Visual Basic
  1.  
  2.   if trim$(list1.list(x)= ElItemMuestra then
  3.       ...........
  4.   end if
  5.  
  6.  

Además fíjate si es costoso que cada vez que introduzcas un ítem deberás verificar si es el mayor y si lo es readaptar todos de nuevo a este tamaño, sino lo es sólo hay que adaptar éste al tamaño mayor. Igualmente cuando elimines un ítem deberías verificar si el ítem eliminado era el mayor, si no lo era no pasa nada, pero si lo era deberás localizar de nuevo el mayor y redistribuir todo de nuevo al nuevo tamaño.

Haz unas funciones que serán invocadas según el caso descrito cuando se añaden,  elimina ítems, o cambias de ancho el control.

Tendrás una función verificar al añadir que haría
Código: Text
  1. Si hay items en el listado luego
  2.   si el el ancho del nuevo item es mayor que el existente luego
  3.        añadir el nuevo ítem
  4.        el ancho de éste es el nuevo ancho de ajuste
  5.        recorrer toda la lista y reajustar según el nuevo ancho
  6.    en otro caso
  7.       ajustar este item al ancho actual
  8.       añadir el nuevo ítem
  9.    fin caso
  10. no hay item en el listado
  11.     añadir el nuevo ítem
  12.     el ancho de éste es el nuevo ancho de ajuste
  13. fin caso
  14.  
     

Tendrás una función verificar al eliminar que haría
Código: Text
  1.  
  2. eliminar el ítem
  3. Si hay items en el listado luego
  4.   si el el ancho del que se va a eliminar es el acnho actual luego
  5.        recorrer la lista para localizar el item de mayor ancho
  6.        el ancho de éste (encontrado) es el nuevo ancho de ajuste
  7.        recorrer toda la lista y reajustar según el nuevo ancho
  8.    fin caso
  9. no hay items en el listado
  10.    el nuevo ancho de ajuste es 0
  11. fin caso
  12.  


Cuando se recorre la lisa para ajustar hay que ajustar según el tipo de alineación actual (si hay más de 1).

57
Visual Basic 6.0 e inferiores / Re: Control Cwgraph en visual basic 6.0
« en: Sábado 4 de Septiembre de 2010, 05:22 »
Si el control tiene licencia necesitas colocar el archivito en tu ordenador.

58
Visual Basic 6.0 e inferiores / Re: VB6: ComboBox con "Separador" de texto
« en: Sábado 4 de Septiembre de 2010, 05:17 »
La verdad, no logro entenderte.

Si no eres capaz de explicarte correctamente será más difícil que alguien te pueda ayudar.
No entiendo que quieres decir con 'separador de texto', tampoco logro sacar conclusiones con el supuesto ejemplo que pones.

59
Bueno una vez acabadas las vacaciones, como te señale, vamos a construir un control de usuario.

Como es largo (de explicar) lo haré en partes.
En esta primera parte vamos a describir todo lo necesario para poder desarollar los proyectos y crear los archivos necesarios para crear el control y probarlo. ncluyendo la primera prueba del control, sin código alguno, listo para la siguiente parte en que iré exponiendo código y las razones de qué, cómo, cuándo y porqué de cada cosa.

______________________________
Para empezar es conveniente saber que un control deusaurio se crea cuando necesitamos exponer una interfaz de usuario, es decir algo gráfico. Desde este punto de vista estos controles deberían mejor llamarse 'control gráfico de usuario' frente a las clases que podrían llamarse 'control no gráfico de usuario', como el orden de suceso de las cosas fueron de una manera cada cosa se llamó como en su momento se consideró oportuno. También es importante señalar que quien ya ha trabajado con clases encontrará bastante asequible trabajar con controles de usuario.

Ahora crearemos todos los archivos y proyectos que necesitamos para empezar, se creará un proyecto para elcontrol y un proyecto para probarlo y ambos proyectos serán controlados por lo que en el entorno VB se llama 'grupo de proyectos' . Así abramos el entorno de desarrollo y elegimos eltipo de proyecto 'control Activex'.  Ahora cambiamos el nombre del proyecto (para no perdernos en explicaciones conviene que le des el mismo nombre que sugiero, luego en tu desarrollo dale el nombre que prefieras, éste nombre elegido es por comodidad en la didáctica, nada más) desde 'proyecto1' a 'PryBoton'. Ahora igualmente cambiamos el nombre del control de usuario desde 'UserControl1' a 'CtlBoton'. finalmente le damos al botón guardar para guardar el proyecto, la ruta elígela como prefieras yo sugiero algo como: 'C:Mis proyectoscontrolesBotón simple'.

Una vez creado el proyecto del control, podremos cerrar el entorno y volverlo a abrir o bien desde el menú 'archivo' elegir 'crear nuevo proyecto', ahora elegimos un proyecto de tipo 'exe estándar'. Igualmente que con el anterior a este proyecto le renombramos desde 'proyecto1' a 'Probar_ctlBoton' . el nombre del formulario no importa. Ahora guardamos el proyecto, la ruta será la misma que elegimos para el control pero creamos una carpeta llamada 'pruebas' y lo guardamos dentro de esa carpeta ('C:Mis proyectoscontrolesBotón simplePruebas'). Este proyecto está destinado a probar el control mientras lo estamos diseñando e incluso para probarlo una vez hayamos compilado el control.

Para que ambos proyecto trabajen juntos ambos deben estar dentro de un grupo de proyectos, así ahora vamos al menú 'archivo' y elegimos 'añadir proyecto' y desde la ficha 'recientes' elegimos el proyecto 'pryBoton' (o bien lo localizamos desde la ficha existente, también podríamos haber creado en este momento el proyecto del botón) y lo abrimos. Si nos fijamos bien en el cuadro de herramientas se nos ha añadido el icono para el control que hemos añadido (más adelante se indicará como proporcionar un icono personalizado para el control). Seleccionamos dicho icono del control (veremos que el tooltip del icono señala el tipo de control que es (ctlBoton) . Bien pués ahora pongamos una instancia del control en el formulario del proyecto de prueba.
Ahora pulsamos el botón de guardar proyecto, el archivo del grupo de proyectos 'grupo1.vbg' (vb-Group ) lo guardamos también donde el proyecto de prueba, no es necesario cambiarle el nombre. Si ahora cerramos el entorno cuando volvamos a abrir el entorno ahora buscaremos abrir el archivo de proyectos, 'grupo1.vbg', ya que si sólo abrimos uno de los proyectos se abrirán sólo los archivos concerniente a ese proyecto, este archivo de 'grupo' es el que vincula 2 o más proyectos entre sí. Mas adelante se darán las indicaciones oportunas a la hora de compilar el control.

Bien ahora ya tenemos todo listo para empezar. Vayamos al control de usaurio y abramos el control, sobre las propiedades del control busquemos la propiedad backcolor cambiémosla por cualquier color que no sea gris... rojo, negro va bien. Si apartamos la ventana del control lo suficiente para ver el formulario veremos que el control aparece 'rayado', esto es indicativo de que el control está en 'modo diseño' . Cerremos la ventana del control (la ventana no el proyecto) veremos que inmediatamente nuestro control en el formulario cambia, no sólo desaparece el rayado sino que ahora aparece del color que le elegimos para el fondo, se dice que ahora el control está en 'modo de ejecución'. Esto es importante tenerlo en cuenta, ya que un poyecto de vb estaba en ejecución cuando pulsábamos f5 y aquí aún no lo hemos pulsado.

Podemos proceder, pero primero damos al botón paa guardar todos los cambios operados (yo en mis opciones de vb tengo por defecto que cuando ejecute un proyecto me pida si se guardan o no los cambios así, yo no necesito pulsar el botón, pero hay que acostumbrarse a guardar los cambios antes de ejecutar (el proyecto deprueba). Pulsemos la tecla F5 y veremos nuestro control en ejecución, aunque de momento no hace nada, sin embargo se ve y (en mi caso aparece rojo).

Ya estamos listos para empezar a diseñar nuestro botón. Esta es la primera parte, los preparativos iniciales, realmente lleva más tiempo explicarlo que hacerlo... y bastante más si además se tiene que teclear las indicaciones así que ruego paciencia.

Mañana empezaremos a diseñar el botón y explicaremos el ciclo de vida de un control de usuario.

60
Creando un control OCX.
Ahora estoy de vacaciones así que sólo me pao de tanto en tanto por el foro ni puedo dedicarle tiempo.
Para finales de agosto regreso, si no tienes mucha prisa para entonces te pongo un ejemplo...

61
Visual Basic 6.0 e inferiores / Re: Coordenadas (x,y) cuando escribo en picture
« en: Sábado 24 de Julio de 2010, 21:10 »
Claro, puede darte un valor que no esperas, porque debes tener en cuenta el factor de escala del picture...

Además debes tener en cuenta si haces un retorno de carro o no. Recuerda que un retorno de carró sucede tras un picture1.print "hola" , luego al hacer un retorno de carro currentx vuelve a valer 0.

Hay 2 soluciones dependiendo de qué te veas forzado a elegir:
1 - no hacer el retorno de carro en este momento, sino más tarde
Código: Visual Basic
  1.  
  2. Private Sub Form_Load()
  3.     Dim x As Long
  4.     Me.Show
  5.     Picture1.CurrentX = 20
  6.     Picture1.Print "Temperatura";      ' el ; indica que continúa en la misma línea...
  7.          x = Picture1.CurrentX
  8.     picture1.print ' ahora hacemos el retorno de carro... después de haber tomado la posición.
  9.     MsgBox x
  10. End Sub
  11.  
  12.  

2 - Puedes calcular manualmente el 'destino' aunque hubiere saltado de línea, hay 2 propiedades para ello... usamos textwidth...
Código: Visual Basic
  1.  
  2. Private Sub Form_Load()
  3.     Dim x As Long
  4.     Me.Show
  5.     Picture1.CurrentX = 20
  6.     Picture1.Print "Temperatura"   ' hay retorno de carro porque no hay punto y coma..
  7.           x = 20 + Picture1.TextWidth("Temperatura") ' le pido la longitud al mismo texto introducido + el desplazamiento previo...
  8.     MsgBox x
  9. End Sub
  10.  
  11.  

62
Visual Basic 6.0 e inferiores / Re: Coordenadas (x,y) cuando escribo en picture
« en: Sábado 24 de Julio de 2010, 20:23 »
En un momento que tengo...
A ver Nilson, esto no debería serte a estas alturas problemático...

Sea que estamos pintando en un picture1...
Código: Visual Basic
  1.  
  2. ' elegir una posición x al azar entre 1 y la mitad de la ventana
  3. ' escribir temperatura en la x elegida
  4.  
  5. ' Ahora consultamos la posición actual.... del cursor En este preciso instante.
  6. x = picture1.CurrentX
  7. msgbox x
  8.  
  9.  

63
Visual Basic 6.0 e inferiores / Re: Adaptar Imagen al PictureBox
« en: Jueves 17 de Junio de 2010, 19:10 »
Llevaba alrededor de 1 hora escribiendo y explicando los cambios, pero al darle a enviar se ha ido todo al garete y me da pereza rescribirlo todo de nuevo, así que sólo te mando el proyecto con los cambios operados.... y si algo no lo entiendes preguntas, así será más breve...

2 cosas no obstante que si debo aclararte, la función dibujarimagen remplaza en uso a tu rutina Dibujar_Imagen (que se ha comentado),  y he añadido una función para poder especificar al guardar una imagen con la extensión de la misma, esto afecta seguramente afecte a otras funciones que pretendan utilizar la imagen guardada, como por ejemplo una función que pretenda borrar la imagen del disco, por lo que dichas situaciones deben localizar la imagen usando la función al respecto y puede usarse como ejemplo el código de llamada cuando se trata de 'guardar a disco la imagen'.

64
Visual Basic 6.0 e inferiores / Re: Adaptar Imagen al PictureBox
« en: Miércoles 16 de Junio de 2010, 04:43 »
Lo he descargado, mañana te lo miró en un momento, que se me hace ya muy tarde.... Sólo te pondré el código que se necesite cambiar...

65
Visual Basic 6.0 e inferiores / Re: Adaptar Imagen al PictureBox
« en: Lunes 14 de Junio de 2010, 14:58 »
Un modo sencillo  de utilizar imágenes es utilizar un control image con la propiedad strecht establecida a true. Ahora cuando cambies una medida, la imagen se rescala automáticamente para ajustarse al control.

Claro que un control no es un contenedor, por lo que si el control ha de contener otros controles, entonces sería mejor que metieras el control image dentro del picturebox.

Si a pesar de todo quieres utilizar un picturebox, la solución pasa por usar el método paintpicture.
Carga la imagen en un picturebox oculto (invisible) que tiene la propiedad border a 0 y la propiedad autosize a true, ahora sólo tienes que hacer 2 cosas...
1 hacer el tamaño del picturebox de destino de las medidas que quieres.
2 pegar en el picturebox de destino la imagen del picturebox de origen
El picturebox de destino debe tener establecida la propiedad autoredraw a true.

Todos estos valores los estbalecemos en la carga del formulario y como es para probar, ya precargamos una imagen...
Código: Visual Basic
  1.  
  2. Private Sub Form_Load()
  3.     Dim ruta As String
  4.     PicOculto.BackColor = vbWhite  ' para distinguirlo del fondo del formulario si quieres probar sin hacerlo invisible.
  5.     PicOculto.Visible = False      ' lo ocultamos  de la vista del usuario
  6.     PicOculto.BorderStyle = 0      ' sin borde 3d
  7.     PicOculto.AutoSize = True      ' garantiza que cuando se cargue una imagen el control se ajuste al tamaño de la misma.
  8.    
  9.     ruta = Environ$("windir") & "WebWallpaper"
  10.     ruta = ruta & Dir(ruta)
  11.     PicOculto.Picture = LoadPicture(ruta)
  12.    
  13.     PicDestino.Move 0, 0          ' lo movemos a la esquina superior izquierda
  14.     PicDestino.AutoRedraw = True   ' lo que peguemos se quedará permanente.
  15. End Sub
  16.  
  17.  

Necesitamos saber la cantidad de twips por píxel de la resolución actual, esto lo pdedimos por ejemplo durante el resize del formulario... al menos ocurre 1 vez ( cuando se construye el formulario).
Código: Visual Basic
  1.  
  2. Dim stpx As Single  ' se contienen en estas variables
  3. Dim stpY As Single
  4.  
  5.  
  6. Private Sub Form_Resize()
  7.     stpx = Screen.TwipsPerPixelX
  8.     stpY = Screen.TwipsPerPixelY
  9. End Sub
  10.  
  11.  

Finalmente con un botón realizamos la acción deseada... fíjate que le damos 500 píxeles de ancho y alto, a la función debe pasársele el valor deseado
Código: Visual Basic
  1.  
  2. ' mostramos 3 cambios de tamaño con pausas de 3 segundos entre ellas
  3. Private Sub Command1_Click()
  4.     Call EscalarImagen(500, 500)
  5.     Call Pausa(3)
  6.     Call EscalarImagen(640, 480)
  7.     Call Pausa(3)
  8.     Call EscalarImagen(1024, 768)
  9.  End Sub
  10.  
  11. Private Sub EscalarImagen(ByVal Ancho As Long, ByVal Alto As Long)
  12.     With PicDestino
  13.         Call .Move(.Left, .Top, Ancho * stpx, Alto * stpY) ' cambiamos el tamaño al deseado
  14.         Call .PaintPicture(PicOculto.Picture, 0, 0, Ancho * stpx, Alto * stpY, 0, 0, PicOculto.Width, PicOculto.Height, vbSrcCopy) ' pegamos la imagen con el tamaño deseado.
  15.     End With
  16.     Me.Caption = CStr(Ancho) & " x " & CStr(Alto) ' ponemos en el título de la ventana el tamaño actual de la imagen
  17. End Sub
  18.  
  19. ' hacemos una pausa antes de seguir...
  20. Private Sub Pausa(ByVal Segundos As Byte)
  21.     Dim tim As Single
  22.    
  23.     tim = Timer
  24.     Do
  25.         DoEvents
  26.     Loop While Timer - tim < Segundos
  27. End Sub
  28.  
  29.  

66
Visual Basic 6.0 e inferiores / Re: JOYSTICK EN VB
« en: Lunes 14 de Junio de 2010, 14:25 »
Como te he respondido en el otro hilo, el enlace funciona perfectamente. Tal vez tengas un problema con tu navegador-firewall...

67
Visual Basic 6.0 e inferiores / Re: Controlar El Joystick Desde Visual Basic
« en: Lunes 14 de Junio de 2010, 14:23 »
Cita de: "egtfar"
el enlace para bajar el ejemplo no sirve!
Funciona perfectamente, yo lo acabo de probar.

68
Visual Basic 6.0 e inferiores / Re: ComboBox
« en: Lunes 14 de Junio de 2010, 13:53 »
Citar
En C++ cuando queremos que un if no haga nada cuando un Text está vació escribimos if (Text1.Text ="") Then return; como se haría en Visual Basic
En VB hay 2 maneras, la primera es ignorarlo... con lo que sólo se hacen acciones si tiene texto:
Código: Visual Basic
  1.  
  2.     If Text1.text <> "" then
  3.           ' código
  4.     end if
  5.  
  6.  
En el ejemplo se ve que si no hay texto no se ejecuta código.
Claro que puede darse el caso que tras ese código haya más código y sólo queramos que se llegue ahí si hay 'texto'. La solución es salir como en C con return, pero VB6 emplea su propia instrucción.
Código: Visual Basic
  1.  
  2.     If Text1.text ="" then exit function ' o sub si es una subrutina y no una función
  3.  
  4.  


Citar
Qué propiedad he de utilizar para usar un ComboBox con un Select Case. No sé como pasarle el índice de cada uno de los elementos del Combo para en función de lo seleccionado haga una cosa.
Listindex apunta al elemento actualmente seleccionado. Imagina una matriz, lisindex refiere al elemento actual.
 
Ahora bien para conocer el texto de un elemento cualquiera se usa la propiedad list. es como si tuvieramos una matriz llamada list
Combo1.List(23)  ' refiere el texto del elemento 23
Código: Visual Basic
  1. Private Sub Command1_Click()
  2.     Select Case (Combo1.list(combo1.listindex))
  3.          Case 0
  4.              MsgBox ("Cobre")
  5.         Case 1
  6.              MsgBox ("Aluminio")
  7.     End Select
  8. End Sub
  9.  
En un control combo a diferencia de un control lista, el valor del elemento seleccionado puede obtenerse directamente con la propiedad text:
Código: Visual Basic
  1.  
  2.      dim Texto as string
  3.  
  4.      Texto = combo1.List(combo1.Listindex)
  5.      msgbox Texto
  6.      Texto = Combo1.Text
  7.      msgbox Texto
  8.  
  9.  
Así, ambas líneas de código de asignación del texto son equivalentes. Pero ojo, esto no es recíprocamente cierto, es decir sólo es cierto cuando listindex es distinto de -1. Imagina que en el combo tenemos 7 elementos , los días de la semana, yo podría perfectamente hacer esto:
Código: Visual Basic
  1.  
  2.  
  3. ' para probarlo correctamente desde la interfaz pulsa por ejemplo en 'jueves'
  4. Private Sub Command1_Click()
  5.     Dim Texto As String
  6.      
  7.      Texto = Combo1.List(Combo1.ListIndex)
  8.           MsgBox Texto
  9.      Texto = Combo1.Text
  10.          MsgBox Texto
  11.      Combo1.Text = "Hola que tal"   ' aquí automáticamente cambia el listindex a -1
  12.           MsgBox Combo1.ListIndex
  13.      Texto = Combo1.List(Combo1.ListIndex)
  14.          MsgBox Texto
  15. End Sub
  16.  
  17.  
El msgbox 1 indicará 'Jueves', el 2º también, luego cambiamos el texto del combo, y automáticamente se cambia el listindex a -1 (incluso aunque el valor introducido exista en el combo), de hecho para verificarlo nos muestra listindex = -1 señal de que actualmente no hay elegido ninguno del combo (porque es eso lo que ha sucedido cuando hemos metido un valor directamente en el texto). Al final como ha cambiado el listindex a -1 (no itemseleccionado) entonces no hay texto para el elemento.

Si no queremos ese comportamiento debemos activar la propiedad 'Locked' del combobox, esto impide que el usuario introduzca texto en el combo, aunque por código nosotros todavía podremos cambiarlo. Por tanto es importante que sepas la diferencia entre usar: 'Combo1.Text' y  'Combo1.List(Combo1.ListIndex)' . Aunque oparecen lo mismo queda claro que no lo son. la 1ª expresión refleja el texto actualmente en el combo, la 2ª expresión refleja el contenido del elemento seleccionado, por eso la 1ª y la 2ª no necesariamente coincidirán.

69
OpenGL / Re: Colisiones 3D
« en: Domingo 6 de Junio de 2010, 10:18 »
Yo usaría el valor de colisión de acuerto a un baremo de 'tensión del cordaje de la raqueta' , es decir el cordaje muy tenso podría tener un valor 5 y el cordaje menos tenso un valor de -5 por ejemplo , así tendrías 11 niveles de tensión. Este mismo valor serviría para determinar luego la fuerza de rebote, la exactitud del ángulo del rebote y por tanto la capacidad de 'efectos'.

Cuánto más tensa, con mayor fuerza devuelve la pelota también con mayor precisón resulta el ángulo pero la posibilidad de efecto es nulo y al revés cuanto menos tensa (-5) con menos fuerza devuelve la pelota, la precisión del ángulo de rebote es menor pero hay grandes posibilidades de hacer efectos

Los efectos serían la diferencia que hay entre un 'tiro tenso' y un 'tiro parabólico', el efecto lo calcularíamos como la variación de la posición de la raqueta cuando el valor de colisión es (pongamos 200) y  cuando alcanza el valor de colisión para la tensión elegida por el usuario teniendo en cuenta la velocidad de la pelota.  un ejemplo de suposición, cuando la posición de  la pelota para una colisión es 200, o menos tomamos la posición de la raqueta, calculamos el ángulo de la pelota con la raqueta y le llamamos 'angulo de llegada' cuando la pelota impacta (el valor de colisión determinado según el nivel de tensión de la cuerda) tomamos nuevamentela posición de la raqueta para determinar el 'ángulo de impacto'. Ahora con el ángulo de llegada, el ángulo de impacto, la velocidad de la pelota y la tensión de la cuerda debes determinar una trayectoria de rebote y una velocidad de rebote. Adicionalmente podrías alterar estos valores en función de la distancia al centro de la raqueta donde impacte la pelota, le daría más realismo pero tus cálculos serían un poco más complejos.

Por supuesto los mismos valores: angulo de llegada, ángulo de impacto, velocidad de la pelota y tensión de las cuerdas (no hemos considerado tensión de la raqueta (la fuerza con que se sujeta la raqueta), ni aceleración de la raqueta (diferencia de tiempo que transcurre entre el cálculo del angulo de llegada y el angulo de impacto, es decir acerco la raqueta a la pelota, mantengo la distancia o alejo la distancia?, el cual influye en la fuerza de rebote) ni como decíamos antes, lugar de impacto sobre la raqueta (no es lo mismo que pegue en el centro que próximo a un extremo)) podrías usarlo para calcular el movimiento de la raqueta.

Calcular los valores:
* Velocidad de la pelota: Velocidad de salida de la pelota (desde el jugador contrario) menos la pérdida unitaria por distancia en base a la trayectoria seguida. también podrías calcularla como velocidad de salida de la pelota - tiempo transcurrido. Este valor en todo caso se calcula cuando la pelota está a una distancia de colisión de 200 o menos. (distancia de precolisión y que asociamos con el material de la raqueta cuando el golpe va a proceder con la raqueta y con el tipo de pista y escenario cuando rebota en el suelo). Al hablar más abajo de tensión de pista, se explica más sobre esto.
* Angulo de llegada: Angulo formado entre el centro de la raqueta y el centro de la pelota cuando esta en distancia de precolisión.
* Angulo de impacto: angulo formado entre el centro de la raqueta y el centro de la pelota cuando ésta hace colisión.
* Tensión de las cuerdas: ya vimos que este valor es una constante elegida por el jugador y que va asignada a la tensión de las cuerdas de la raqueta. Es una propiedad de la raqueta.


Si los añades ...:
* Tensión de Pista: para simular rebotes en el suelo .... es equivalente a considerar un jugador excepto en 2 cosas el cálculo es más simple porque no hay , elementos de cálculo 'extra' (los que se detallan debajo). El valor de distancia de precolisión, en vez de 200, podría variar según sea un suelo de tierra o hierba y además variar ligeramente estos valores según la pista donde se juegue: por ejemplo Roland Garrós: tierra = 230, Hierba = 200, Sidney; Tierra= 240, hierba = 180; Winbledon Tierra= 210, hierba= 170..etc... quédate con la idea, no con los valores.

Otra cosa para calcular rebotes de pista, la velocidad de precolisión aumenta con la gravedad, por lo que aquí importa el valor y máximo alcanzado, pero incluso más que el valor y importa la relación xy, distancia x entre el jugado que golpeó entre la altura máxima alcanzada. Este valor lo calculas como un factor de suma para la velocidad de salida del rebote, deberás probar una constante que se multiplica por dicho factor calculado, para ver que tenga un efecto lo más realista posible sin encarecer tus cálculos. Es decir si tu calculaste una velooocidad de rebote de 80Km/h este factor podría darte un valor a sumar en un rango +- 10%, 10% cuando salió un 'globo' y -10% cuando se hizo una dejada cerca de la red y una altura no mayor de 2 metros (por poner un ejemplo). Fíjate como un valor 0, prácticamente sería cuando se golpea desde la línea de fondo y la pelota no supera los 2 metros de altura, luego un valor negativo será cuando x sea un valor menor y será un valor positivo cuando la pelota tienda a subir más alto de 2 metros  y cuanto más cerca de la red... esto te da una idea aproximada de como hallar un valor eficaz.

* La tensión de la raqueta: es una suma a la tensión de las cuerdas, pero digamos que la tensión de las cuerdas es constante y la tensión de la raqueta podría definirse para el jugador en cada movimiento (golpe), si quiere hacer una dejada cerca de la red, tendrá que tener una tensión de raqueta muy baja con respecto a si quiere hacer una dejada estando lejos de la red.
*  El lugar de impacto en la raqueta: De modo similar, es una suma para ese 'golpe' a la tensión de las cuerdas, influye también en el ángulo de salida.
* La velocidad de movimiento de la raqueta (en busca de la pelota):, también es un valor a sumar a la tensión de las cuerdas, éste valor influirá en la velocidad de devolución y en ciertos efectos en el eje x/z  é y/z (normalmente más en uno que en otro).

Nota: yo he puesto un valor de 200 (2 metros) como distancia de precolisión, pero en la práctica tendrás que probar, la idea es simplemente establecer el concepto, más que el valor.... y recuerda que ese valor puede y debería ser también un factor unido a la raqueta podrías reflejarlo como una propiedad del material de la raqueta, madera, plástico, metal y por tanto variar entre una gama de valores....
Calcular un valor para la precolisión debería ser basado en el tiempo y las distancias empleadas, supongamos que empleas distancias en cm. y que la pista tiene  24 metros, entonces deberíamos definir un tiempo de reacción del usuario que puede ser aproximadamente de menos de 1 segundo, luego la precolisión va relacionada con la distancia que la pelota sería capaz de recorrer en ese tiempo, como no es una situación real, podriamos conformarnos con que este valor sea fijo para una distancia o para un tiempo, si lo haces para el tiempo resultará más practico calcularlo en el temporizador pero posiblemente no sea tan eficaz ya que subyugas la veocidad de respuesta del jugador tanto si la pelota va a 150km/h como si va a 30km/h, basarlo en distancia es más realista, pero complica los cálculos, entonces el tiempo de reacción del oponente dependerá de la velocidad de la pelota, que efectivamente es más realista aunque tampoco exacto. Sin embargo utilizar inicialmente un valor basado en el tiempo te permite experimentar con mayor comodidad y te ayudará a encontrar un valor óptimo basado en la distancia, por eso no desprecies usar en pruebas un valor basado en el tiempo de reacción por ejemplo 1 segundo para empezar a probar estaría muy bien... pero naturalmente tendrías que ir reduciendo hasta llegar posiblemente a tiempos de 50-300milisegundos. (no pases por alto la jugabilidad aunque suponga falsificar al alza estos valores, si no resultará un juego muy difícil).
Un valor de 150 km/h (como valor de saque) es una velocidad de 41'6 m/sg luego a esa velocidad la pelota tarda apenas medio segundo en cruzar la pista de extremo a extremo, esa velocidad va decayendo, de modo que debe actualizarse constantemente, luego el resto del peloteo alcanza velocidades mucho menores también influídos por las distancias a recorrer.

Nota 2: la colisión debe estar sincronizada con el 'avance mínimo' del movimiento de la raqueta, por ejemplo si tu avance es 0'8 (como indicas que tienes) la colisión  sobre las cuerdas debe estar en el rango -0'4 a + 0'4 (para una tensión de cuerdas igual a 0, para una tensión de cuerdas igual a 3 debería estar entre 2'6 y 3'4), y la precolisión (usando por ejemplo el valor de 200) un valor 10 veces mayor en: 196 a 204. (8 cm de recorrido)

p.d.: Como necesitas un timer para ir actualizando el avance de la pelota, debes establecer 2 comparaciones, si la pelota toca el suelo antes de la red o no, una vez sobrepasada la red, ahora empezamos a comparar el momento en que la pelota alcance la distancia de precolisión para calcular  los valores previos para el cáclulo de un rebote sea del jugador o del suelo, si se produce un rebote en el suelo ahora, es claro que el movimiento de avance sigue pero con valores actualizados por el rebote. sobrepasar la red para entrar en la pista del jugador contrario por tanto es un buleano:

Operativa del temporizador:
Código: Text
  1.  
  2. actualizar avance pelota
  3. actualizar desplazamiento de jugadores (raquetas) si hubiere lugar
  4. si red false luego (la pelota aún está en el campo del que saca)
  5.          si precolision luego
  6.                  colision igual calcular si colisión en suelo
  7.                  si colision suelo luego  
  8.                          punto perdido para el jugador, botó en su propio campo
  9.                           esto implica: parar temporizador, actualizar puntos, pelota en manos del jugador correspondiente para saque
  10.                 fin si                
  11.          no precolision
  12.                  precolision igual calcular si precolisión en suelo
  13.                  si precolision luego        
  14.                          calcular condiciones de llegada
  15.                  fin si
  16.          fin si
  17.          red igual calcular si red (si se sobrepasó la red consultando el valor x),  según el turno del jugador  
  18. si red true luego
  19.          si precolision luego
  20.                  colision igual calcular si colisión en suelo
  21.                  si colision suelo luego
  22.                          si botes igual 0 luego
  23.                                  si botó dentro campo luego
  24.                                           recalcular trayectoria
  25.                                           botes igual 1
  26.                                           colision igual false
  27.                                           precolision igual 0
  28.                                  si botó fuera de campo
  29.                                          punto perdido para último jugador que golpeó pelota
  30.                                  fin si
  31.                          si botes igual 1 luego
  32.                                 punto ganado para último jugador que golpeó pelota
  33.                          fin si        
  34.                  si colision jugador luego
  35.                           calcular Rebote
  36.                  fin si
  37.          no precolision
  38.                  precolision igual calcular si precolisión en suelo o jugador
  39.                  si precolision luego   (sea un tipo u otro): precolisión=0 no hay presolisión, precolisión=1 precolisión de suelo, precolision= 2 precolisión de jugador, precolisión= 3 precolisión de suelo y jugador (la colisión determinará que sucede al final si jugador o suelo).      
  40.                          calcular condiciones de llegada
  41.                  fin si
  42.          fin si
  43. fin si
  44.  

70
No es muy práctico ese método, porque a priori no sabes si tienes 3 o 20 partes.
Lo correcto sería que una función que utilizara un bucle...

en ódigo sería más o menos:
Fíjate que  tomamos los archivos del 1 en adelante y se pegan  todos en el archivo 0
Código: Visual Basic
  1.  
  2. Private Function RefundirArchivo(ByRef Rutas() As String) As String
  3.     Dim f1 As Integer, f2 As Integer
  4.     Dim b() As Byte, k As Long, n As Integer, t As Long
  5.  
  6.     On Local Error GoTo sale    '  típicamente un fallo con una ruta, un archivo no se pudo abrir, no existe,etc...
  7.     If (Not (Rutas)) <> -1 Then  ' la matriz tiene elementos ?
  8.         f1 = FreeFile: f2 = FreeFile
  9.         Open Rutas(0) For Binary As #f1
  10.         t = 1
  11.         For n = 1 To UBound(Rutas)
  12.             Open Rutas(n) For Binary As #f2  ' abrimos archivo uno a uno
  13.                 k = LOF(f2)                  ' nos informamos de su tamaño
  14.                 ReDim b(0 To k - 1)          ' reservamos memoria
  15.                 Get #f2, , b                 ' leemos origen
  16.                 Put #f1, t, b                ' pegamos en destino
  17.                 t = t + k                    ' actualizamos puntero de escritura
  18.             Close #f2                        ' cerramos archivo actual
  19.         Next
  20.         Erase b                              ' liberamos memoria
  21.         RefundirArchivo = Rutas(0)           ' si todo fue bien devolvemos la ruta del archivo resultante, si falló algo se devuelve una cadena vacía.
  22.     End If
  23. sale:
  24.     Close #f1, f2
  25. End Function
  26.  
  27.  
  28.  

Para que funciones correctamente se requiere ciertas condiciones... la mas obvia es:
* La matriz de rutas esté correctamente ordenada si las partes se unen en diferente orden ya sabes que podrá salir.
* El tamaño final del archivo no puede superar el tamaño de un long (2GB.)

Para probarlo: imginemos que tenemos un lote de archivos en la unidad c, que sellaman 'Mi archivo.jpg' y los siguientes en la forma 'Mi archivo-00x.jpg' donde x es un cifra del 1 al 9, queremos por tanto refundir esos archivos del 1 al 9 sobre el primero.. usando el evento click del formulario:
Código: Visual Basic
  1.  
  2. Private Sub Form_Click()
  3.     Dim r() As String, res As String, k as integer
  4.    
  5.     '  recopilación de las rutas...
  6.      ReDim r(0 To 9)
  7.     r(0) = "C:Mi archivo.jpg"
  8.     For k = 1 To 9
  9.         r(k) = "C:Mi archivo-00" & CStr(k) & ".jpg"
  10.     Next
  11.    
  12.     res = RefundirArchivo(r)           '   llamada a la función
  13.    
  14.    ' avisar del resultado
  15.      If res <> "" Then
  16.         MsgBox "Archivo refundido en el archivo: " & res
  17.     Else
  18.         MsgBox "Algo falló al refundir archivos..."
  19.     MsgBox
  20. End Sub
  21.  
  22.  
  23.  

p.d.: Adicionalmente el método que te señalan más arriba podría fallar, ya que utiliza caracteres para leer un archivo, un carácter se compone de 2 bytes, así cuando leas ficheros cuyo tamaño no sea par, fallará.... porque estarás pegando un byte más que desplazará a los de los siguientes archivos.

71
Windows / Re: NO aparece mi Lector de DVD en mi pc
« en: Domingo 30 de Mayo de 2010, 16:10 »
Perdona, Nilson, olvidé éste hilo...
La solución si fallaba, era desinstalar el dispositivo y luego forzarle a instalarse desde el CD de instalación.
Es muy probable que algún virus (u otra causa) te quedara corrupto alguna librería y no encontrara una copia de seguridad.

72
Como te he comentado en otro mensaje anterior, este foro es de vb 6... no de vb.net

utiliza el Menú: BUILD .... en la carpeta Release de tu proyecto aparecerá el ejecutable si no encontró ningún error.

p.d.: menú:GENERAR (que lo tienes en español).

73
Visual Basic para principiantes / Re: Flash en Visual B 2008 ERROR
« en: Viernes 28 de Mayo de 2010, 15:42 »
Sólo 2 cosas...

1 - Este es un eforo de vb6 de vb 2008.
2 - Tu cuestión versa sobre flash, que es un producto de adobe, lo acorde es que preguntes en un foro que verse sobre adobe. VB es de Microsoft. Aunque VB integras la tecnología ActiveX, los detalles del funcionamiento de cada uno recáe sobre su fabricante, flash es de adobe, los detalles serán conocidos posiblemente en un foro sobre tecnologías de adobe. Como por ejemplo, saber, si flash requiere o no licencia para ser programado...

74
Como tienes el código sin indentar da pereza leerlo. He hallado algunos errores incluído conceptuales...
La variable 'numero', es una matriz, no puedes asignar un valor único a una matriz completa, sino que debes establecerlo a elemento en una posición concreta.

Código: Visual Basic
  1. '  Esto no es válido:
  2. NUMERO = Text1.Text
  3.  
  4. '  Esto si es válido:
  5. NUMERO(i) = Text1.Text
  6.  
  7.  ' y  Esto también es válido:
  8. NUMERO(6) = Text1.Text
  9.  

Luego hay errores conceptuales, por ejemplo,  estableces una matriz de 11 elementos pero luego sólo usas 10. Las matrices declaradas sin specificar su elemento inferor se basan en la declaración Option Base, que por defecto (cuando se omite) es 0.
Entonces si tu dices
Código: Visual Basic
  1.  
  2. Dim x(10)  ' va del elemento 0 al 10, por que option base no se estableció, por defecto es 0
  3. dim x(1 to 10) ' va del elemento 1 al 10, por que lo he declarado explícitamente
  4. dim x(-5 to 5) ' va del eleemnto -5 al elemento 5, por que lo he declarado explícitamente
  5.  
  6.  

Ahora si yo establezco en el código:
Código: Visual Basic
  1.  
  2.    Option base 1
  3. Dim x(10)  ' va del elemento 1 al 10, por que option base se estableció en 1
  4. dim x(0 to 10) ' va del elemento 0 al 10, por que lo he declarado explícitamente
  5. dim x(-5 to 5) ' va del eleemnto -5 al elemento 5, por que lo he declarado explícitamente
  6.  
  7.  

Luego cometes otro error, si tienes que mostrar 10 textos, es correcto hacer un bucle con ese número de iteraciones, pero el textbox sólo se establece 1 vez antes de que tu ejecutes tu código. Esto no es consecuente. si el valor introducido fue 5, toda la matriz tendrá el mismo resultado, porque textbox1.text no cambia.

La solución: o bien pones un textbox por cada elemento de la matriz, o bien solicitas el texto mediante inputbox, tesoluciono el problema precisamente usando este último método..
Código: Visual Basic
  1.  
  2. Dim RESULTADO(1 To 10) As Long
  3. Dim N As Integer
  4.  
  5. Private Sub cmdAGREGAR_Click()
  6.     Dim I As Byte
  7.     Dim txt As String
  8.    
  9.     For I = 1 To UBound(NUMERO)
  10.         Do
  11.             txt = InputBox("Introduce un número...entre -32767 y 32767", "elemento " & I & " de 10", I)
  12.             If Abs(Val(txt)) > 32767 Then
  13.                 txt = ""
  14.             End If
  15.         N = Val(txt)
  16.         Loop While N = 0
  17.         RESULTADO(I) = N * N
  18.     Next I
  19. End Sub
  20.  
  21.  

He hecho varios cambios, fíjate en porqué los he hecho...
La matriz Numero sobra ya, si recogemos los valores al momento de usarlos.
La matriz resultado de ha dmensionado desde 1 a 10 elementos, para ser coherentes.
El texto se recoge con inputbox, puesto que la variable es un entero, el texto sólo es aceptado si el texto está dentro del rango de entero y ese valor es distinto de 0 (esta última restricción habría que pensársela ya que 0 es un número válido).
La matriz resultado se ha declarado como long, porque si se declara como integer cuando hallemos el cuadrado de ciertos valores provocará desbordamiento.
La variable de contador i, se declaró como byte, sólo utiliza un rango 1-10, suficiente para su contenido.

Un bucle do...loop no optimizado controla que se introduzca un texto válido. Sería preferible usar la expresión if isnumeric(txt) luego... también te recuerdo que -32768 es un valor integer lo mismo que 0. Perfeccionar el método es cosa a tu esfuerzo.
....etc...

75
Visual Basic para principiantes / Re: Como poner un video en un Form
« en: Viernes 28 de Mayo de 2010, 14:49 »
En el link más abajo, describo entre otras cosas, como poner vídeos , incluye código para reproducir vídeos.

En tu caso si nada más arrancar el formulario quieres ya que se reproduzca un vídeo, lo unico que tienes que haces es proveer la ruta del archivo justo en el evento load del formulario, o bien recibirlo a través de la variable de entorno (command$). Los tipos de archivo que puede reproducir son aquellos de los que tengas los códecs instalados en el equipo donde funciona...

viewtopic.php?f=39&t=42868

Páginas: 1 2 [3] 4 5 ... 29