Iconos y la excepción DivideByZero

Tengo un cuadro de lista dibujado por el propietario que contiene una lista de estructuras que representan los elementos. Esta estructura tiene dos propiedades, un icono y una cadena para mostrar. Ha funcionado bien para mostrar iconos pequeños, 16x16 y más o menos. Sin embargo, traté de adaptar este cuadro de lista para mostrar imágenes de una carpeta y tuve algunos errores inexplicables.

public static System.Drawing.Icon BitmapToIcon (System.String String_Bitmap, System.Drawing.Icon Object_Default)
{
    try
    {
        //return System.Drawing.Icon.FromHandle(((System.Drawing.Bitmap)(System.Drawing.Bitmap.FromFile(String_Bitmap))).GetHicon());
        System.IO.Stream s = new System.IO.MemoryStream(System.IO.File.ReadAllBytes(String_Bitmap));
        System.Drawing.Bitmap b = ((System.Drawing.Bitmap)(System.Drawing.Bitmap.FromStream(s, true, true)));
        System.Drawing.Icon i = System.Drawing.Icon.FromHandle(b.GetHicon());
        s.Close();
        b.Dispose();
        return i;
    }
    catch
    {
        return Object_Default;
    }
}

en otra parte:

BitmapToIcon("D:/pictures/picture001.jpg", null);

El directorio tiene alrededor de 400 imágenes de todas las formas y formatos, pero solo unas 60, espaciadas aleatoriamente, aparecen en el cuadro de lista. En ListBox.DrawItem(), Graphics.DrawIcon() lanza una función DivideByZero. Al atrapar la excepción, registra los íconos como 0x0. Obviamente, mi función está escrita para devolver un icono predeterminado (nulo en este caso) en caso de error.

Sé que el formato ICO de Windows tiene un límite de 256x256, pero eso no es lo que está sucediendo aquí, por lo que sé. Algunas de las imágenes que SÍ dibuja son mucho más grandes y tampoco son cuadradas. Además, todas las imágenes que no se cargan en una lista de 400 se cargan bien en una lista de 10. Pensé que tal vez GDI tenía demasiados identificadores o algo así, así que cambié la función para desechar mis mapas de bits de origen y agregué una declaración de suspensión. pero ninguno ayudó. Cambiar el cuadro de lista para usar mapas de bits en lugar de iconos solucionó el problema de dibujo, pero ahora consume mucha más memoria.

¿Hay alguna razón por la que GetHIcon() devuelva resultados tan extraños como este y qué puedo hacer al respecto?

preguntado el 22 de mayo de 12 a las 21:05

