elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


 


Tema destacado: Doble factor de autenticación o verificación en dos pasos


  Mostrar Mensajes
Páginas: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [15] 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ... 148
141  Programación / Programación Visual Basic / Re: Establecer jerarquía en controles Treeview en: 19 Mayo 2018, 22:26
No, yo no me enojo fácilmente... lo que pasa es que a veces al hablar, puedo parecer brusco y de ahí habrá quien asuma enojo...

Más arriba te ponía un ejemplo (con código y todo), con la intención de explicarte que aunque hay múltiples ítems en principio ídénticos, ninguno caía en otra 'caja' que la suya propia, precisamente para ilustrar que lo que lo hace posible es elegir una clave única para esa 'caja'...
...en el ejemplo, la clave se formaba con "año" + los 4 digitos del año.

De igual modo debes proceder tú... Para rama principal se le debe asignar una clave única. Y luego todos los elementos bajo esa rama, deben hacer alusión a esa clave.
En realidad es algo que ya debería venir desde diseño en la propia BD. Si no es así, el código para delimitar correctamente cada caso, puede ser tortuoso, porque tendrás que verificar muchos otros factores (posiblemente no disponibles en los datos rescatados), que supondrá mayor sobrecarga, aún suponiendo que logre salir bien... o directamente no ser posible por no disponer de los datos suficientes para delimitarlo.

He abierto tu base de datos, pero hay bastantes tablas y no me apetece perder tiempo mirando la relación entre ellas, si lo tienes preferiría que pusieras un diagrama (incluso aunque sea dibujado a mano), donde se vea la relación entre todas ellas... tampoco es preciso que sea un diagrama de toda la base de datos, basta que te ciñas por ejemplo a 'cotizaciones' y muestres las tablas implicadas con esta, los campos que tiene cada una y como se relacionan los campos (los que se relacionen) de una con las otras... Después es solo extender el concepto al resto de casos.




La forma óptima pasa por un diseño adecuado de la base de datos...
Realmente lo que he visto de tu BD, dista mucho, así que intento hacerte una explicación algo en detalle pero sin profundizar (daría para un libro).

Sea una tabla llamada ventas, con estos campos:
- IdVenta: -> único, numérico, autoincrementable, "primary key", otras tablas se relacionan con esta clave.
- IdArticulo: -> Foreign key, relacionado con la tabla artículos. Realmente este campo puede ser una lista de artículos (cada compra no es de un solo artículo) en cuyo caso no debe aparecer como tal, si no como un método "GetArticulosPorVenta(IdVenta)"
- IdComprador: -> Foreign key, relacionado con la tabla artículos.
- IdVendedor: ->  Foreign key, relacionado con la tabla artículos.
- IdEnvio: -> Foreignkey, relacionado con la tabla envios. Este dato se rellena cuando el vendedor relice el envío.
- IdMetodoEnvio: -> Foreign key, relacionado ocn una tabla ServiciosDeEnvio, es un valor elegible por el comprador, de una enumeración... esto es muy dependiente de las zonas geográficas y los sevicios que allí se den. pero generalmente existirá algún tipo de prioridad (estandar, urgente y muy urgente), etc.. Este dato se rellena cuando el comprador elige un método de envío entre los disponibles. Al final hablo de la tabla Mensajeros y ServiciosDeEnvio.
- EnvioConjunto: En esta venta varios artículos se envían juntos en un mismo paquete. (esto se relaciona con IdArticulo, más abajo hablo sobre esto)
- FechaVenta: -> datetime, tomada con la función 'now', en el momento de validar la compra.
- FechaEntrega: -> datetime, fecha prevista de entrega, aproximada... posiblemente sea la suma de la fecha de compra o más claramente de la fecha de verificación del cobro, + TiempoLogistica (dependiente del artículo, tamaño, existencias, origen) y destino del comprador (si vive en la ciudad, en el país, o en el extrajero) y posiblemente del método de envío elegido. Este dato se rellena automáticamente cuando se eleige l método de envío...
- Estado: -> valor de enumeracion: problema, comprado, pagado, procesando, enviado, recibido, eliminado (retirado a una base de datos de backup, cuando ya tiene una antigüedad de x semanas/meses tras ser recibido). Problema es el resto de estados pero en valor negativo, indica que en ese estado positivo se registró un problema, así se sabe que es un problema y donde recáe el problema.

En tu Bd, para esta tabla, usas ncli, usa mejor IdCliente para señalar que es una clave única (Id)... y usa el nombre completo, IdCliente, IdComprador, no IdCli, ni IdC... no se ahorra nada por omitir 8 caracteres en el nombre de un campo.

A tu tabla le falta (como mínimo) el IdArticulo...(pero esto tiene miga, me extiendo más abajo, primero por pasos) cada venta es única, pero diferentes ventas pueden tener un mismo artículo...
Una posible explicación es que tienes una tabla llamada Ventas_Detalles, bien puedes trasladar ahí los detalles de esta tabla, pero en ese caso, en esta tabla debe haber unica y exclusivamente el IdVenta y pocos campos más (también Ids)... es decir esta tabla sería un 'array' un índice donde buscar la venta y con ella ir a la tabla detalles... sin embargo lo veo redundante. porque en la tabla detalles, no va a haber repetida ningún idVenta, luego aquella es un clon de esta, pero disperasando unos datos en una y otros en otra...

Una misma venta puede contener varios artículos, por lo que en realidad, es mjor opción eliminar IdArticulo de la tabla ventas, pero disponer de un método apuntando a otra tabla... ahí si podría llamarse VentaDetalles, pero para nada los campos que tu tienes... y considerar que cada venta tiene detalles (como mínimo un artículo comprado) y para conocer los artículos comprados se debe consultar dicha tabla: "select IdArticulo from VentaDetalles where idVenta = EstaVenta" (Ventas.IdVenta: aquí se pasa el idVenta por el que estás interesado), esto devuelve todos los registros de artículos asociados a una venta específica, artículos que luego se colocan como hijos de la venta en el treeview.


