在ListView中的网格中显示128x128像素或更大的缩略图图标

Jar*_*ike 45 c# listview thumbnails .net-2.0 winforms

原始问题(见下面的更新)

我有一个WinForms程序需要一个体面的可滚动图标控件与大图标(真的是128x128或更大的缩略图),可以点击到hilight或双击以执行某些操作.最好是浪费的空间最小(每个图标下方可能需要短文件名标题;如果文件名太长,我可以添加省略号).

具有适当颜色,间距等的listview的完成版本http://www.updike.org/images/listview-great.png

我尝试使用带有LargeIcon的ListView(默认.View),结果令人失望:

截图显示LargeIcon视图中的小图标http://www.updike.org/images/listview-poor.png

也许我错误填充控件?码:

        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++;
        }
Run Code Online (Sandbox Code Playgroud)

我需要带有小空间的大图标,而不是带有令人尴尬的小图标的大空间.

  1. 是否有.NET控件可以满足我的需求?
    • 有没有最喜欢的第三方控件呢?
    • 如果没有,哪个控件最好继承和调整以使其工作?
    • 我应该分解并制作一个自定义控件(我有很多经验...只是不想去那个极端,因为这有点涉及).

我找到了关于OwnerDraw的这个教程,但是从那里开始的工作基本上达到了上面的数字3或4,因为该演示只是展示了如何在细节视图中对行进行调整.

更新

添加线

ilist.ImageSize = new Size(128, 128);
Run Code Online (Sandbox Code Playgroud)

在for循环之前修复了大小问题,但现在图像被调色为8位(看起来像系统颜色?),即使调试器显示图像作为24bpp System.Drawing.Bitmap插入到ImageList中:

大图标,最后是http://www.updike.org/images/listview-poor2.png

  1. 我如何(可以吗?)使图像以完整的24位颜色显示?
    • 图标周围的间距仍然相当浪费......我该如何解决?我可以吗?

更新2

随着添加线

ilist.ColorDepth = ColorDepth.Depth24Bit;
Run Code Online (Sandbox Code Playgroud)

设置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);
Run Code Online (Sandbox Code Playgroud)

ListView控件可能不完美或具有我期望的默认值(如Spacing属性)但我很高兴我可以驯服它,最后:

替代文字http://www.updike.org/images/listview-great.png

顺便说一下,为了保持缩略图的正确宽高比,我必须制作自己的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();
}
Run Code Online (Sandbox Code Playgroud)

arb*_*ter 14

更新:

  1. 除图像大小外,还设置图像列表颜色深度(ilist.ColorDepth = ColorDepth.Depth24Bit)
  2. WinForms ListView无法更改图标间距,但可以使用Win32轻松完成.你需要将LVM_SETICONSPACING发送到ListView(有许多教程如何在.net中使用SendMessage win32函数,所以我认为这个方向对你来说已经足够了).


jva*_*erh 5

您可以使用FlowLayoutPanel并在其中删除图片框.将图片框设置为128x128,将sizemode设置为"缩放"(这样可以在不丢失宽高比的情况下调整图像大小).您甚至可以以编程方式添加图片框.

PictureBox pb = New Picturebox;
 pb.image = gcf.image128;
 FlowLayoutPanel1.Controls.Add(pb)
Run Code Online (Sandbox Code Playgroud)

由于你需要在图片框下面有一个标签,你可以创建一个像Pastor这样的Usercontrol,它说它只有一个图片框和一个标签.然后,这将是您要添加到flowlayoutpanel的控件实例.


Gra*_*ian 5

ObjectListView(.NET ListView的开源包装器)可以轻松自定义绘制Tile视图.看一下demo上的Complex视图,在启用自定义绘制时切换到Tile视图:owner drawn tile view http://objectlistview.sourceforge.net/cs/_images/tileview-ownerdrawn.png

如果您只想要128x128图像加上一些文本细节,您甚至不需要所有者绘制它.您可以给它一个大的图像列表,然后使用IsTileViewColumn标记要在Tile上显示哪些文本信息.