web-dev-qa-db-fra.com

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

Question d'origine (voir la mise à jour ci-dessous)

J'ai un programme WinForms qui a besoin d'un contrôle d'icône déroulant décent avec de grandes icônes (128x128 ou des vignettes plus grandes, vraiment) qui peuvent être cliquées pour s'allumer ou double-cliquer pour effectuer une action. De préférence, il y aurait un espace gaspillé minimal (des légendes de nom de fichier courtes pourraient être nécessaires sous chaque icône; si le nom de fichier est trop long, je peux ajouter des points de suspension).

finished version of listview with proper colors, spacing, etc.
(source: pdike.org )

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

screenshot showing tiny icons in LargeIcon view
(source: pdike.org )

Peut-être que je remplis le contrôle incorrectement? 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 grand espace vide avec de petites icônes embarrassantes.

  1. Existe-t-il un contrôle .NET qui fait ce dont j'ai besoin?
    • Y a-t-il un contrôle tiers préféré qui fait cela?
    • Sinon, quel contrôle serait le meilleur à hériter et Tweak pour le faire fonctionner?
    • Dois-je tomber en panne et créer un contrôle personnalisé (avec lequel j'ai beaucoup d'expérience ... ne veux tout simplement pas aller à cet extrême car cela est quelque peu impliqué).

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

Mettre à jour

Ajout de la ligne

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

avant que la boucle for ne corrige le problème de taille, mais maintenant les images sont palette-ized à 8 bits (ressemble aux couleurs du système?) même si le débogueur montre que les images sont insérées dans l'ImageList comme 24bpp System.Drawing.Bitmap's:

large icons, finally
(source: pdike.org )

  1. Comment puis-je (puis-je?) Faire afficher les images en couleur 24 bits?
    • L'espacement autour des icônes est encore assez inutile ... comment résoudre ce problème? Puis-je?

Update 2

Avec l'ajout de la ligne

ilist.ColorDepth = ColorDepth.Depth24Bit;

suivant après avoir défini ilist.ImageSize, j'ai suivi les conseils de l'arbitre et changé 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 n'a pas les valeurs par défaut que j'attendais (comme une propriété Spacing) mais je suis content d'avoir pu l'apprivoiser, à la fin:

alt text
(source: pdike.org )

Soit dit en passant, pour maintenir le rapport d'aspect approprié pour les miniatures, j'ai dû créer mes propres images bitmap 128x128, effacer l'arrière-plan pour correspondre 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();
}
44
Jared Updike

Pour la mise à jour:

  1. Définissez 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 modifier l'espacement des icônes, mais cela peut être facilement fait en utilisant Win32. Vous devez envoyer LVM_SETICONSPACING à votre ListView (il y a beaucoup de tutoriels pour utiliser la fonction winMessage de SendMessage en .net, donc je pense que cette direction doit être suffisante pour vous).
13
arbiter

Vous pouvez utiliser le FlowLayoutPanel et y déposer des boîtes d'image. Réglez la boîte d'image sur une taille de 128x128 et le mode de taille sur "zoom" (cela prend soin de redimensionner votre image sans perte de rapport hauteur/largeur). Vous pouvez même ajouter par programme les boîtes d'image.

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

Étant donné que vous devez avoir une étiquette sous la Picturebox, vous pouvez créer un Usercontrol comme Pastor a dit que tout ce qu'il avait était une Picturebox et une étiquette en dessous. Ce serait alors l'instance de contrôle que vous ajouteriez à votre panneau d'écoulement.

5
jvanderh

ObjectListView (un wrapper open source autour d'un .NET ListView) permet de dessiner facilement une vue Tile. Jetez un œil à la vue Complexe de la démo, passez en mode Mosaïque lorsque le dessin personnalisé est activé: owner drawn tile view
(source: sourceforge.net )

Si vous vouliez seulement une image 128x128 plus quelques détails de texte, vous n'auriez même pas besoin de la dessiner. Vous pouvez lui donner une grande liste d'images, puis marquer les bits d'informations textuelles que vous souhaitez afficher sur le carreau, en utilisant IsTileViewColumn.

5
Grammarian

Avertissement: je travaille pour Atalasoft

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

2
Lou Franco

Faire un contrôle personnalisé ne serait pas trop mal. 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 les PictureBoxes) 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 pour montrer qu'il est sélectionné. La partie "la plus difficile" serait de rééchantillonner l'image en 128x128 si elles ne sont pas déjà de cette taille et même cela peut être facilement avec GDI +.

1
Pastor