Tabla VentaDetalles:
Cada registro de compone de dos referencias. Una al artículo y otra  a la venta. De esto modo multiples artículos comprados apuntarán a la misma venta.
- IdArticulo: foreign key, se relaciona con un único artículo.
- IdVenta: foregin key, relaciona a este artículo con una compra específica.
opcional - IdVendedor: foreign key (abajo del todo después del pseudocódigo comento esta opción)

La otra opción es más cara y supone un mal planteamiento de la base de datos, ya que exige que si se compran varios artículos, exista un registro de compra por cada artículo... Es mla planteamiento por:
- De entrada exige sobrecarga de memoria, la base de datos crece, una compra elegante solo requiere un registro de venta + 2 ids por cada artículo comprado, frente a tantos registro de venta como articulos comprados en una sola venta.
- Como cada venta, tiene su primarykey, esta resulta inútil para relacionar todos los artículos comprados con una sola venta (que es lo que te pasa). Supone entonces que al comprar debes crear una referencia única para cada venta (que es justamente lo que es un primary key, que se crea sola y de la que te desentiendes, pero aquí por tu solución te la debes currar tú), y en cada registro de venta (para una misma compra) debe constar esa referencia de venta...
- Supone además crear más métodos... para consultas y actualizaciones.
- No existe una tabla donde consten todas esas 'referencias únicas, sino que resulta de 'explorar' intensivamente dicha tabla 'ventas' (intensivamente=sobrecarga inútil).




Entonces la existencia de la tabla Ventas y los campos declarados sugiere que además deben existir las siguientes tablas (más las derivadas de esas):
Articulos, Compradores (clientes), Compras, Vendedores, Almacen, Pedidos, Mensajeros, ServicioDeEnvio, Envios, Imagenes...


La tabla articulo (producto):
Breve descripción: Sobre ella recáe el añadir o eliminar artículos (siponibles a la venta), y actualizaciones: modificar precio, descripción,  nombre imagen. Se relaciona además de con: Ventas, Clientes y Vendedores con Almacen y Pedidos.
Respecto de pedidos, hace falta saber si los artículos son todos de un solo vendedor o cada vendedor expone sus propios artículos (asumo esto último si existen IdVendedor, es que hay más de uno), es decir que no es para empresa que vende si no para una empresa que gestiona compra-ventas, ellos mismos solo son mediadores y no venden artículos propios. Esto implica que esta tabla puede ser muy diferente según el caso... haré una somera descruipción de cada caso aparte:
Si hay multiples vendedores, la tabla almacén, Pedidos y otras sobran, ya que será el propio vendedor el encargado de tales gestiones y escapa, aquí todavía se podrá mantener la tabla envíos, donde el comprador indique fecha de pago (si no es inmediato y recibido cuando llegue a su casa el paquete, y el vendedor indique cobrado, enviado... aunque estos estados deben ser opcionales, porque unos y otros suelen olvidar actualizar tales datos.


Tabla Articulo: Vendedor Absoluto: por ejemplo una ferretería, un supermercado.
- IdArticulo: -> único, numerico, autoincrementable, primary key,
- IdImagen: -> foreignKey --- se relaciona con la tabla Imagenes. Un valor 0 indica que no posee imagen asociada al artículo.
- Nombre: -> texto, 64caracteres máximo (aprox.). Nombre simple que el cliente verá como título del artículo.
- Referencia: ref + hash del nombre + IdArticulo , ejemplo:  refAD34B2-00345. Este se recalcula solo cuando cambia el nombre. Y solo sirve para ventas futuras, para las pasadas ya no importa.
- Descripcion: --> Texto más largo y más detallado, que descibra el producto.
- TiempoDeManipulación: -> numerico byte, indica el tiempo aproximado (en días) que se tarda en envolver y enviar dicho artículo. No es lo mismo un reloj, que un armario de 4 puertas. En caso de un supermercado, o una ferretería esto es inmediato, se lo lleva el propio comprador, luego este campo sobraría.
- Peso: -> numerico, entero . peso aprox en decimas de kg. es decir algo de valor 1, señala que psa 100 gramos, algo de valor 10 pesa 1kg. (para evitar operar con números reales), si requieres dos decimales, es volver a plicar lo mismo.
- Dimensiones: -> 20 caracteres en la forma xxx'xx-yyy'yy-zzz'zz  largoXanchoXalto en cm. con 2 decimales. Un comprador querrá saber las medidas de ciertos artículos. si empieza por un valor que no es dígito, se considera que no se proporciona medidas, no uses espacios al caso, relena con ceros, ejemplo: 001'23-030'00-102'40.
- Existencias: -> numérico Cantidad restante en stock. ---> Debe relacionarse con tabla Almacen
- AlarmaExistencias: -> numérico, Cuando se compra un artículo, existencias se reduce en 1 8la cantidad comprada), y se verifica si es menor o igual que este campo, si es así, dispara un evento a "Pedidos".


