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).
(source: pdike.org )
J'ai essayé d'utiliser un ListView avec LargeIcon (par défaut .View) et les résultats sont décevants:
(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.
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.
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:
(source: pdike.org )
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:
(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();
}
Pour la mise à jour:
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.
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é:
(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.
Avertissement: je travaille pour Atalasoft
Il existe un contrôle de vignette d'image dans notre SDK de création d'image .NET, DotImage
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 +.