46

原始问题(请参阅下面的更新)

我有一个 WinForms 程序,它需要一个体面的可滚动图标控件,带有大图标(实际上是 128x128 或更大的缩略图),可以单击以突出显示或双击以执行某些操作。最好是尽量减少浪费的空间(每个图标下方可能需要短文件名标题;如果文件名太长,我可以添加省略号)。

具有适当颜色、间距等的列表视图的完成版本。
(来源:updike.org

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

在 LargeIcon 视图中显示小图标的屏幕截图
(来源: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++;
        }

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

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

我找到了关于 OwnerDraw 的本教程,但从那基本上相当于上面的 3 或 4 号,因为该演示只是展示了如何在详细信息视图中为行添加趣味。

更新

添加行

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

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

大图标,终于
(来源:updike.org

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

更新 2

随着添加线

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();
}
4

5 回答 5

14

对于更新:

  1. 除了图像大小之外,还设置图像列表颜色深度 (ilist.ColorDepth = ColorDepth.Depth24Bit)
  2. WinForms ListView 无法更改图标间距,但可以使用 Win32 轻松完成。您需要将LVM_SETICONSPACING发送到您的 ListView(.net 中有很多关于如何使用 SendMessage win32 功能的教程,所以我认为这个方向对您来说一定足够了)。
于 2009-07-09T08:40:58.030 回答
5

您可以使用 FlowLayoutPanel 并将图片框放入其中。将图片框的大小设置为 128x128,将 sizemode 设置为“缩放”(这可以在不损失纵横比的情况下调整图像大小)。您甚至可以以编程方式添加图片框。

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

由于您需要在图片框下有一个标签,您可以创建一个用户控件,如 Pastor 所说,它只有一个图片框和一个标签。然后这将是您将添加到 flowlayoutpanel 的控件实例。

于 2009-07-09T00:19:18.517 回答
5

ObjectListView(围绕.NET ListView 的开源包装器)使自定义绘制Tile 视图变得容易。查看演示中的 Complex 视图,启用自定义绘制时切换到 Tile 视图:(来源:sourceforge.net所有者绘制的平铺视图

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

于 2009-07-13T09:07:40.477 回答
2

免责声明:我为 Atalasoft 工作

在我们的 .NET Imaging SDK 中有一个图像缩略图控件,DotImage

于 2009-07-09T00:23:50.093 回答
1

制作自定义控件不会太糟糕。我会从 Panel 或 Usercontrol 继承,因为我相信两者都会自动为内容添加滚动条。

为每个图像动态添加容器(如 PictureBoxes)和标题,处理容器的 mousedown 或 mouseclick 事件,并可能在其周围绘制一个红色方块以表明它已被选中。“最难”的部分是将图像重新采样到 128x128,如果它们还没有那么大,甚至可以很容易地使用 GDI+。

于 2009-07-09T00:03:16.037 回答