Tabla Articulo: Múltiples Vendedores: La empresa es un intermediario entre el comprador y vendendor (tipo eBay).
Como decía más arriba para la descripción de artículos, si cada artículo es provisto por un vendedor concreto, forzosamente es obligado que esta tabla incluya unos campos y no requiere otros. Del mismo modo unos campos los podrá modificar el vendedor otros son automáticos (como los ids) y según la necesidad de destino, otros pueden variar...
- IdVendedor: -> foreign key, a fin de que un vendedor pueda tener acceso a su artículo en venta y hacer las modificaciones que precise.
- IdArticulo: -> único, numerico, autoincrementable, primary key,
- IdImagen: -> foreignKey --- se relaciona con la tabla Imagenes. Un valor 0 indica que no posee imagen asociada al artículo.
- Nombre: -> texto, 64caracteres máximo (aprox.). Nombre simple que el cliente verá como título del artículo.
- Referencia: ref + hash del nombre + IdArticulo , ejemplo:  refAD34B2-00345. Este se recalcula solo cuando cambia el nombre. Y solo sirve para ventas futuras, para las pasadas ya no importa.
- Descripcion: --> Texto más largo y más detallado, que descibra el producto. Un libro puede llevar el nombre de autores o ISBN, en cambo un pantalón puede señalr si es para señora y la talla.
- TiempoDeManipulación: -> numerico byte, indica el tiempo aproximado (en días) que el vendedor señala tardar en envolver y enviar dicho artículo. Este tiempo se supone que es añadido a la fecha de verificación del cobro.
- Peso: -> numerico, entero . peso aprox en decimas de kg. es decir algo de valor 1, señala que psa 100 gramos, algo de valor 10 pesa 1kg. (para evitar operar con números reales), si requieres dos decimales, es volver a plicar lo mismo.
- Dimensiones: -> 20 caracteres en la forma xxx'xx-yyy'yy-zzz'zz  largoXanchoXalto en cm. con 2 decimales. Un comprador querrá saber las medidas de ciertos artículos. si empieza por un valor que no es dígito, se considera que no se proporciona medidas, no uses espacios al caso, relena con ceros, ejemplo: 001'23-030'00-102'40.
- Existencias: -> numérico Si el vendedor dispone de más de 1 igual a la venta, en otro caso vale 1. Esto no requiere almacén Debe relacionarse con tabla Almacen
- Otros campos que pudieren ser importantes según el cliente del programa.


Tabla Compras:
Esta tabla tiene el mismo propósito para los Compradores que para los Vendedores la tabla Ventas.
En realidad bien diseñado, Ni Ventas ni Compras deben existir, si no una llamada Transacciones donde el vendedor hace consultas de sus Ventas (esto es, ventas sería una clase con varios métodos, lo mismo que compras, que realizan consultas a la tabla transacciones, una spreguntando con IdVendedor y otros con el IdComprador).
Que se le llame tblTransacciones a la tabla, no cambia más que el nombre, los campos vienen siendo los mismos, solo lo aleja de la idea de 'pertenencia' o asociación a 'vendedores'.


Tabla Imagenes:
Contiene el id de cada imagen y la ruta donde localizarla.
Hay quien guarda la imagen en la base de datos, pero eso hace una base de datos gigante y la expone a fallos y problemas de rendimiento. Por ejemplo cuando se debe restructurar una base de datos, mover imágenes (registros conteniendo imágenes) es pesado...
Solo tiene dos ventajas guardar imágenes en la BD: resulta tan infranqueable como la propia BD, la posibilidad de extravío se limita al extravío de la propia BD. En su contra lo mismo, si están en la BD y esta revienta, se piuerden todas, si están en ficheros sueltos en una carpeta, se perderá la que se pierda el resto se mantiene.
Aún así si uno decide guardarimágenes en una BD, sugiero que es aBD, solo aloje imágenes y nada más...
- IdImagen:  -> único, numerico, autoincrementable, primary key, Una imagen inexistente debe tener id=0, una imagen ilocalizable se debe devolver mediante un método que al final entregue -Id . Así cuando se localiza una imagen si se devuelve un valor menor que 1, implica que (0) ó no tiene (-0) ó que la imagen no está en la ruta esperada, fue eliminada, renombrada, etc...
- Ruta: -> texto, 512 caracteres (los 248 para la ruta + los 260 para el fichero).. seguramente no se usen... una forma de dejarlo más corto, es dejar rutas relativas, para el fichero, es decir la carpeta es fija y conocida en la instalación, por tanto basta guardar el nombre d ela imagen, y al caso entonces se puede crear un hash para la imagen como nombre basado en el IdArticulo y Nombre del artículo, + la extnsión de la imagen, con lo que se reduce a apenas 32-40 caracteres: ..\Imagenes\articulos\*.*

Las tablas Compradores, Vendedores, Mensajeros vienen a ser casi idénticas, solo cambia su nombre. Y la tabla que s eles asocia: A Vendedores con Ventas, a Compradores con Compras, a Mensajeros con Envios  y a los previos también con Envios indirectamente a traves de compras o ventas.


Otras tablas:
Almacen: Stocks de entrada.
Pedidos: Stocks de compra.
Mensajeros: Datos de empresas de enviós. (es idéntico a compradores y vendedores)
ServiciosDeEnvio:
- IdModeloEnvio: sería su principal campo, donde se relaciona la empresa IdMensajero con un tipo particular de envio..
- Prioridad: estandar, urgente, muy urgente,
- Lejania: local, nacional, internacional, etc...
- MedidasMaximas (como campo más arriba de 20 caracteres)
- PesoMaximo: (como campo más arriba, para evitar decimales)
- Precio: Lo que cuesta este servicio si cae dentro de las exigencias.
- Sobrecoste1:  Precio extra por algún detalle, por ejemplo si sobrepasa de 12, pero no llega a 20, x por cada kilo o fracción extra. (el 1 es porque puede haber más sobrecostes).

En realidad el diseño final, depende mucho de los requisitos del que reclama el programa (al margen de la propia especificación), unos te dan rienda suelta, y otros reclaman cosas muy específicas... y a veces absurdas.


Y bueno, si esto lo tuvieras más o menos así... teniendo perfectamente relacionado cada cosa con su Ids, se puede usar para rescatar de la BD, los registros asociados.
Entonces, con el diseño mostrado para la clase ventas, por ejemplo podrías tomar cada registro de venta de un vendedor y luego buscar los artículos de cada venta...
 
Evidentemente la vista del treeview, contendrá lo que se quiera consultar, pero se debe ser coherente... en el ejemplo se mstraría como raíz los datos del vendedor, como hijo de este ítem cada una de las ventas, y bajo cada venta cada uno de los artículos de dicha venta.
 (podría reducirse desde todas a solo las que haya a partir de 'x' fecha, o solo las 'y' últimas)...
