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).
(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 :
(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.
- 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 :
(source : <a href="http://www.updike.org/images/listview-poor2.png" rel="nofollow noreferrer">updike.org </a>)
- 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 :
(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