46 votes

Affichage d'icônes miniatures de 128x128 pixels ou plus dans une grille dans ListView

Question originale (voir mise à jour ci-dessous)

J'ai un programme WinForms qui a besoin d'un contrôle d'icône défilant décent avec de grandes icônes (vignettes 128x128 ou plus, vraiment) qui peuvent être cliquées pour les mettre en évidence ou double-cliquées pour effectuer une action. De préférence, il y aurait un minimum d'espace perdu (de courtes légendes de noms de fichiers pourraient être nécessaires sous chaque icône ; si le nom de fichier est trop long, je peux ajouter une ellipse).

finished version of listview with proper colors, spacing, etc.
(source : <a href="http://www.updike.org/images/listview-great.png" rel="nofollow noreferrer">updike.org </a>)

J'ai essayé d'utiliser une ListView avec LargeIcon (par défaut .View) et les résultats sont décevants :

screenshot showing tiny icons in LargeIcon view
(source : <a href="http://www.updike.org/images/listview-poor.png" rel="nofollow noreferrer">updike.org </a>)

Peut-être que je ne remplis pas correctement le contrôle ? Code :

        ImageList ilist = new ImageList();
        this.listView.LargeImageList = ilist;
        int i = 0;
        foreach (GradorCacheFile gcf in gc.files)
        {
            Bitmap b = gcf.image128;
            ilist.Images.Add(b);
            ListViewItem lvi = new ListViewItem("text");
            lvi.ImageIndex = i;
            this.listView.Items.Add(lvi);
            i++;
        }

J'ai besoin de grandes icônes avec peu d'espace vide, pas de grands espaces vides avec des icônes ridiculement petites.

  1. Existe-t-il un contrôle .NET qui fait ce dont j'ai besoin ?
    • Y a-t-il une commande tierce favorite qui fait cela ?
    • Si ce n'est pas le cas, quel serait le meilleur contrôle à hériter et à modifier pour que cela fonctionne ?
    • Devrais-je m'effondrer et faire un contrôle personnalisé (ce que je sais faire... mais je ne veux pas aller jusqu'à cet extrême puisque c'est un peu compliqué).

J'ai trouvé ce tutoriel sur OwnerDraw mais le travail à partir de cela revient essentiellement au numéro 3 ou 4 ci-dessus puisque cette démo montre juste comment pimenter les lignes dans la vue détaillée.

Mise à jour

Ajout de la ligne

ilist.ImageSize = new Size(128, 128);

avant la boucle for a réglé le problème de taille mais maintenant les images sont palettisées en 8 bits (on dirait des couleurs système ?) même si le débogueur montre que les images sont insérées dans l'ImageList en tant que 24bpp System.Drawing.Bitmap's :

large icons, finally
(source : <a href="http://www.updike.org/images/listview-poor2.png" rel="nofollow noreferrer">updike.org </a>)

  1. Comment faire pour que les images s'affichent en couleurs 24 bits ?
    • L'espacement autour des icônes est encore plutôt inutile... comment puis-je corriger cela ? Est-ce que je peux ?

Mise à jour 2

En plus d'ajouter la ligne

ilist.ColorDepth = ColorDepth.Depth24Bit;

Ensuite, après avoir réglé ilist.ImageSize, j'ai suivi les conseils d'arbiter et modifié l'espacement :