Código:
' se omite cualquier tratamiento posible de error, solo pretende ser ilustrativo de la forma correcta de proceder
Funcion VistaVendedorTodasSusVentas( numerico esteVendedor, string conectionString)
   Resulset: rsVendedor, rsVentas, rsArticulo

   Vaciar Treeview
   AbrirBD(conectionString)

    rsVendedor = Select From tblVendedores where IdVendedor = esteVendedor
    Añadir al Treeview como raíz el registro IdVendedor

    rsVentas = "Select all from Ventas where IdVendedor = EstevendedorQueConsulta", y luego en un bucle
    Por cada registro de este rsVentas
        Añadir al treeview esta venta con clave IdVenta, bajo raiz. ('strinnizada', añadiendo algún caracter para que no empiece por dígito, por ejemplo el nombre del vendedor, o simplemente key = "v" & IdVenta
        rsArticulos = "select IdArticulo from VentaDetalles where idVenta = EstaVenta"
        For cada registro en rsArticulos
            Articulo = "Select * From tblArticulos where IdArticulo = registro"
            añadir al treeview como hijo de IdVenta, los detalles del artículo que interesen..
        siguiente
    Siguiente
    
    cerrar BD
Fin funcion
Puede que a primera vista te parezca mucha sobrecarga tantas consultas, pero se limita a lo preciso en cada caso, no a obtener un tocho de regstros que luego no se requieran, o no se correspondan, como resultado es más eficiente, son llamadas breves y rápidas, porque son muy acotadas.

Si Access no se comportara bien (no debería ser problema con las versiones actuales que están muy optimizadas, otro cantar sería versiones de los 90), en esos casos quizás convenga añadir a la tabla tblVentaDetalles el campo IdVendedor, y así se podrían rescatar todos de la BD, de una sola vez, a la entrada de la función (en vez de en el bucle), y en el bucle luego revisar cuales correponde al caso. para aligerar esto, con cada añadido al treeview, sería acorde ir eliminado del resulset los registros ya metidos, así la búsqeuda sería más corta cada vez en el bucle... es decir estamos remplazando la sobrecarga en el servidor (donde consta la BD), por sobrecarga en el entorno de la vista (el equipo del cliente)...

Otra opción a considerar en el ejemplo, sería mostrar el vendedor en raíz, y luego bajo el las ventas... y solo cuando el usuario pulse en dicha venta es cuando se consulta los artículos para dicha venta y se muestra en otra ventanita aparte (o en la misma ventana bajo el treeview principal, otro treeview, o un listview a la derecha, etc..).
Esto es aún más acertado, porque aligera aún más la BD de carga de trabajo, solo se reclamarán los artículos de aquella venta para la que el usuario quiera ver los detalles.


Y bueno ya sale un mensaje largo así que corto...
142  Programación / Programación Visual Basic / Re: Establecer jerarquía en controles Treeview en: 18 Mayo 2018, 19:23
Pero eso es ya un problema d elos detalles de la base de datos.

En realidad, yo he puesto como clave:
 Key = RST!NOMBRE_CLI & CStr(RST!IDCoti)
...pero en realidad, yo he usado un criterio arbitrario, tú eres quien tiene los detalles de la base de datos.
La cuestión es que debes usar como clave algo único, que no esté replicado por otro lado... yo he partido del supuesto que IdCoti, es una clave única (por ejemplo) respecto de una transacción para un cliente, es decir que no puede estar asociado a otros clientes, ni a otras transacciones.

La forma de arreglarlo, es tener coherencia en la BD, para tener campos únicos de modo que no pueda existir más asociación que (por ejemplo) el par formado por NombreCli + IdCoti... y en consonacia usar la clave adecuada al caso.
Dicho de otro modo, si tienes un campo "primary key" para cada 'grupo', ahí tienes la segunda parte de la clave, junto con el nombre del grupo, o simplemente "g" + rst.Id (que se declaró primaryKey).

Y por lo mismo es tu responsabilidad asegurarse que si en el mismo treeview debes mostrar diferentes tablas al mismo tiempo sus primary key, deben ir precedidas por algún identificador distinto en cada caso... precisamente para que no cuelen agrupaciones foráneas...

...en definitiva elige como clave algo único, exclusivo para cada agrupación, para que solo sus artículo y ningún otro puedan asociarse a esa clave... y nada más pueda colarse bajo él... si no has diseñado adecuadamente la BD, quizás tengas que reestructurarla...
143  Foros Generales / Noticias / Re: Bill Gates ha tenido que explicarle a Donald Trump la diferencia entre VIH y VPH en: 18 Mayo 2018, 17:46

Es algo recurrente que a ti cualquier noticia donde tenga que ver USA te moleste...

No entiendo tu actitud... Elektro simplemente comenta algo que yo mismo refrendo...

Hablar de un presidente (o de lo que sea) con la excusa de que Bill Gates está relacionado con la informática, no lo convierte en una noticia de informática, es un chascarrillo propio de viejas... y todo esto al margen de lo que uno piense o deje de pensar sobre política.  No veo que resulte tan difícil mantener claras y separadas las cosas.
144  Programación / Programación Visual Basic / Re: Establecer jerarquía en controles Treeview en: 18 Mayo 2018, 16:28
Ok, si...
Como no pude probar el proyecto, lo escribí al vuelo... hay un par de faltas... relacionadas directamente con las colecciones en vb6.

- Vb6, no tiene una función directa para reclamar si un ítem existe en una colección, la solución pasa por provocar un error (si no existe)... que no hemos interceptado (luego lo hago).
Es una manera pobre en programación, resolver problemas a base de provocar 'conscientemente' un error... pero aquí no hay otra manera posible....
 
- El otro problema es que VB6, en el parámetro de ítem al admitir un valor numérico o un string (pero como un parámetro variant), en vez de determinar el 'vartype(parametrovariant) = que sea string (y en otro caso es un número), asumo que va a lo simple y rápido... si empieza por un dígito, lo toma como un número... desentiéndose de que el valor de un string, es legítimo que empiece por un dígito...
 
En realidad, tú que puedes ejecutar bien el código, podrías haberte dado cuenta... aunque sea la primera vez que operes con un trieview, la colección nodes, es una implementación de un objeto collection, con los que asumo qu si habrás trabajado más veces... y sus virtudes y carencias son las mismas.

Código
  1. Sub CARGAR_COTI_SEGUN_NOMBRE(ByVal strQuery As String)
  2.    Dim i As Long
  3.    Dim FACTORY As Node
  4.    Dim GROUP As Node
  5.    Dim ARTICULO As Node
  6.    Dim TIPO_ORDEN As String
  7.    Dim Key As String   ' clave del nodo que se buscara y tal vez se añadira...
  8.    Dim Existe As Node  ' nodo que se busca
  9.  
  10.    '// Conectar la Base Datos con ADO
  11.    Call ConectarBDD
  12.    StrSQL = strQuery
  13.    RST.Open StrSQL, CN, adOpenStatic, adLockOptimistic, adCmdText
  14.  
  15.  
  16.    'me.show
  17.    Do While Not RST.EOF
  18.  
  19.        With TreeView1.Nodes
  20.            .Clear
  21.            Set FACTORY = .Add(, , , RST!NOMBRE_CLI, otFactory, 1)
  22.            For i = 1 To RST.RecordCount
  23.  
  24.                '<------1 aquí la solución para claves que empiezan con dígito, antecederla con una letra cualquiera, pero mejor si tenemos un ascendente como padre, usamos su propia clave...
  25.                Key = RST!NOMBRE_CLI & CStr(RST!IDCoti)  ' esta es la clave del grupo...
  26.  
  27.                on error resume next ' <----2 aquí la mitad de la solución para saber si un ítem existe,
  28.                Set Existe = TreeView1.Nodes.Item(Key)  ' buscamos el nodo cuya clave interesa...
  29.                If Not (Existe Is Nothing) Then  ' si existe anadimos el articulo bajo el (como hijo)...
  30.                    Set ARTICULO = .Add(Existe, tvwChild, , "Cant.: " & RST!Cantidad & " - " & RST!Descripcion, 3)
  31.                    'ARTICULO.EnsureVisible
  32.                Else  ' Si no existe se anade el grupo (con su key) y el articulo bajo el...
  33.                    err.clear '<------3 aquí la otra mitad del problema de buscar un ítem (cuando no existe).
  34.                    Set GROUP = .Add(FACTORY, tvwChild, Key, "Número: " & RST!IDCoti & " - " & "Fecha: " & RST!Fecha, otGroup, 2)
  35.                    'GROUP.EnsureVisible
  36.                    Set ARTICULO = .Add(GROUP, tvwChild, , "Cant.: " & RST!Cantidad & " - " & RST!Descripcion, 3)
  37.                    'ARTICULO.EnsureVisible
  38.                End If
  39.  
  40.                RST.MoveNext
  41.                FACTORY.Expanded = True
  42.            Next i
  43.        End With
  44.    Loop
  45.  
  46.    '// Cerrar la base de datos y liberar la memoria
  47.    Call CerrarADO
  48. End Sub
  49.  


Para que no te pierdas en averiguar cuales son los cambios y añadidos, aquí los aclaro:
Añado eso sí, alguna línea extra para ubicarlos correctamente...
Código
  1.          For i = 1 To RST.RecordCount
  2.  
  3.                '<------1 aquí la solución para claves que empiezan con dígito, antecederla con una letra cualquiera,
  4.                   ' pero mejor... si tenemos un ascendente como padre, usamos su propia clave... delante de la que queremos.
  5.                Key = RST!NOMBRE_CLI & CStr(RST!IDCoti)  ' esta es la clave del grupo...
  6.                ' antes: Key = CStr(RST!IDCoti)  ' esta es la clave del grupo...
  7.  
  8.                ' esta línea se olvidó... poder simplemente correr el programa, y se hubiera detectado a la primera,
  9.                 ' cuando todavía el treeview está vacío (solo con la raíz el 'factory'...
  10.                on error resume next ' <----2 aquí la mitad de la solución para saber si un ítem existe,
  11.                Set Existe = TreeView1.Nodes.Item(Key)  ' buscamos el nodo cuya clave interesa...
  12.                '.....              
  13.                '....
  14.                Else  ' Si no existe se anade el grupo (con su key) y el articulo bajo el...
  15.                    ' Justo en el caso que se produzca error, porque no existe, hay que liberar el error...
  16.                    err.clear '<------3 aquí la otra mitad del problema de buscar un ítem (cuando no existe).
  17.                    Set GROUP = .Add(FACTORY, tvwChild, Key, "Número: " & RST!IDCoti & " - " & "Fecha: " & RST!Fecha, otGroup, 2)
  18.  

Por último, te diría que cambiaras el orden en el condicional, siempre resulta más sencillo ordenarlo en la forma:
   "si existe esto... hacer A... y si no ... hacer B
que decirlo al revés:
   "si no existe esto... hacer B y si no ... hacer A    (el y si no aquí, equivale a si existe)...
La forma de 'si no existe' es más adecuada cuando solo se hace algo en dicho caso, y nada en el otro...

Piensa que para cuestiones del foro (y más si son muy sencillas), escribo directamente en la cajita de respuesta, luego es fácil que se escape algún gazapo pero confiando que el interesado pueda darse cuenta... y corregirlo, mientras lo prueba.







p.d:
Ya que estamas... y que es tu primera vez con un treeview... nota que todos los nodos que son 'ramas' del árbol, para tener una estructura de árbol en la que pueda buscarse con acceso aleatorio (no por recorrido, que es lento), deben tener una clave única... en cambio los nodos terminales, llamados hojas, no es preciso... esas son las que uno debiera recorrer por índice o 'siguiente', 'previo'...

Dicho de otro modo:
En los nodos terminales, el dato importante es el 'texto' (el valor, que en este caso es un string llamado texto).
En los nodos internos, el dato importante es la 'clave'.


Como tengo hoy un tiempito libre a esta hora... Te adjunto un código que acabo de hacer, para que pruebes... y veas lo necesario de poder buscar un nodo...

Es un sencillo ejemplo, que añade años con sus meses bajo el año... si se intenta añadir un año dos veces, como ya existe, no deja, ni genera un conflicto (si genera un error como ya se ha comentado más arriba, pero se trata)...

Abajo adjunto una imagen de como se ve...
Lleva estos 4 controles, con los siguientes nombres:
Treeview: tv1
Label: labAño
Hscroll: hscrAño
command: comAdd


Código
  1. Private n_Raiz As Node
  2.  
  3.  
  4. Private Sub ComAdd_Click()
  5.    Dim key As String
  6.    Dim selYear As Node ', n As Node
  7.    Dim k As Byte
  8.    Dim año As Integer
  9.  
  10.    año = HScrAño.Value
  11.    key = "Año: " & CStr(año)
  12.  
  13.    With Tv1.Nodes
  14.        On Error Resume Next
  15.        Set selYear = .Item(key)
  16.        If (selYear Is Nothing) Then
  17.            Err.Clear
  18.            Set selYear = .Add(n_Raiz, tvwChild, key, key)
  19.            selYear.EnsureVisible
  20.            For k = 1 To 12
  21.                ' si no se va a hacer luego nada con el nodo añadido, se puede ignorar...
  22.                'Set n = .Add(selYear, tvwChild, , MonthName$(k))
  23.                Call .Add(selYear, tvwChild, , MonthName$(k))
  24.            Next
  25.            selYear.Expanded = True
  26.            Call InfoNodos(.Count - 1)
  27.        Else
  28.            MsgBox "Ya se ha añadido el año " & CStr(año) & " al árbol."
  29.        End If
  30.    End With
  31. End Sub
  32.  
  33. Private Sub Form_Load()
  34.    Set n_Raiz = Tv1.Nodes.Add(, , "Raiz", "Calendario anual")
  35.    HScrAño.Value = year(Now)
  36. End Sub
  37.  
  38. Private Sub HScrAño_Change()
  39.    LabAño.Caption = "Año: " & CStr(HScrAño.Value)
  40. End Sub
  41.  
  42. Private Sub InfoNodos(ByVal NumNodos As Long)
  43.    Dim años As Long
  44.    Dim mensajes As String
  45.  
  46.    If (NumNodos > 0) Then
  47.        años = (NumNodos / 13)
  48.        NumNodos = (NumNodos - años)
  49.        mensaje = "El árbol tiene ahora " & CStr(años) & " años y " & CStr(NumNodos) & " nodos más..."
  50.    Else
  51.        mensaje = "El árbol está vacío... solo contiene la raíz..."
  52.    End If
  53.    MsgBox mensaje
  54. End Sub
  55.  

145  Foros Generales / Noticias / Re: Multan por primera vez a una persona por compartir imágenes en WhatsApp en: 18 Mayo 2018, 05:08
Yo no considero ni puedo considerar eso como delito... en realidad se trata de una denuncia pública de un delito... a no ser que me digan que el tipo se colo en la casa del tipo para grabar el vídeo...

Si estaba en la calle, sea poli, enfermero, político o juez... poco importa, leches... las cámaras de tv, graban todos los domingos a millones de espectadores que acuden al estadio a ver fútbol... y nunca ha pasado nada.
146  Foros Generales / Noticias / Re: Todo el contenido de la Wikipedia será enviado a la Luna en un cohete espacial en: 18 Mayo 2018, 05:02
Voy a ver si lo hackeo, y antes de partir, meto a los 200 políticos más dañinos del mundo, y lo desvío al SOL... y 4 70M4R P0R CUL0. :laugh: :laugh: :laugh: :laugh: :laugh: :laugh: :laugh: :laugh: :laugh: :laugh: :laugh:
147  Programación / Ejercicios / Re: ayuda nesecito resolver este ejercicio en pseudocodigo en: 18 Mayo 2018, 04:45
Cada jugador debe...   y se considerara que...  un tiempo mayor a 16 minutos... o que su promedio de tiempos... diariamente puede asistir un número variable de jugadores.. en máximo un mes todos los jugadores...

S1 -Cuantos jugadores deben salir del equipo como resultado de la evaluación de las pruebas?
S2 -Cuantos continúan con el equipo?
S3 -Cuantos continúan en el equipo de acuerdo a cada condición establecida?
Cuando existen muchos condicionantes, tantos que resulta prácticamente imposible o tedioso hacerlo de cabeza... en estos casos lo que se hace es recurrir a una tabla de verdad.

En la cabecera de la primera fila, se coloca cada condicionante (un identificador del condicionanteincluso en forma de expresión si fuere preciso), en cada fila bajo la primera, en la primera columna, cada una de las opciones posibles de cada condición... (pueden recogerse en rangos o lista, si comparten condición 5-12; 3-15, 3,7y11, en la misma fila, etc...)

Luego se va rellenando la tabla cruzando ambos datos (colocando en cada casilla del 'mapa' V,F; 1,0;L T,F (la pareja que prefieras). Importante no errar al rellenarlo, porque luego es prácticamente complicado de descubrir el fallo.... revisa varias veces que lo rellenaste correctamente.

Finalmente a la derecha de añade una columna por cada 'pregunta' (S1, S2, S3), y línea a línea se recorre cada caso actualizando mentalmente si se sigue cumpliendo o si deja de cumplirse, al final se pone V (verdadero) ó F (Falso), 1, 0 ó en ingles T, F, como Salida para esa pregunta en esa línea.
Una vez completo toda la columna (para cada salifa, función), se fija uno en si hay más Verdadero que Falsos... como esto es pura álgebra, si aparecen menos Verdadero que Falso, pues lo expresamos en afirmativo, si son menos los falsos lo expresamos en negativo...
Si Solo el Lunes nadas, es más sencillo afirmarlo... "solo nado el lunes" si sólo el sábado no nadas es más sencillo negar ese día que afirmar el resto "solo el sábado no nado" (que decir "nado el lunes, el martes, el miércoles... y el domingo").

Seguramente recuerdes del álgebra aquello de ABC+ACB+CB+DFG+AG...etc... pués igual, a cada condicionante asígnale una letra y a cada caso posible de ese condiionante un número, luego se trata de recorrer la tabla y poner las expresiones resultantes... y al igual que las expresiones de álgebra (porque esto también es álgebra), se pueden resumir desde la forma canónica (eso ya en una segunda fase)...

Finalmente ya reducidas las expresiones... de la tabla de verdad es luego bastante sencillo realizar el pseudocódigo, porque solo tienes que poner los casos de cada condicionante (que afirma o niega como se ha dicho antes, elegir el más breve).
148  Programación / Programación Visual Basic / Re: Establecer jerarquía en controles Treeview en: 18 Mayo 2018, 04:24
Como te dije, no pude ejecutar el proyecto por falta de liberías de las referencias...

Pues bien, estuve revisando tu codigo pero me lanza errores en 3 puntos el primero es esto

'Aca me marca el 1er error, indicando "No se encontro el elemento"
Código:
Set Existe = TreeView1.Nodes.Item(Key)  ' buscamos el nodo cuya clave interesa...
'Aca me indica que "la clave no es valida"
Código:
Set GROUP = .Add(FACTORY, tvwChild, , "Número: " & RST!IDCoti & " - " & "Fecha: " & RST!Fecha, otGroup, 2)
'Y aca me indica que "el objeto no es valido"
Código:
Set ARTICULO = .Add(GROUP, tvwChild, , "Cant.: " & RST!Cantidad & " - " & RST!Descripcion, 3)
Básicamente tu problema se reduce a que no has copiado la función que te he puesto...
Compara tu línea:
Set GROUP = .Add(FACTORY, tvwChild, , "Número: " & RST!IDCoti & " - " & "Fecha: " & RST!Fecha, otGroup, 2)
con la mía:
' Si no existe se anade el grupo (con su key) y el articulo bajo el...
Set GROUP = .Add(FACTORY, tvwChild, Key, "Número: " & RST!IDCoti & " - " & "Fecha: " & RST!Fecha, otGroup, 2)



Todavía no sé si has cometido otro error, porque la línea aparece dos veces, y el resto de errores pueden demanar del primero, si tras la corrección previa, todavía aparecer error, entonces considera que tampoco copiaste correctamente esta parte:
Nuevamente compara tu línea
Set ARTICULO = .Add(GROUP, tvwChild, , "Cant.: " & RST!Cantidad & " - " & RST!Descripcion, 3)

con la mía (nota que la línea de 'artículo' aparece dos veces, pero son diferentes cada vez)
If Not (Existe Is Nothing) Then  ' si existe anadimos el articulo bajo el (como hijo)...
    Set ARTICULO = .Add(Existe, tvwChild, , "Cant.: " & RST!Cantidad & " - " & RST!Descripcion, 3)

...en fin, es mejor que copies y pegues entera la función que te puse, y remplaza por completo la que tienes, o bien coméntala entera, por si luego quieres analizar más tranquilamente las diferencias...

Vamos, que copiar y pegar, es lo mínimo que uno nunca debería hacer mal... máxime dedicándose a esto...
149  Programación / Programación Visual Basic / Establecer jerarquía en controles Treeview en: 17 Mayo 2018, 04:35
Que tal perdón por molestar, tengo un duda, espero me puedas ayudar te adjunto el code para que lo puedas apreciar mejor.

Te comento, que uso el control treeview y lo que estoy atascado es como agrupar los datos cargados en ellos, si lo ejecutas veras como esta quedando

https://drive.google.com/open?id=..... retirado por discrección


En la carpeta hay 3 capturas de como seria, espero me apoyes

Gracias x tu tiempo
Lo primero decirte que el propósito del foro es ayudar a todos... una duda resuelta vale para otros, luego procede preguntar en el foro, no en mensajes privados. Los mensajes privados, como su nombre indica, son para mensajes que no atañe a nadie más que a los que participan dle mensaje...

Es posible exponer claramente tus dudas, sin necesidad de exponer todo tu código (si razonablemente no lo quieres exponer), si es lo que te preocupa, de hecho, puedes ver como editando 2 de dichas imágenes que mandaste junto con una sola función de carga del Treeview, basta...

Después de todo, no he podido ejecutar tu proyecto, porque yo tengo instalado el entorno de vb6 en un XP, y tu tienes referencias a librerías, no disponibles en XP.

Lo siguiente decirte, que estás usando la versión de commoncontrols de vb5 (SP2), es mejor si la actualizas por la de vb6 (SP6)...
También podría decirte que hay lugar para mucha optimización, peor ese es otro tema...

A lo que venimos...

Cuando como en tu caso cargas datos procedentes de una base de datos y por tanto a priori, desconoces si los ítems a cargar son únicos o tienen subítems, y en cuyo caso quieres que se coloquen exactamente como subítems DEL MISMO ÍTEM, lo adecuado es localizar si existe ya el ITEM, y en tal caso se coloca como 'hijo' de él...

En tu código, no solo no haces búsqueda es que ni puedes hacerla porque no asignas ninguna clave, para luego poder buscar el nodo...

Este es tu código tal cual lo tenías (modificado para eliminar tantas líneas en blanco y antecediendo las declaraciones de variables a cualquier otra sentencia (das trabajo inútil al analizador léxico y al sintáctico, declarando variables en otras partes que no sea al comienzo)).
Código
  1. Sub CARGAR_COTI_SEGUN_NOMBRE(ByVal strQuery As String)
  2.    Dim i As Long
  3.    Dim FACTORY As Node
  4.    Dim GROUP As Node
  5.    Dim ARTICULO As Node
  6.    Dim TIPO_ORDEN As String
  7.  
  8.    '+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
  9.    '// Conectar la Base Datos con ADO
  10.    Call ConectarBDD
  11.    '+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
  12.  
  13.    StrSQL = strQuery
  14.    RST.Open StrSQL, CN, adOpenStatic, adLockOptimistic, adCmdText
  15.  
  16.    Do While Not RST.EOF    
  17.        With TreeView1.Nodes
  18.            .Clear
  19.            Set FACTORY = .Add(, , , RST!NOMBRE_CLI, otFactory, 1)
  20.            For i = 1 To RST.RecordCount                
  21.                Set GROUP = .Add(FACTORY, tvwChild, , "Número: " & RST!IDCoti & " - " & "Fecha: " & RST!Fecha, otGroup, 2)                  
  22.                Set ARTICULO = .Add(GROUP, tvwChild, , "Cant.: " & RST!Cantidad & " - " & RST!Descripcion, 3)                                  
  23.  
  24.                RST.MoveNext
  25.                FACTORY.Expanded = True
  26.            Next i
  27.        End With
  28.    Loop
  29.  
  30.    '+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
  31.    '// Cerrar la base de datos y liberar la memoria
  32.    Call CerrarADO
  33.    '+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
  34. End Sub
  35.  

Y esta es la modificación de la función para que realice el cometido que reclamas...

Nota, que en cada ítem de 'Grupo' añadimos la clave, precisamente para luego poder buscarlo...
Y una vez encontrado (esto es, ya existe), solo se añade el artículo al grupo existente (como hijo de aquel)...
La sintaxis del método Add (nodo) es:
objeto.Add(relativa, relación, clave, texto, imagen, imagenSeleccionada)
Relativa: es una referencia al nodo bajo el cual se trabaja (clave o indice). Se usa el índice cuando la posición es fija y nunca cambia (es más rápido que buscar), se usa la clave, cuando se añaden y eliminan elementos, y por tanto varía y no tendrán nunca un puesto asegurado en un índice específico.
Relación: Indica el posicionado respecto del referenciado (relativo)... primero, último, siguiente, previo, hijo... excepto hijo, el resto es como 'hermano' del referenciado...
Clave: Un texto asociado como único para poder hacer búsquedas... Si se pone clave, y no hicieras búsqueda como hago, no podrías añadirlo, porque te diría que ya existe en la colección nodes un ítem con esa clave... en casos así, donde pueda haber claves repetidas y no interese ponerlos cmo hijos sino al mismo nivel debe omitirse la clave...
Texto: el dato textual que se mostrará en el control para ese ítem...
El resto es autoexplicativo...

Código
  1. Sub CARGAR_COTI_SEGUN_NOMBRE(ByVal strQuery As String)
  2.    Dim i As Long
  3.    Dim FACTORY As Node
  4.    Dim GROUP As Node
  5.    Dim ARTICULO As Node
  6.    Dim TIPO_ORDEN As String
  7.    Dim Key As String   ' clave del nodo que se buscara y tal vez se añadira...
  8.    Dim Existe As Node  ' nodo que se busca
  9.  
  10.    '+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
  11.    '// Conectar la Base Datos con ADO
  12.    Call ConectarBDD
  13.    '+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
  14.  
  15.    StrSQL = strQuery
  16.    RST.Open StrSQL, CN, adOpenStatic, adLockOptimistic, adCmdText
  17.  
  18.    'me.show
  19.    Do While Not RST.EOF
  20.  
  21.        With TreeView1.Nodes
  22.            .Clear
  23.            Set FACTORY = .Add(, , , RST!NOMBRE_CLI, otFactory, 1)
  24.            For i = 1 To RST.RecordCount
  25.  
  26.                Key = CStr(RST!IDCoti)  ' esta es la clave del grupo...
  27.                Set Existe = TreeView1.Nodes.Item(Key)  ' buscamos el nodo cuya clave interesa...
  28.                If Not (Existe Is Nothing) Then  ' si existe anadimos el articulo bajo el (como hijo)...
  29.                    Set ARTICULO = .Add(Existe, tvwChild, , "Cant.: " & RST!Cantidad & " - " & RST!Descripcion, 3)
  30.                    'ARTICULO.EnsureVisible
  31.                Else  ' Si no existe se anade el grupo (con su key) y el articulo bajo el...
  32.                    Set GROUP = .Add(FACTORY, tvwChild, Key, "Número: " & RST!IDCoti & " - " & "Fecha: " & RST!Fecha, otGroup, 2)
  33.                    'GROUP.EnsureVisible
  34.                    Set ARTICULO = .Add(GROUP, tvwChild, , "Cant.: " & RST!Cantidad & " - " & RST!Descripcion, 3)
  35.                    'ARTICULO.EnsureVisible
  36.                End If
  37.  
  38.                RST.MoveNext
  39.                FACTORY.Expanded = True
  40.            Next i
  41.        End With
  42.    Loop
  43.  
  44.    '+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
  45.    '// Cerrar la base de datos y liberar la memoria
  46.    Call CerrarADO
  47.    '+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
  48. End Sub
  49.  
NOTA: Para ver como van apareciendo uno a uno... 'descomenta' las línea de código comentadas...
'ARTICULO.EnsureVisible (y si la ventana aún no es visible
'me.show
OJO: Solo para verlo claro, ejecutando las líneas paso a paso (tecla de función: F8), luego lo vuelves a comentar... carga más rápido si el control se actualiza solo al final... y no con cada añadido.
150  Programación / .NET / Re: Ejecutar programa mediante esto. en: 17 Mayo 2018, 01:54
Tranquilo, no hay ningún problema...
Cada uno tiene su forma de ver las cosas y en definitiva, nadie y todos a la vez tenemos razón. En defnitiva nos une buscar soluciones, aunque sea desde distintas perspectivas, es un "problema" del intelecto inquieto que no para...  :laugh: :laugh: :laugh:
Páginas: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [15] 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 ... 148
Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines