我有一个WinForms程序需要一个体面的可滚动图标控件,带有大图标(真的是128x128或更大的缩略图),可以点击进入hilight或双击以执行某些操作。最好是浪费的空间最小(每个图标下方可能需要短文件名标题;如果文件名太长,我可以添加省略号)。
(来源:updike.org)
我尝试使用带有LargeIcon的ListView(默认.View),结果令人失望:
(来源:updike.org)
也许我错误地填充了控件?代码:
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++;
}
我需要带有空白空间的大图标,而不是带有令人尴尬的小图标的大空间。
我找到了this tutorial about OwnerDraw但是从那以后的工作基本上达到了上面的数字3或4,因为该演示只展示了如何在详细信息视图中为行添加了更多。
添加行
ilist.ImageSize = new Size(128, 128);
在for循环之前修复了大小问题但现在将图像调色到8位(看起来像系统颜色?),即使调试器显示图像作为24bpp System.Drawing.Bitmap插入到ImageList中:
(来源:updike.org)
随着添加行
ilist.ColorDepth = ColorDepth.Depth24Bit;
在设置ilist.ImageSize之后,我按照仲裁者的建议改变了间距:
[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);
ListView控件可能不完美或者具有我期望的默认值(比如Spacing属性)但是我很高兴我可以驯服它,最后:
(来源:updike.org)
顺便说一下,为了保持缩略图的正确纵横比,我必须制作自己的128x128位图,清除背景以匹配控件,并将这些图像居中:
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();
}
答案 0 :(得分:13)
更新:
答案 1 :(得分:5)
您可以使用FlowLayoutPanel并在其中删除图片框。将图片框设置为128x128,将sizemode设置为“缩放”(这样可以在不丢失宽高比的情况下调整图像大小)。您甚至可以以编程方式添加图片框。
PictureBox pb = New Picturebox;
pb.image = gcf.image128;
FlowLayoutPanel1.Controls.Add(pb)
由于你需要在图片框下面有一个标签,你可以像Pastor一样创建一个Usercontrol,它说它只有一个图片框和一个标签。然后,这将是您要添加到flowlayoutpanel的控件实例。
答案 2 :(得分:5)
ObjectListView(.NET ListView的开源包装器)可以轻松自定义绘制Tile视图。查看演示中的复杂视图,在启用自定义绘制时切换到平铺视图:
(来源:sourceforge.net)
如果您只想要128x128图像加上一些文字细节,您甚至不需要所有者绘制它。您可以给它一个大的图像列表,然后使用IsTileViewColumn标记要在Tile上显示哪些文本信息。
答案 3 :(得分:2)
免责声明:我在Atalasoft工作
我们的.NET Imaging SDK中有一个图像缩略图控件,DotImage
答案 4 :(得分:1)
制作自定义控件也不会太糟糕。我会继承Panel或Usercontrol,因为我相信它们都会自动为内容添加滚动条。
为每个图像动态添加容器(如PictureBoxes)和标题,处理容器的mousedown或mouseclick事件,并可能在其周围绘制一个红色方块以显示它已被选中。 “最难”的部分是将图像重新采样到128x128,如果它们还不是那么大,甚至可以很容易地使用GDI +。