[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

public int MakeLong(short lowPart, short highPart)
{
    return (int)(((ushort)lowPart) | (uint)(highPart << 16));
}

public void ListView_SetSpacing(ListView listview, short cx, short cy)
{
    const int LVM_FIRST = 0x1000;
    const int LVM_SETICONSPACING = LVM_FIRST + 53;
    // http://msdn.microsoft.com/en-us/library/bb761176(VS.85).aspx
    // minimum spacing = 4
    SendMessage(listview.Handle, LVM_SETICONSPACING,
    IntPtr.Zero, (IntPtr)MakeLong(cx, cy));

    // http://msdn.microsoft.com/en-us/library/bb775085(VS.85).aspx
    // DOESN'T WORK!
    // can't find ListView_SetIconSpacing in dll comctl32.dll
    //ListView_SetIconSpacing(listView.Handle, 5, 5);
}

///////////////////////////////////////////////////////////

ListView_SetSpacing(this.listView, 128 + 12, 128 + 4 + 20);

Le contrôle ListView n'est peut-être pas parfait ou ne possède pas les valeurs par défaut auxquelles je m'attendais (comme une propriété d'espacement), mais je suis heureux d'avoir pu l'apprivoiser, au final :

alt text
(source : <a href="http://www.updike.org/images/listview-great.png" rel="nofollow noreferrer">updike.org </a>)

À propos, pour maintenir le bon rapport hauteur/largeur des vignettes, j'ai dû créer mes propres bitmaps 128x128, effacer l'arrière-plan pour qu'il corresponde au contrôle, et centrer ces images :

public void CenterDrawImage(Bitmap target, Color background, Bitmap centerme)
{
    Graphics g = Graphics.FromImage(target);
    g.Clear(background);
    int x = (target.Width - centerme.Width) / 2;
    int y = (target.Height - centerme.Height) / 2;
    g.DrawImage(centerme, x, y);
    g.Dispose();
}

2 votes

ComCtl32.dll ne possède pas ListView_SetIconSpacing (ainsi que toutes les autres fonctions ListView_x), car il ne s'agit pas de fonctions mais de simples définitions c++. En fait, ListView dans Vista a beaucoup de fonctions qui ne sont pas disponibles en .net sans une interopérabilité native massive.

1 votes

Je viens de rencontrer le même problème, merci beaucoup :D

14voto

arbiter Points 5503

Pour la mise à jour :

  1. Définir la profondeur de couleur de la liste d'images en plus de la taille de l'image (ilist.ColorDepth = ColorDepth.Depth24Bit)
  2. WinForms ListView n'a pas la possibilité de changer l'espacement des icônes, mais cela peut être fait facilement en utilisant Win32. Vous devez envoyer LVM_SETICONSPACING à votre ListView (il y a beaucoup de tutoriels sur l'utilisation de la fonction win32 SendMessage dans .net, donc je pense que cette direction doit être suffisante pour vous).

5voto

jvanderh Points 1845

Vous pourriez utiliser le FlowLayoutPanel et y déposer des boîtes à images. Définissez la taille de la boîte à images (128x128) et le mode de taille (sizemode) sur "zoom" (cela permet de redimensionner l'image sans perte de rapport hauteur/largeur). Vous pouvez même ajouter les boîtes à images par programme.

PictureBox pb = New Picturebox;
 pb.image = gcf.image128;
 FlowLayoutPanel1.Controls.Add(pb)

Puisque vous avez besoin d'une étiquette sous la boîte à images, vous pourriez créer un Usercontrol comme l'a dit Pastor, qui n'a qu'une boîte à images et une étiquette sous celle-ci. Ce serait alors l'instance de contrôle que vous ajouteriez à votre panneau d'affichage.

0 votes

Je pourrais essayer ceci. Le défilement libre (si tout va bien) et la mise en page sont ce que je veux. Le problème est qu'il faut que le défilement soit fluide.

0 votes

Vous pouvez contrôler la marge autour des boîtes à images (ou de votre contrôle) pour définir l'espacement dont vous avez besoin entre elles en utilisant la propriété Margin de chaque boîte à images.

0 votes

Après être devenu fou avec ça, j'ai fait quelques recherches et j'ai trouvé cet article intéressant : codeproject.com/Articles/20013/Image-Thumbnail-Viewer-with-NET

5voto

Grammarian Points 4085

ObjectListView (une enveloppe open source autour d'une ListView .NET) facilite le dessin personnalisé d'une vue en mosaïque. Jetez un coup d'œil à la vue complexe de la démo, et passez à la vue en mosaïque lorsque le dessin personnalisé est activé : owner drawn tile view
(source : <a href="http://objectlistview.sourceforge.net/cs/_images/tileview-ownerdrawn.png" rel="nofollow noreferrer">sourceforge.net </a>)

Si vous ne vouliez qu'une image de 128x128 et quelques détails textuels, vous n'auriez même pas besoin de la dessiner en tant que propriétaire. Vous pourriez lui donner une grande liste d'images, puis marquer les éléments d'information textuelle que vous souhaitez afficher sur la tuile, en utilisant IsTileViewColumn.

1 votes

Une note - licence GPL. Juste quelque chose à considérer si vous voulez l'utiliser dans une application commerciale.

1 votes

Si vous souhaitez l'utiliser dans une application commerciale, il est très facile d'obtenir une licence.

2voto

Lou Franco Points 48823

Disclaimer : Je travaille pour Atalasoft

Il existe un contrôle de vignette d'image dans notre SDK .NET Imaging, DotImage

1 votes

Le ListView .NET intégré n'est pas conçu aussi proprement que je l'aurais espéré ; je suis surpris qu'il ne "fonctionne pas tout simplement", avec tous ces petits détails à gérer. Je comprends qu'Atlassoft ait un marché pour des composants mieux conçus ! On pourrait penser qu'il y aurait un contrôle pour naviguer dans les vignettes où il suffirait de déposer vos images et "boom", ça marche tout simplement... mais peut-être que l'idée de toutes ces "grandes" (> 100 pixels :-) images était farfelue lorsque Win95/NT a été conçu...

1 votes

@Jared, c'est parce que ListView a évolué dans le temps avec Windows, et est toujours basé sur des idées conçues dans Win95.

1voto

Créer un contrôle personnalisé ne serait pas trop difficile. J'hériterais de Panel ou d'un Usercontrol, car je crois que les deux ajoutent automatiquement des barres de défilement pour le contenu.

Ajouter dynamiquement des conteneurs (comme des PictureBox) et des légendes pour chaque image, gérer l'événement mousedown ou mouseclick pour le conteneur et peut-être dessiner un carré rouge autour de lui pour montrer qu'il est sélectionné. La partie la plus "difficile" serait de rééchantillonner l'image en 128x128 si elle n'a pas déjà cette taille et même cela peut facilement être fait avec GDI+.

0 votes

Le rééchantillonnage en 128x128 (ou vraiment, 128xH ou Wx128) est déjà fait. C'est juste que je n'aime pas déboguer et rendre le tout rapide et robuste, le tester et l'ajuster car cela prend du temps.

0 votes

Et le fait de faire fonctionner le ListView signifie également que j'obtiens des choses comme les touches fléchées et le focus/sélection gratuitement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X