Lo haría ALTAMENTE recomiendo usar el Using ( declaración. -

Realmente no está claro dónde está el problema. No ha proporcionado el código que llama al método que lanza la excepción y no ha detallado si la excepción se lanza cuando intenta dibujar Object_Default o no. -

Peter, intenta leer la pregunta de nuevo. Declaré muy claramente que la excepción está siendo lanzada por Graphics.DrawIcon() en el DrawItem() de ListBox. -

privado void ICONLIST_DrawItem (System.Object Object_Sender, System.Windows.Forms.DrawItemEventArgs Object_Arguments) { RK.ICONLIST.RECORD Struct_Temporary = ((RK.ICONLIST.RECORD)(this.Items[Object_Arguments.Index])); System.Drawing.Rectangle Rectangle_Graphic = Object_Arguments.Bounds; try{Object_Arguments.Graphics.DrawIcon((Struct_Temporary.Graphic ?? this.SafeIcon), Rectangle_Graphic);} catch(System.Exception e){System.Windows.Forms.TextRenderer.DrawText(Object_Arguments.Graphics, e.Message); } } -

También Eric, probé la declaración de uso y no hizo ninguna diferencia. -

2 Respuestas

Ryan, Eric quiere decir que sería mejor usar la directiva using para evitar códigos como:

System.Drawing.Bitmap b = ((System.Drawing.Bitmap)(System.Drawing.Bitmap.FromStream(s, true, true)));

Después de refactorizar se vería así:

using System.Drawing.Bitmap;

Bitmap b = ((Bitmap)(Bitmap.FromStream(s, true, true)));

Es difícil leer el código que proporcionó. Intente usar la función Image.FromFile() para cargar su imagen o use el constructor Bitmap con el parámetro de ruta.

    Bitmap b = new Bitmap(String_Bitmap);
    Icon i = Icon.FromHandle(b.GetHicon());

contestado el 23 de mayo de 12 a las 05:05

El mapa de bits se deriva de la imagen abstracta, por lo que FromFile() debería hacer lo mismo. Realmente parece que Bitmap es más inteligente con los identificadores GDI que Icon. - ryan killian

Si el uso de mapas de bits tiene muchos recursos, intente implementar su cuadro de lista como un cuadro de lista virtual, donde la idea principal es mostrar solo los elementos visibles y dibujar otros solo si el usuario desplaza los elementos. Puede mostrar las fuentes del cuadro de lista para descubrir por qué requiere tantos recursos y cómo puede refactorizarlo para que funcione de manera adecuada y rápida. - Layko Andrei

Debe atrapar el error en su cláusula catch para ver qué tipo de excepción está causando que se devuelva el icono predeterminado.

Si nunca llamas DestruirIcono y llame a este método repetidamente, es posible que se esté quedando sin recursos de GDI.

También puedo sugerir que este código es equivalente a su código y un poco más fácil de leer:

    using ( var b = (Bitmap)Image.FromFile(String_Bitmap))
        return Icon.FromHandle(b.GetHicon());

Además, ¿por qué no cambia la estructura de su cuadro de lista para que funcione con mapas de bits en lugar de iconos y simplemente se deshace de este problema de iconos? :-)

contestado el 23 de mayo de 12 a las 14:05

Sí, probé alrededor de una docena de variaciones diferentes de BitmapToIcon(), muchas de las cuales incluían una llamada a DestroyIcon(), con casi la misma cantidad de efectos secundarios extraños. Uno parecería cargar todos los íconos solo para bloquearse aproximadamente 3/4 del camino hacia abajo con "no se puede acceder al ícono desechado" a pesar de que no había hecho nada de eso y otro devolvió 0x0 para todo. Encendí el contador GDI en TaskManager y absorbía más de 1000 identificadores para 400 íconos frente a aproximadamente 95 si usaba mapas de bits. - ryan killian

Cuando capturo la excepción en BitmapToIcon() obtengo "ocurrió un error GDI genérico". La búsqueda en línea dice que es una trampa para muchos errores, entre ellos identificadores con fugas, por lo que no es de mucha ayuda. - ryan killian

En cuanto a por qué no uso mapas de bits, es solo en parte por terquedad. Uno, uso BitmapToIcon() en algunos otros lugares para íconos reales de 16x16, y dos, si lo piensas bien, un cuadro de lista lleno de mapas de bits. debemos tienen los mismos problemas. Ambos son objetos GDI con identificadores dentro de una estructura a la que accedo a través de ListBox.Items[]. Por qué uno (BitmapListBox) funciona y el otro (IconListBox) se vuelve loco me supera. - ryan killian

Otra variación sí logró dibuje todos los íconos, pero realmente arruinó las vistas de árbol y los cuadros combinados en otras aplicaciones, lo que supongo que se debió al límite de manejo de GDI. Es como si el ícono .NET, como la fuente .NET, se implementara lo suficiente como para usarse ocasionalmente (como configurar un ícono de ventana), pero se convierte rápidamente en un desastre si realmente comienza a hacer algo serio con él. Supongo que, en lugar de cualquier otra alternativa, tendré que marcar "usar un BitmapListBox en su lugar" como respuesta... - ryan killian

Diablos, incluso probé una versión en la que mi estructura solo tenía un puntero al icono porque pensé que tal vez la copia de la estructura que salía de Elementos [] se recopilaba y su propiedad de icono se eliminaba. - ryan killian

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.