|
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 ... 9 10 [11] 12 13 ... 29
251
« en: Miércoles 3 de Junio de 2009, 23:37 »
Si uno no sabe muy bien como, lo importante es resolverlo.
Pero cuando algo es muy simple o snecillamente bastante asequible uno debe ver si puede optimizar el código.
Así que te propongo que lo optimices un poquito porque le das muchas vueltas innecesariamente para obtener el primero y el último. Debes quitar el bucle y el último debes obtenerlo sin utilizar el strreverse. Te doy una pista... si utilizas las función Left (izquierda) la función Mid 'middle' (Medio) no crees que existirá una función más ?, cuál podría ser ?.
Luego la comprobación de 4 caracteres aunque soluciona el caso, dado que procede de la interfaz deberías detectarlo cuando y dónde se introduce siempre que dicho textbox se usa exclusivamente para esta función y no de forma compartida para otros botones.
Txtnu.Text.maxlength= 4 y en el evento validate lo controlas...
Si utilizas el buscador verás que no hace mucho hablamos bastante sobre el evento validate donde hay ejemplos que te ilustran para qué sirve dicho evento y cómo se utiliza. ...
252
« en: Martes 2 de Junio de 2009, 21:39 »
Esto no precisa ninguna ayuda.
Si no sabes resolver esto por tí mismo, dedícate a otra cosa, no importa que digas que eres un novato...
253
« en: Lunes 1 de Junio de 2009, 04:10 »
Te comento k al principio de la elaboración del programa escogí usar colecciones, pero noté k, en el caso concreto para lo k las uso, era muchísimo más rápido utilizar matrices, x lo k en determinado momento tuve k hacer el cambio casi completo de colecciones a matrices. De hecho, en el caso concreto de mi programa, solo en un caso resultó más eficiente utilizar las colecciones k las matrices .
Deaven, si esta afirmación es cierta, es bastante probable que estés produciendo código 'espagueti'. Un modo de determinarlo a grsosso modo es confirmar que, el hecho de que tus matrices trabajen más rápido que las colecciones no sea debido a: a ) que sólo has considerado el tiempo de acceso a los elementos. b ) que la operación de acceso a los elementos es sustancialmente más elevada proporcionalmente en realación a otras operaciones como añadir o eliminar elementos de la matriz. Si es el caso a, estás producinedo código espagueti, si señalas el caso b, como, sin embargo señalabas que tienes que redimensionar miles de veces muchas matrices resulta una contradición. Para considerar el rendimiento de una estructura no debe sólo considerarse el tiempo de acceso a los elementos, en esto una matriz es más rápido que el resto de estructuras, también debe considerarse el tiempo invertido en el resto de operaciones realizadas sobre la estructura, típicamente añadir y quitar elementos y buscar elementos determinados. Si las matrices son los reyes en cuanto al acceso a un eleento arbitrariamente escogido no lo resulta para acceder a un determinado elemento que cumpla un criterio, por ejemplo si digo devolver el valor que sigue al que yace en el elemento x, en una matriz requiere recorer toda la matriz para buscar y verificar que el elemento hallado sea el que cumple dicho objetivo, si la matriz tiene 1 millón de elementos significa que debes recorrer 1 millón de elementos, si se emplea una estructura cuyos elementos están ordenados sólo se necesitan recorrer 20 elementos para obtener el resultado. Igualmente añadir o quitar elementos , si a la matriz la redimensionas cada vez que añades o eliminas un elemento es lento, y no tanto si el elemento añadido o eliminado es el último que si es el primero, como según los casos no va a ser siempre el último elemento significa que si tienes 1 millón de elementos y tengo que eliminar el elemento 500.000 significa que tengo que bajar desde el elemento 500.001 hasta el final -1 una posición y luego redimensionar (aunque no estás obligado a redimensionar en un momento dado). En eso las matrices son muy lentas. Un árbol por ejemplo añade o elimina elementos en cualquier posición con mucha celeridad. Basta con conectar los hijos del nodo a eliminar (si sólo vamos a eliminar ese nodo, y no también su rama de descendencia) con el padre del nodo a eliminar, de acuerdo al tipo de árbol que sea sólo conectaremos uno de sus hijos o varios y si el árbol mantiene un tipo de orden deba seleccionarse el hijo que se conecta al padre si sólo se conecta 1... En fin, que si estás trabajando con un programa para inteligencia artificial te recomiendo encarecidamente que diseñes varios tipos de estructuras de datos (empleando clases) para hacer un código mucho más fácil de mantener y sobretodo de ampliar reducirás drásticamente las líneas de código necesarias y globalmente correrá más rápido, incluso aunque alguna clase se base en utilizar una matriz cuando su tamaño nunca sea relativamente grande...( creo que tenía por ahí un código que me pidió mi sobrino sobre un simple colección realizada usando una matriz, la condición de uso de esa clase le sugerí que no superara como máximo los 100 elementos, si lo quieres me lo dices lo localizo y te lo expongo). A base de matrices un programa complejo se vuelve insostenible y cada vez que decidas modificarlo te dará una pereza enorme porque tendrás que 'ponerte las pilas' para entender tu propio código (qué quería hacer aquí..) y ver donde debes añadir y cómo sin afectar lo que ya está hecho...
254
« en: Sábado 30 de Mayo de 2009, 00:45 »
No está dentro de lo razonable que cabe esperar ese tipo de error. Si la imagen no fuera válida te daría el error 481 o algún otro si el problema fuera la ruta de acceso...
No es un error de VB6... Es probable que tengas corrupta alguna dll... ó Quizás algún virus tenga usurpado el portapepeles. Trata de restaurar el archivo kernell32, con una copia 'buena' y versión correcta al S.O. que usas. Si eso no funciona trata reinstalando VB y si sigue sin funcionar sin duda tendrías un problema de seguridad que tendrías que corregir lo antes posible, actualiza tus antivirus reinicia en modo 'a prueba de fallos' y pasa todos los antivrus a ver si fijan el problema.
A problemas mayores (si te dejó dañado algunas librerías) restaura el S.O. y si ni con eses quizás la solución fuere formatear...
255
« en: Sábado 30 de Mayo de 2009, 00:21 »
puedes abreviar un poco el código que te señala cpmario, supongo que todavía serás capaz de entenderlo: Private Sub Timer1_Timer() Static blnShowLabel As Boolean blnShowLabel = not blnShowLabel Label1.Visible = blnShowLabel DoEvents End Sub
Recuerda que aquí timer1 es un control no la instrucción Timer Para hacer algo parecido con la instrucción Timer el código sería: private Periodo as integer ' un valor menor de 86401 (segundos de 1 día) ' al cruzar la medianoche, mientras se ejecuta esta función la llamada fallará, si no se controla... es un ejercicio para el interesado controlar dicha situación private sub AlterarModo Static blnShowLabel As Boolean dim crono as long crono= Timer do doevents loop while (timer - crono) < periodo blnShowLabel = not blnShowLabel Label1.Visible = blnShowLabel end sub ' Este código es equivalente al anterior pero que desactiva el timer tras su ejecución Private Sub Timer1_Timer() Static blnShowLabel As Boolean blnShowLabel = not blnShowLabel Label1.Visible = blnShowLabel timer1.enabled=false ' esto hace que sea idéntico a la rutina anterior End Sub ' la llamada de uno u otro método son equivalentes, aunque el resultado es distinto, ya que el timer es asíncrono. public sub Micodigo 'algún código ' .............. call AlterarModo timer1.enabled= true ' aquí se activa el timer, pero se contínua 'al timepo' con la siguiente línea ' más código ' ....................... end sub ' si necesitáramos que el timer se comportara de forma síncrona como sucede con la función tendríamos que ponerle una trampa. public sub Micodigo 'algún código ' .............. call AlterarModo timer1.enabled= true do ' aquí el se espera hasta que el timer se apague antes de continuar con la siguiente línea, por tanto se comporta igual que la llamada a 'AlterarModo' doevents loop while timer1.enabled = true ' más código ' ....................... end sub
Sin embargo para hacer 'parpadear' un control conviene que sea un control timer, precisamente porque es asíncrono y la ejecución continúa... Por último recordarte que el timer se utiliza con milisegundos y su valor máximo es aproximadamente 1 minuto por lo que habrás de utilizar un multiplicador de frecuencia para valores mayores... la función timer trabaja con segundos y su valor expresa los segundos que han pasado desde la medianoche por eso después de 86399 pasa a 0. si un período a controlar es 400 y se invoca después del segundo 86001 no fncionará ya que nunca se dará la condición (timer - puntoDeInicio) > periodo
256
« en: Jueves 28 de Mayo de 2009, 04:59 »
Deaven debes tener en cuenta algunas cosillas para acelerar tanto trasiego. Si como dices una matriz de repente tienes que aumentarla al doble de su tamaño, entiendo que o bien haces un trasvase de información procedente de dos matrices de idéntico tamaño, o bien entiendo que estás reservando espacio de una sola vez para que no se agote rápidamente y tengas contínuamente que que redimensionar las matrices. Si esto es así, es posible que te vaya mejor una colección. Una matriz es más rápida que una colección cuando el número de elementos no va a superar nunca algo así como 100 a partir de ese tamaño una colección suele ser más eficiente, añades y quitas elementos dinámicamente por lo que no malgastas memoria, esto es no utilizas más espacio del que justamente necesitas a cada instante. Ahora bien una colección es un poco limitada, no permite muchas cosas, sin embargo puedes utilizarla para crear clases que utilicen la colección como base añadiendo métodos. No obstante si (como supongo) el código lo estás usando para el programa de inteligencia artificial, creo que sería más acertado que en determinadas circunstancias usaras árboles. en VB6 es relativamente fácil implementar cualquier tipo de árbol. Por ejemplo posiblemente te sería muy útil el arbol de tipo 'montículos' ya que supongo que muchas de las acciones que realices se basarán en cuestiones de prioridad. Los montículos también son óptimos para ordenar y además los montículosm permiten pasarlo a una matriz o crear un montículo desde una matriz en un tiempo prácticamente lineal. Es difícil determinar que tipo de árbol irá mejor para cada cosa, porque desconocemos los detalles del uso que le das a cada matriz. En cualquier caso si usas matrices ten en cuenta el siguiente consejo: Cuando utilices varias veces seguidas el mismo índice de una matriz es más rápido usar una variable. Pongo un ejemplo y lo pruebas si te parece... dim k as long, valor as long dim Matriz(0 to (10^6) -1) as long dim o as long, p as long, q as long, r as long dim t1 as siongle, t2 as single ' cronómetros... ' asignamos valores a la matriz para empezar, no importa el valor para lo que queremos mostrar. for k= 0 to ubound(matriz) matriz(k)=k next t1= timer for k= 0 to ubound(matriz) o=matriz(k) / 3 p= matriz(k) mod 11 q= matriz(k) + 5 if matriz(k) mod 25=0 then r= matriz(k) - q else r= matriz(k) - p end if next t1= timer - t1 t2= timer for k= 0 to ubound(matriz) valor= matriz(k) o=valor / 3 p= valor mod 11 q= valor + 5 if valor mod 25=0 then r= valor - q else r= valor - p end if next t2= timer - t2 msgbox "tiempo 1: " & t1 & " tiempo 2: " & t2
Fíjate que el código es equivalente y que la segunda parte es más larga pués incluye una asignación más al principio del bucle. sin embargo correrá más rápido, porque primero investiva la dirección de la matriz 'matriz(0)' y luego necesita localizar el índice 'x' en la matriz el cálculo claramente es : dirección elemento 0 + desplazamiento indice = matriz(0) + (indice * bytes que ocupa el tipo usado). Como en el bucle se usa matriz(k) 5 veces en cada ciclo es más lento que el 2º ejemplo que sólo utiliza 1 vez, luego recurre a una variable cuya dirección se toma sin calcular nada (*), lo que en grandes bucles o en un uso intensivo de matrices supone un buen ahorro de tiempo. Básicamente si usamos un mismo índice al menos 4 o más veces el tiempo de hacer una asignación a una variable 'nueva' compensa al uso de calcular la dirección del índice.
257
« en: Jueves 28 de Mayo de 2009, 04:17 »
porqué no capturas el error completamente y aportas dicha info ?
on local error goto ....
msgbox err.number & " " & err.description & " " & err. .....
258
« en: Lunes 25 de Mayo de 2009, 20:43 »
Casi con seguridad es lo que te señala Mosquito. Convierte la ruta al shortpath equivalente... aquello de donde era "C:Archivos de Programa..." queda como "c:Archiv~1..." Para ello puedes usar una API al efecto o bien añadir una referencia al FilesystemObject (windows Scripting runtime) , el objeto file admite trayectos cortos y largos. un breve ejemplo: (primero añade la referencia), añade un botón al formulario , luego utiliza el código siguiente... Dim fso As New FileSystemObject Dim fich As File Private Sub Command1_Click() Dim ruta As String ruta = "C:windowsWebWallpaperDesierto rojo con luna.jpg" ruta = RutaCorta(ruta) MsgBox ruta End Sub Private Function RutaCorta(ByVal ruta As String) As String On Local Error Resume Next Set fich = fso.GetFile(ruta) RutaCorta = fich.ShortPath End Function
259
« en: Lunes 25 de Mayo de 2009, 19:50 »
La solución que te presenta Moskito tiene una ventaja y una desventaja. La ventaja es que te permite redimensionar FACILMENTE . La desventaja es que el cálculo de las direcciones es más lento ya que es una matriz dentro de una matriz de estructuras. tiene que calcular la dirección del índice de la matriz luego de la estructura y luego de la otra matriz. El modo en que VB6 redimensiona las demás dimensiones es del siguiente modo: dim k() ' declarar 3 dimensiones redim k(0 to 99, 0 to 99, 0 to 99) ' 3 dimensiones = 100 * 100 * 100 elementos 1millón. ' redimensionar la mariz redim preserve k(100,100, 120) ' al utilizar preserve sólo se puede alterar la última dimensión y no permite añadir ni quitar dimensiones. Para hacer esto hay que crear una nueva matriz con las diemnsiones requeridas y pasar desde la primera hacia esta lo que deseemos, luego asignar a la primera el valor de esta.
Puede interesar ver algunas consideraciones en torno alas matrices dinámicas, estáticas y el uso de preserve las matrices variant son otro caso que ahora no comentamos ' usando una matriz dinámica Dim k() As Byte ' esto es perfectamente válido ReDim k(0 To 99, 0 To 99, 0 To 99) ReDim Preserve k(0 To 99, 0 To 99, 0 To 120) ReDim Preserve k(0 To 99, 0 To 99, 0 To 20) ' esto no es válido ReDim Preserve k(0 To 99, 0 To 99, 0 To 99, 0 To 2) ' añadir dimensiones ReDim Preserve k(0 To 99, 0 To 99) ' quitar dimensiones ReDim Preserve k(0 To 99, 0 To 120, 0 To 99) ' variar tamaño de dimensiones anteriores a la última ' pero sin preserve (lo anterior) si es válido, porque se borra toda la información de la matriz y se crea de nuevo, por eso se llama dinámica ReDim k(0 To 99, 0 To 99, 0 To 99, 0 To 2) ' añadir dimensiones ReDim k(0 To 99, 0 To 99) ' quitar dimensiones ReDim k(0 To 99, 0 To 120, 0 To 99) ' variar tamaño de dimensiones anteriores a la última ' usando una matriz estática Dim W(0 To 99, 0 To 99) As Byte ' no se puede redimensionar de ninguna manera, W es una matriz estática, durante su vida no puede tener otras dimensiones que las declaradas, es una matriz de dimensiones 'constante' ReDim Preserve W(0 To 99, 0 To 120) ' en cuanto entre en la función marcará el error (early binding), comentar la línea entonces ReDim W(0 To 99, 0 To 120) ' en cuanto entre en la función marcará el error (early binding), comentar la línea entonces w(45, 45, 45) = 122 ' marcará que las dimensiones no corresponden... en cuanto entre en la función (early binding) k(45, 45, 45, 45, 45, 45) = 122 ' aquí sólo notará el error cuando llegue a su ejecución. (late binding) ' esto no da error, porque al ser estática con erase lo que hace es borrar la matriz y reconstruirla nuevamente (equivale a borrar su contenido a cero, una reiniciación de la misma) Erase W W(45, 45) = 122 ' una matriz dinámica borrada equivale a no estar inicializada es como cuando sólo se había declarado Dim k() As Byte ' aquí dará error, el error es que no tiene dimensiones declaradas. Erase k k(45, 45, 45) = 122
ejemplo de un redimensionado de una matriz dinámica en una dimensión anterior: Supongamos una matriz que guarda meses y días en forma de matriz... dim año() as boolean redim año(1 to 12, 1 to 7) ' primera semana de cada mes ' asignar valores... for mes= 1 to 12 for dia=1 to 7 año(m,s)=true next next
Después de esto supongamos que tenemos otro problema similar pero que en vez de usar sólo la 1ª semana de cada mes queremos usar las 4 semanas completas del mes para redimensionar la matriz podríamos considerarlo como 28 días en vez de 7 redim año(1 to 12, 1 to 28) 'las 4 semanas de cada mes ' asignar valores... for mes= 1 to 12 for dia=8 to 28 año(m,s)=true next next
pero puede que queramos trabajar utilizando una dimensión más para referirnos a cada semana por separado dado que no podemos hacer un preserve y a la vez variar el número de dimensiones tenemos que utilizar una mtriz de intercambio... dim prov(1 to 12, 1 to 4, 1 to 7) ' declaramos la matriz provisional que es como debería quedar la matriz original ' asignamos los datos actuales ' hacemos un equivalente al preserve pero trasladando datos donde corresponda for mes= 1 to 12 for dias= 1to 7 prov(mes,1,dias)= año(mes,dias) next next ' si queremos reasignar los datos nuevos... for mes= 1 to 12 for semana= 2 to 4 for dias= 1to 7 prov(mes,semana,dias)= true next next next ' finalmente la matriz se la entregamos a la matriz de uso público aquí prov es privada para la función cuyo cometido exclusivo (de la función) podría ser éste año= prov ' año toma tanto los datos como las diemsniones,
Esto (lo anterior) supone una molestia porque se necesita crear una función específicamente para esto, por eso la solución que expone Moskito debe tenerse en consideración. Otra solución es la que te presento a continuación, que trata de usar una matriz dinámica unidimensional oculta, el sistema utilizado para localizar el valor es similar a como se hace a bajo nivel, pero de cara a usarlo repetidamente es más cómodo que utilizar una matriz de varias dimensiones que además se prestan mucho a confusión. De hecho cuand se usan más de 2 dimensiones interesa más tener un estructura de este tipo. De hecho con poco más lo puedes convertir en una clase Redimensionar la matriz equivale a asignar a la propiedad año un nuevo valor. Y tomar el valor de ún índice equivale a usar la propiedad DiaX donde se le pasan los indices de cada dimensión mes,semana y dia que se utiliza para calcular el índice de la matriz valores. public type infoAño Meses as byte Semanas as byte Dias as byte end type private p_Año as infoAño ' la matriz es unidimensional, es ella quien guarda todos los elementos y somos nosotros quienes proveemos la dirección de cada elemento. Private valores() as boolean ' pregunta por los índices que tiene cada 'dimensión' friend property get Año( optional preservar as boolean=false) as infoAño año= p_año end property ' redimensiona la matriz privada con los nuevos valores de las diemsniones friend property let Año( optional preservar as boolean=false, byref nAño as infoAño) if preservar=false then redim valores(0 to (nAño.meses * nAño.seamanas * nAño.dias ) - 1) else ' invocar a una función que resguarde valores actuales .. queda como ejercicio para el interesado, ' esto puede ser en parte similar a la función del código anterior pero debería usarse un select case para ver que 'dimensiones' son las que varían end if p_año= nAño next public property get DiaX(byval Mes as byte, byval Semana as byte, byval Dia as byte) as boolean diaX= valores((mes-1) * 28) + ((semana-1) * 7) + dia - 1) end property public property let DiaX(byval Mes as byte, byval Semana as byte, byval Dia as byte, byval v as boolean) valores((mes-1) * 28) + ((semana-1) * 7) + dia - 1)= v end property ' sobrecarga, llama a la propiedad, pero recibe como parámetro una estructura.... friend function GetDiaX(byref fecha as infoAño) as boolean GetDiaX= diax(fecha.meses, fecha.semanas,fecha.dias) end function friend sub SetDiaX(byref fecha as infoAño) diax=(fecha.meses, fecha.semanas,fecha.dias) end function
nota: el código está escrito directamente quizás se haya escapado algún error nota2: para los que se toman todas las palabras al pie de la letra... el hecho de utilizar variables llamadas mes, semana ,etc... sólo tiene por objeto no perderse en detalles por trabajar con objetos de naturaleza abstracta, si un ejemplo se explica con algo conocido resulta más fácil ver lo que se quiere explicar sin perderse en la naturaleza del objeto de ejemplo si fuera bastracto, por tanto en ejemplos de este tipo sólo interesa la didáctica. Como todo el mundo sabe como el año no tiene períodos regulares lo que supuestamente se utiliza para el cálculo en el ejemplo no tiene nada que ver con el cálculo real de fechas, si a alguien le confunde, sustituye mes, semana, dia y año por nombres cualquiera de variables.. En todo caso haz unas pruebas de rendimiento con cada método si tienes que hacer un uso intensivo para decidir el que más convenga... si no hay un uso intensivo y por tanto el rendimiento no es decisivo, elige el que más cómodo te resulte.
260
« en: Domingo 24 de Mayo de 2009, 03:47 »
Será que sabes utilizar el buscador del foro y que vas a utilizarlo ?.
261
« en: Domingo 24 de Mayo de 2009, 03:32 »
Qué tal te manejas con el inglés... ?
262
« en: Domingo 24 de Mayo de 2009, 03:31 »
Utiliza el buscador, en el foro hay bastantes temas sobre el control MSComm... léelos y tendrás más claro qué y cómo proceder... usar input no es la mejor idea... usa el buscador...
263
« en: Domingo 24 de Mayo de 2009, 03:28 »
Limitar el tamaño del formulario está bien, no sólo porque en un determinado caso resulte adecuado si no también por que es absurdo reducir un formulario hasta un tamaño cuyo contenido es impracticable.
Lo que no está nada bien es fijar un formulario en una posición determinada. Personalmente odio las aplicaciones que tratan de limitar la libertad al usuario con cosas absurdas como fijar una posición que al programador le trae sin cuidado pero no al usuario. Una cosa es que cuando un formulario aparezca se coloque centrado en la pantalla y otra muy distinta es que no se pueda mover. Y como usuario cuando me encuentro dichas aplicaciones lo que intento es remplazarlas por otras que no me coarten la libertad de ver otra ventanita que dichosamente también se abre centrada en la pantalla pero que no la veo precisamente porque esa tonta ventana la tapa y no puedo moverla.
También personalmente encuentro más útil centrar una nueva ventana que aparece, sobre la ventana principal de la aplicación no sobre la pantalla y sólo centro sobre la pantalla, la ventana principal de la aplicación cuando se carga...
Que ganas con centrar una ventana contínuamente sobre la pantalla... te dan algún premio ? ... peinso que quizás el de cosas idiotas, más no creo. quién impulsará tales tonterías?. Deja que el usuario mueva la ventana donde le dé la gana.
264
« en: Lunes 18 de Mayo de 2009, 13:00 »
Lo tienes prácticamente bien... ' en el form frmnuevo ' las propiedades max y min deberían limitarse para que se obtenga un número mínimo y máximo de columnas, tener 100.000 columnas no tiene sentido. private sub NudSa__ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NudSa.ValueChanged call LlenaColumna(NudSa.value) end sub ' en el 'otro' formulario...que lo quieres usar public Sub LlenaColumna(byval Columnas as integer) Me.LsvZ.Columns.clear ' borramos las que tenía previamente, si no con cada llamada el número aumenta. For i as integer= 0 To Columnas -1 ' porque de 0 a 10 hay 11 elementos, no 10 Me.LsvZ.Columns.Add("C" & i.tostring) Next End Sub
No obstante el problema que tu tienes se remite a que no identificas claramente como trabaja el listview, para empezar para poder ver el nº de columnas es necesario establecer la propiedad view a 'Details', ya que el control listview está diseñado par apoderse utilizar en diferentes situaciones, en tu caso esa situación es 'details'... Luego debes entender que dentro de un listview hay varias colecciones, las columnas sólo son las cabeceras 'posibles que queremos mostrar, podemos fijar 5 columnas y sin embargo por 'detrás' tener 20. Para manejar las filas como un todo, debemos usar la colección items, y para manejar las 'columnas' en cada iten debemos trabajar con la colección subitems, como los subitems pertenecen a un item concreto puede resultar confuso hasta que se entienda como trabaja. Para ello te he elaborado el siguiente código, que espero te ayude a entender mejor el control listview. Nota que para entenderlo adecuadamente debes ejecutarlo paso a paso, y para que puedas ir viendo los resultado sobre la marcha en el formulario (pon aun lado del monitor el código y a otro el formulario de modo que ambas partes queden a la vista, si el monitor es estrecho, entonces distribúyelo verticalmente, pero ambos deben estar a la vista al mismo tiempo) he provisto en el código varias línas que actualizan la vista del formulario, de modo que puedas ver el cambio efectuado en cada 'acción'. Recuerda que las líneas 'System.Windows.Forms.Application.DoEvents()' sólo tienen aquí sentido para poder referescar la imagen mientras estás ejecutando paso a paso el código, para una ejecución normal hay que comentarlas o eliminarlas. Public Class Form1 ' establecemos el tipo de vista que necesitamos, nuestro caso es detalles Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ListView1.View = View.Details ' si no no se verán las columnas End Sub ' actualizamos al número de columnas elegido. Private Sub NumericUpDown1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NumericUpDown1.ValueChanged Call LlenaColumna(sender.value) End Sub ' creamos 10 items por cadacolumna para ilustrar el ejemplo. Public Sub LlenaColumna(ByVal Columnas As Integer) Dim nuevaSubIt() As Windows.Forms.ListViewItem.ListViewSubItem ' borramos las que tenía previamente, si no con cada llamada el número aumenta. Me.ListView1.Columns.Clear() Me.ListView1.Items.Clear() System.Windows.Forms.Application.DoEvents() For Col As Integer = 0 To Columnas - 1 ' porque de 0 a 10 hay 11 elementos, no 10, restamos 1 Me.ListView1.Columns.Add("Columna" & Col.ToString, 120) ' texto y ancho ' si la columna ya fue creada podemos usar estas otras líneas para modificar esos valores ' ListView1.Columns(Col).Text = "Columna" & Col.ToString ' texto de la columna ' ListView1.Columns(Col).Width = 120 ' ancho de la columna Next System.Windows.Forms.Application.DoEvents() ReDim nuevaSubIt(0 To Columnas - 1) For It As Byte = 0 To 9 ' 9 itemes Me.ListView1.Items.Add("Item" & It.ToString) ' columna 0 System.Windows.Forms.Application.DoEvents() For Col As Integer = 1 To Columnas - 1 nuevaSubIt(Col) = New Windows.Forms.ListViewItem.ListViewSubItem(ListView1.Items(It), "Item" & It.ToString & "_Columna" & Col.ToString) ' si ya han sido creado los subitems, usaríamos esta línea 'Me.ListView1.Items(It).SubItems(Col).Text = "Item" & It.ToString & "_Columna" & Col.ToString Next Me.ListView1.Items(It).SubItems.AddRange(nuevaSubIt) System.Windows.Forms.Application.DoEvents() Next End Sub End Class
El código no está optimizado, ten en cuenta que en cada cambio de columnas, lo borra todo y lo rehace de nuevo, un caso acertado es trabajar sólo con la diferencia de columnas entre la actual y la seleccionada, esto es si ahora tengo 15 columnas y luego marco 12, todo lo que tendría que hacer es eliminar las últimas 3 columnas, en cambio si ahora tengo 7 columnas y luego marco 13 lo que se debería hacer es añadir las 6 nuevas columnas, dejando intactas las existentes... pero esto es ya ejecrcicio para ti, la base ya la tienes.
265
« en: Domingo 17 de Mayo de 2009, 13:26 »
en la variable dr se asigna un DataReader eso es todo.. Gracias por tu ayuda..!!!
Saludos Mauricio Bueno al decir que tipo, esperaba que pusiersa la declaración, al final del post te digo por qué ... De entrada puedes hacer un rendimiento más óptimo al bucle si conoces el tipo de datos que tratas de recuperar. el datareader recupera los datos como objetos, por ello luego debes hacer una conversión al tipo deseado utilizando .ToString . si sabes que es un String y un integer invócalos de esta manera: dr.gestString("SPROY_NOMBRE") dr.GetInt32("CTO_ID")
Con ello se ahorra la conversión desde object al tipo de datos que es. Otra mejora que puedes hacer es que si conoces la posición del campo dentro de la tabla te refieras con su índice en vez de con su nombre. Esto tiene una desventaja que es preciso conocer, si en un futuro haces modificaciones en la tabla y el campo 'SPROY_NOMBRE' antes era (pongamos) el campo nº 2 y ahora es el campo nº 3, no nos devolverá lo que esperamos... Por contra sucede la inversa, si en un futuro cambiamos el nombre del campo 2 que antes se llamaba 'SPROY_NOMBRE' y ahora se llama 'NOMBRE_SPROY' , no lo encontrará pero todavía si lo encontraría referenciando el campo 2. en fin esto son decisiones que deben tomarse cuando uno diseña y debe decidir si hay cambios en un futuro como serán los cambios, añadir, quitar,reordenar campos ? o incluso cambiar nombres de campos.. ? Esto se haría del siguiente modo: dr.gestString(2) ' el campo eneavo que le corresponda. dr.GetInt32(6) ' por poner un ejemplo...
Sin embargo con esto sólo se consiguen mejoras no muy significativas (para el problema que supuestamente tu tienes). Me temo que el problema lo tienes en la propia declaración del DataReader, qué es lo que realmente quería ver cuando te solicitaba que tipo de datos era dr, el nombre lo sugiere (aunque prefiero verificarlo), sin embargo esperaba que pusieras la declaración. Ponme la declaración de la línea: dim dr as sqldatareader = Command.Execute....( .... )
Es con esto (dr= command.Exec....) , con lo que pudo confirmar mis sospechas e indicarte la solución.
266
« en: Domingo 17 de Mayo de 2009, 11:27 »
No se necesita ser ningún experto, si alguien te dice coge una lechcuga y pártela en 4 trozos, creo que es algo que salvo un manco todo el mundo puede hacer (y aún ese, seguro que lo intenta o se las ingenia de algún modo para intentarlo)... No tengas miedo de poner 4 líneas, en el código, probando también se aprende, si alguien dice a y b son 5, y no entendí pués uno puede probar a= b and 5 , b= a and 5 , 5= a and b .... no se va a romper nada por ello... y así no dependes de que vuelvapor aquí para decirte algo más concreto. dim RutaApplica as string RutaAplica= My.Application.Info.DirectoryPath messagebox.Show RutaAplica
Si dentro de la aplicación tengo una carpeta con imágenes que se llama 'Imágenes' y dentro de esta otra que se llama 'Tarjetas' (lo siento veo estúpido llamar a una carpeta cards si tu idioma es el español), entonces puedes conectar la ruta... dim RutaTarjetas as string RutaTarjetas = RutaAplica & "ImágenesTarjetas" messagebox.show RutaTarjetas
Durante la carga del programa debemos comprobar que la carpeta "..ImágenesTarjetas", existe y si no existe habrá que decidir hacer, si pedir al usuario que localice la ruta, o crearla nuevamente (si puede ser una ruta vacía) o finalizar el programa si resulta imposible determinar o hallar determinado contenido necesario, informando oportunamente al usuario para que lo reponga o reinstale (el programa, si el contenido no puede ser repuesto desde otro origen)... Para que no te idiotices con otra pregunta absurda con la excusa de no ser un experto, ya te indico que donde he puesto 'RutaTarjetas' , es donde tu tienes puesto 'Module1.ResourceFilePath' , tal que usando RutaAplica, no necesitas un condicional para especificar la ruta (que apuntará siempre al mismo sitio tanto si estás en modo diseño como en ejecución una vez compilado) ...
267
« en: Jueves 14 de Mayo de 2009, 16:32 »
Esta pregunta está respondida en parte aquí: viewtopic.php?f=53&t=38826 Sin embargo hay otras razones... Sstituye la froma de referirte a la ruta que usas actualmente por esta otra forma: Para las rutas referidas a la aplicación usa mejor My.Application.Info.DirectoryPath y luego le sumas el trayecto hacia los archivos dentro de esa ruta. La razón es que .Starttuppath... refiere incluso al arranque desde un acceso directo... Si el error persiste, vuelve, con el error y la ruta que te da ... Y por supuesto sería muy útil, que colocaras la ruta completa donde tienes la aplicación ejecutándose... y donde tienes el proyecto de desarrollo.
268
« en: Jueves 14 de Mayo de 2009, 16:22 »
he buscado en la web la manera de encriptar la clave a un login, pile con el SHA1, todo ok.
Pero ahora, necesito su ayuda ya que no se como hacerlo, que para cuando en el login ponga la clave y este lo lea para poder ingresar al form. lo estoy haciendo en VBnet 2003.
esta es el codigo para encriptar la clave.
' Convertir los valores en hexadecimal ' cuando tiene una cifra hay que rellenarlo con cero ' para que siempre ocupen dos dígitos. Dim sb As New StringBuilder For i As Integer = 0 To result.Length - 1 If result(i) < 16 Then sb.Append("0") End If sb.Append(result(i).ToString("x")) Next ' Return sb.ToString.ToUpper
Al llegar aquí me pierdo y no se qué pretendes hacer... Veamos ...: 1º ) porqué necesitas convertir los datos a Hexadecimal ... ? lo requiere una operación futura ?, es algo que has decidido añadir tú para hacer posteriores operaciones ? 2º ) porqué haces: 'if result(i) <16 then... ' ? se supone que result ofrece una cadena de caracteres alfanuméricos o de caracteres hexadecimales ?. si la cadena devuelta es alfanumérica, entonces result(i) podrá ser arbitrariamente "v", "K", "-", "4", etc... por tanto cuando le pides '< 16' siempre dará TRUE, con lo que el resultado para una cadena codificada pongamos por comodidad que la cadena resul fuera 'Guay30' el resultado de ese bucle sería el sigiente: G0XU0XA0XY0X30X00X ... que dudo mucho sea lo que realmente quieras conseguir. En cambio si la cadena es hexadecimal, lo veo peor, porque tu no tendrás forma de saber si: 456FA21BBC es de la forma siguiente (en orden inverso) CB B1 2A F6 54 o si es C... le añades un '0' o la 'B' y luego si es C0, lo siguiente será BB ó B0, pero si fuera CB lo sigiuente sería B1 o nuevamente sólo B... no lo veo Creo que el error lo cometes previamente, pero en fin si me aclaras esto sabré donde quieres ir a parar y corregirte desde donde te equivocas. Además en es bucle encuentro de entrada 2 errores, en que añades el '0' detrás es decir que si tenemos 9, en vez de convertirlo a 09 lo estás conviertiendo en 90.... y otro es que si una cadena la evaluas como un número debes tener presente que los nº se leen de derecha a izquierda, es decir la cadena: 'RADIO' , primero leemos la R y al final la O, pero si tenemos una cadena como '23456, y queremos operar con ella tratándola como número dbemos considerar que la 1ª cifra es el 6 y la última el 2.... Pero que te quede claro que éste no son los únicos peros... responde mis preguntas una a una y podré darte indicaciones...
269
« en: Jueves 14 de Mayo de 2009, 15:54 »
''Cargo mi dr con los datos con el sql respectivo Do While dr.Read() Att. Mauricio Podrías especificar que tipo de objeto es 'dr' ? , a ti te parece obvio, pero yo tengo que jugar a adivinar... Una vez me lo aclares, podré confirmar si es lo que me temo... y darte alguna indicación para solventarlo.
270
« en: Jueves 14 de Mayo de 2009, 15:39 »
Por qué abres otro hilo ?...
Por qué no estudias un poco más ?.... el error es tan tonto que casi ni merece la pena responderte.
Si la declaración de una función requiere 2 parámetros debes proporcionarle 2 parámetros, ni 1 ni 4.
Además es bastante obvio si miras la función. si tu quieres cambiar el nombre a algo requiere como mínimo 2 parámetros: Uno el nuevo nombre y otro el nombre actual (o una referencia al objeto), sino como cojones va a saber a quien quieres cambiarle el nombre ?
La devolución como en muchos otros casos te informa de si el cambio tuvo éxito o no...
271
« en: Jueves 14 de Mayo de 2009, 11:13 »
... ten en cuenta que SDL te permite crear rectangulos con una simple funcion, dandole los parámetros de estos y la posición donde dibujarlo. Que yo sepa todos los lenguajes permiten crear un rectángulo con una simple función dándole los parámetros... Y un sencillo juego de tablero (al hablar de sencillez me refiero a los gráficos) no necesita ninguna librería especial para poder realizarse, si todavía pretendiera darle animación en tiempo real...
272
« en: Jueves 14 de Mayo de 2009, 10:54 »
Un bucle se compone de 4 'partes': Inicio del bucle, final del bucle, condición de salida/retención y código interno al bucle. Entonces como puedes ver, no hay forma más corta de expresar 4 ideas que expresando las 4 ideas. Esto s como un vaso, puede tener o no asa, pero si tiene asa puede cogerse mejor pero ya es una jarra no un vaso. Si un bucle DO sólo ha de ejecutarse como mucho 1 sóla vez podría ser sustituído por un bloque if ... end if, pero también un bloque if se compone de 4 partes (el bloque más sencillo): Inicio del bloque if, final del bloque if, condición, código interno si cumple la condición... Aunque el inicio de un bloque (o el final ) se le una la condición realmente siguen siendo 4 partes, pero si alguien quiere considerarlo unido e indicar que son 3 partes, no es materia de discusión, pués sólo son formas de entender una misma cosa.
Ahora si con 'corta' quieres decir otra cosa... piensa que una cosa es el lenguaje de 'expresión' y otra cosa lo que el compilador escribe finalmente, entonces no debe preocuparte que si las instrucciones fueran : "IniciarBucleCondicional .... MientrasLaSiguientecondiciónSeCumpla" aunque esto sea más largo que "Do ... loop while" al compilar serían las mismas instrucciones... Un código VB ligeramente más largo no necesariamente genera un compilado más largo, es decir no te bases en la cantidad de palabras escritas para deducir que un determinado código será más breve y rápido cuando se compile que uno equivalente con 2 palabras más.
273
« en: Miércoles 13 de Mayo de 2009, 21:22 »
...Estás muy verde. dim poses as integer dim Actual as integer Actual=poses do '...código loop while Actual = poses ' o también ' loop until actual <> poses
El valor que tome poses es irrelevante... dentro del bucle tiene que haber código que directa o indirectamente modifiquen el valor de poses, de lo contrario tendrás un bucle infinito. Actual tiene un sentido local al procedimiento, en tanto que poses podría tener un ámbito mayor (si fuera necesario).
274
« en: Miércoles 13 de Mayo de 2009, 13:37 »
Después que leas a Moskito, quizás te parezca que no ha respondido exactamente a tus dudas, pero si lo que lo ha hecho, lo que pasa es que quizás no te lo haya explicaco bien, ypor eso pueda darte esa impresión. Renombrar una variable no es posible porque su nombre es una propiedad de sólo lectura durante la ejecución. Por ejemplo el siguiente código da error en text1.name = .... Private Sub Command1_Click() Dim nombre As String Dim c As Control nombre = Text1.Name Text1.Name = Text2.Name ' <-------------------- aquí dará error.... Text2.Name = nombre & "Cambiado" For Each c In Me.Controls msxgbox c.Name Next End Sub
Sin embargo eso no supone ningún problema... imagina Juan (que es un nombre tiene una mujer, una casa y un coche, pero no cualquier mujer ni casa ni coche, si uno una mujer específica y concreta, idem para el coche y la casa... Desafortunadamente a Juan le persigue la policía el ve como solución cambiarse el nombre y lo hace y ya está sigue teneidno su mujer su casa y su coche, sólo cambió su nombre. En programación esto también se puede hacer pero indirectamente, se llama asignación te pongo un ejemplo: Private Type Persona Mujer As String Casa As Integer Coche As Long End Type Dim Juan As Persona Dim Pedro As Persona Private Sub Command1_Click() Me.Cls Me.Print "La identidad de juan es, Mujer: " & Juan.Mujer & " Casa= " & Juan.Casa & " Coche: " & Juan.Coche Me.Print "La identidad de Pedro es, Mujer: " & Pedro.Mujer & " Casa= " & Pedro.Casa & " Coche: " & Pedro.Coche Me.Print: Me.Print "Ahora cambiamos identidad, juan será pedro, y por tanto juan ya no tendrá ni mujer ni casa ni coche..." Call CambiarIdentidad(Pedro, Juan, True) Me.Print "La identidad de juan es, Mujer: " & Juan.Mujer & " Casa= " & Juan.Casa & " Coche: " & Juan.Coche Me.Print "La identidad de Pedro es, Mujer: " & Pedro.Mujer & " Casa= " & Pedro.Casa & " Coche: " & Pedro.Coche MsgBox "Observa los cambios... Cuando cierres este mensaje se cerrará la aplicación." Unload Me End Sub Private Sub Form_Load() Me.AutoRedraw = True Juan.Casa = 12 Juan.Coche = 2500 Juan.Mujer = "Teresa" End Sub ' p1 es la persona que recibe una nueva identidad ' p2 es la identidad que se 'ofrece'... Private Function CambiarIdentidad(ByRef p1 As Persona, ByRef p2 As Persona, Optional ByVal Vaciarp2 As Boolean = True) Dim p3 As Persona If Vaciarp2 = False Then p3 = p1 End If p1 = p2 p2 = p3 End Function
¿Hay alguna forma de que yo pueda hacer esto?,.... Lo anterior (el código) qué quiere decir ?... que lo que se hace es una signación del valor de una variable a otra, la que recibe la signación 'toma plenos poderes' de la identidad del que se le asigna, para que hablemos de un cambio total de nombre, sería acorde anular la identidad del que 'dona' su identidad... como esto puede ser o no necesario nunca se hace en programación que esto ocurra por defecto, por eso en programación si no destruimos al dona la identidad o si no le quitamos su identidad a otra diferente, podemos hablar de 'clones' de identidad. en el mundo no hay 2 personas que llamándose iguales tengan la misma casa, la misma mujer y el mismo coche, en programación esto no supone ningún problema. Por tanto cuando quieras cambiar el nombre de una variable, simplemente usa otra a la que le asignes su 'identidad' (valor ), si necesitas seguir llamándola de la misma forma, ya no le estás cambiando el nombre si sin enbargo necesitas poder referirte a la misma entonces haz como te señala Mosquito, usa una matriz o cualquier otro contendor de variables... objeto colection, etc... Le hice la misma pregunta al profesor de la Universidad, pero lamentablemente no me supo responder. Al pronto quizás no entendió adónde querías ir a parar, pero a buen seguro que sabe que el nombre de una variable es de sólo lectura después de creada. cuando una variable se crea, internamente el nombre se alamacena en un espacio del programa reservado a los identificadores, el nombre en sí es lá intermediación entre la memoria y nuestra inútil capacidad para recordar posiciones de mmmemoria que cambian con una velocidad que no poddríamos seguir... si por ejemplo nuestra variable se guarda en 5634B89 y un instante después se guarda en 345678 no seríamos capaces de identificar ni recordar donde está y qué era... Entonces por eso existen los nombres de variables, para que no tengamos que recordar donde se encuentra un dato. cuando lo referenciemos, internnamente se localiza entre la tabla de identificadores la variable que hemos nombrado si existe recupera un valor que tiene, dicho valor es la posición en memoria, si cambia la posición de memoria, localiza al identificador en la tabla y actualiza la posición, de un modo transparente para nosotros. Ahora vamos a trabajar con posiciones de memoria de nuestras variables, verás que sería un coñazo sólo tener que usar (no ua recordar ) dichas posiciones... Hemos variado ligeramente el código anterior... observa las diferencias que son añadidos al ejecutar el código en la ventana aparecerán 2 lineas más con números que son posicion y punteros a posiciones de memoria. Private Type Persona Mujer As String Casa As Integer Coche As Long Perro As Boolean End Type Dim Juan As Persona Dim Pedro As Persona Private Sub Command1_Click() Me.Print VarPtr(Juan) & vbTab & VarPtr(Juan.Mujer) & vbTab & VarPtr(Juan.Casa) & vbTab & VarPtr(Juan.Coche) & vbTab & VarPtr(Juan.Perro) Me.Print "La identidad de juan es, Mujer: " & Juan.Mujer & " Casa= " & Juan.Casa & " Coche: " & Juan.Coche & " Juan tiene perro: " & IIf(Juan.Perro = True, "si", "no") Me.Print "La identidad de Pedro es, Mujer: " & Pedro.Mujer & " Casa= " & Pedro.Casa & " Coche: " & Pedro.Coche & " Pedro tiene perro: " & IIf(Pedro.Perro = True, "si", "no") Me.Print: Me.Print "Ahora cambiamos identidad, juan será pedro, y por tanto juan ya no tendrá ni mujer ni casa ni coche..." Call CambiarIdentidad(Pedro, Juan, True) Me.Print VarPtr(Juan) & vbTab & VarPtr(Juan.Mujer) & vbTab & VarPtr(Juan.Casa) & vbTab & VarPtr(Juan.Coche) & vbTab & VarPtr(Juan.Perro) Me.Print "La identidad de juan es, Mujer: " & Juan.Mujer & " Casa= " & Juan.Casa & " Coche: " & Juan.Coche & " Juan tiene perro: " & IIf(Juan.Perro = True, "si", "no") Me.Print "La identidad de Pedro es, Mujer: " & Pedro.Mujer & " Casa= " & Pedro.Casa & " Coche: " & Pedro.Coche & " Pedro tiene perro: " & IIf(Pedro.Perro = True, "si", "no") MsgBox "Observa los cambios... Cuando cierres este mensaje se cerrará la aplicación." Unload Me End Sub Private Sub Form_Load() Me.AutoRedraw = True Juan.Casa = 12 Juan.Coche = 2500 Juan.Mujer = "Teresa" Juan.Perro = True End Sub ' p1 es la persona que recibe una nueva identidad ' p2 es la identidad que se 'ofrece'... Private Function CambiarIdentidad(ByRef p1 As Persona, ByRef p2 As Persona, Optional ByVal Vaciarp2 As Boolean = True) Dim p3 As Persona If Vaciarp2 = False Then p3 = p1 End If p1 = p2 p2 = p3 End Function
Verás que las direcciones de memoria de una estructura están una contniuación de la otra, esto es así para calcular fácilmente (ubicar y reubicar) la posición absoluta de un campo de la estructura como un valor relativo respecto del valor absoluto de la estructura. Fíjate que hay 4 bytes de diferencias, la razón es que ni siquiera son los valores reales a los datos, sino punteros a los valores reales, por eso ves que si un string tiene 6 caracteres no podría ocupar la misma posición que si tuviera 20 caracteres, esto supondría modificar y reordenar el resto de campos de la estructura, eso se evita precisamente con los punteros, sólo se toca el lemento deseado, el cáclculo es más o menos: posición de memoria de la variable juan + (orden del campo a localizar * 4) por ejemplo casa sería mujer + 4, así preguntarle por Juan y preguntarle por Juan.mujer nos señala la misma posición... Un último cambio, el campo mujer modifícalo ahora por este otro: ahora cuando ejecutes el código verás que la dirección de mujer ya no sólo no coincide con la de la estructura sino que se aleja bastante del resto... además ahora la posición que se indica para Juan.Casa es juan + 20 Lo dejo a tu sagacidad ver si tratas de entender que ha pasado.... Bueno, aunque parezca que esto no tenga nada que ver con tu pregunta orgininal, la respuesta es que sí, todo se basa en el control de la memoria, por tanto teorícamente sería posible localizar la tabla de símbolos encontrar el nombre de una variable y sustiruir el valor de la misma por los que a uno le diera la gana, sin embargo el 'sistema' lo interpretarñia como una vioación de acceso, es decir se supone que si se cambia el nombre de una variable posiblemente el código quede inutilizado y el propio 'sistema' tenga dificultades para interpretar el nombre por no decir que se habrían saltado los controles de verificación acerca del nombre... está duplicado ?, su tamaño está dentro de los límites ?, utiliza caracteres prohibidos ?, utiliza el nombre de una palabra clave del lenguaje que luego se interprete mal ?.. el compilador realizará conversión de nombres de variables, para optimizar espacio ?... estas y otras razones que te puedes imaginar son las razones por las que el nombre de las variables son de sólo lectura... Espero que te resulte útil para entender detalles que seguro no te explicarán en ningún lado (por lo general).
275
« en: Miércoles 13 de Mayo de 2009, 12:14 »
Cuando quieres borrar una pizarra, qué es lo que haces ?.... Quitas lo que hay encima dejando lo que está debajo. Pero qué pasa cuando hay 2 'capas' es decir que no queremos llegar a la pizarra...? , que hay que restaurar lo que estaba debajo. Para lograr esto se necesita 'saber' que había debajo, es decir tenemos que tener guardado de alguna manera lo que había debajo para poder consltarlo y a partir de elló reconstruirlo. Hay varias formas unas más cómodas que otras , unas más complejas que otras y unas más costosas que otras... a ) Por ejemplo lo más cómodo sería usar alguna librería que ya hiciera eso, pero quizás no sea fácil de adquirir, de usar o de aprender a usar, o simplemente la licencia de uso tiene consideraciones que no entran en nuestros propósitos respecto del proyecto que estemos haciendo. b ) Casi lo más sencillo de hacer utilizando 4 líneas de código ( lo mas sencillo se describe 2 puntos más abajo pero necesitas explicaciones de este punto y el siguiente) , pero para obtener resultados buenos debes entender como opera si no te romperás la cabeza y sólo darás vueltas y vueltas... El código que te expongo ahora va en esa dirección... Crea una nueva aplicación, añade 2 botones y un picturebox, carga desde diseño una imagen al picturebox, copia el código (de más abajo) , ejecútalo... los dos botones dan 4 combinaciones posibles en función del orden pulsado, por tanto podrás observar 4 situaciones diferentes del gráfico. Prueba a hacer cambios, si lo entiendes mo necesitarías más ayuda... Const ini = 100 Dim iniX As Integer Dim iniY As Integer Private Sub Command1_Click() For k = 0 To 29 Picture1.Line (iniX, iniY)-(iniX, iniY + 300), 16777215 - vbRed ' quiero poner rojo, pero como utilizo el 'XOR'... iniX = ini + (k * 20) Next End Sub Private Sub Command2_Click() iniX = 100: iniY = 100 For k = 0 To 29 Step 2 ' solo toca las líneas pares Picture1.Line (iniX, iniY)-(iniX, iniY + 20 + (10 * k)), vbBlue ' estas líneas van creciendo en longitud iniX = ini + (k * 20) Next End Sub Private Sub Form_Load() Dim img As IPictureDisp Me.ScaleMode = vbPixels iniY = 100 With Picture1 .AutoSize = True .AutoRedraw = True ' prueba a desactivar esta línea, y verás lo que ocurre... .Refresh .ScaleMode = vbPixels .DrawMode = vbXorPen .DrawWidth = 15 ' para ver mejor qué es lo que hace, lo normal es que vayas a utilizar 1 o 2... Set img = .Picture .Width = 700 ' bucle de 30 * 20 distancia entee líneas + 100 de ini=700, así quedan todas visibles... .Height = 500 ' 100 de iniy(margens superior) + 300 de alto de línea mayor, más 100 de margen inferior = 500 .PaintPicture img, 0, 0 .Picture = .Image End With Set img = Nothing End Sub
Personalmente me crearía una clase que contuviera una colección de estructuras de tipo 'Linea' con algunos métodos para manejar la colección y dibujar-ocultar ... c ) Puedes usar el control line, en vez del método line del contenedor, al efecto deberías crear una matriz de controles line, donde el primer control tiene índice 0, y no está visible... un botón debería indicar 'Crear nueva línea' y haces un load line(0) y luego un visible=true para esa línea, deberías tener un conjunto de controles para modificar el ancho, alto, posición horizontal y posición vertical , color... Luego a la gora de quitar líneas es un unload él control línea que sobra. Para guardar el resultado en vez de guardarlo como gráfico (esto depende de dónde y cómo lo vayas a usar después ) puedes guardarlo como un conjunto de estructuras de tipo línea que recogen las propiedades que la definen (x,y, dx ,dy , color.... visible ) nº de líneas ... es decir quedarían guardadas como un gráfico 'vectorial' no como un gráfico 'pintado' ... la ventaja es que podrías manipularlo fácilemtne en una nueva carga, por ejemplo escalnado, además actualizarlo sería más fácil si por ejemplo un día toda una cuadra de calles ahora es un único edificio, otra ventaja es el tamaño que ocupa en disco, bastante poco en comparación con una imagen de ANCHO x ALTO píxeles... si en cambio las quieres guardar como gráfico basta que cree un 2º picturebox oculto, con uaotredraw= true, y dibujas con picture2.line la serie de líneas que son visibles en el gráfico actual con las propiedades que tiene cada línea usando for each c in picture1.controls : if typeof(c) is line then... with c picture2.lines( .x , .y) - ( .x1, .y1), .backcolor ...etc... después hacees el picture2.picture= su image y luego salvas las imagen del picture2.... Este modelo es bastante más sencillo de hacer que el modo anterior, pués no tienes que preocuparte de lo que tienes que hacer para controlar cuando y como ocultar líneas en un momento dado, basta eliminarlas o hacerlas invisibles. d ) cualquier método que te permita recordar las lineas trazadas, al quitar líneas lo que harás será borrar el contenido gráfico y redibujar sólo aquellas líneas que se quieren dibujar. La diferencia de este modo con los 2 anteriores, es que requiere redibujar por completo todas las líneas 'válidas' si sólo son unos pocos cientos 8incluso miles) es rapido pero si hay decenas de miles castiga bastante al procesador con cada repintado... Los mértodos descritos anteriores permiten alterar sólo las líneas de interés las demás no habría porqué tocarlas ( en el código de ejemplo, se toca todo porque es de eso, de ejemplo, de hecho el código del botón 2 sólo toca las 'líneas' pares...). Este métod tiene la ventaja de que es el más sencillo de programar, porque no necesitas saber ni entender como funciona la transparencia, simplemente borras todo y trazas de nuevo. con todo necesitas tener que 'recordar' las líneas que se han dibujado, para reconsruirlo. Luego hay otras formas un poco más o menos complejas... pero que no vamos a entrar en detalles, porque si no tienes cierto nivel mínimo de programación (en vb6 por lo menos) te iba a ser muy costoso realizarlo...
Páginas: 1 ... 9 10 [11] 12 13 ... 29
|
|
|