代码之家  ›  专栏  ›  技术社区  ›  Jared Updike

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

  •  44
  • Jared Updike  · 技术社区  · 17 年前

    原始问题(见下文更新)

    我有一个Winforms程序,需要一个不错的滚动图标控件,它带有大图标(实际上是128x128或更大的缩略图),可以单击到hilight或双击来执行一些操作。最好有最小的浪费空间(每个图标下面可能需要简短的文件名标题;如果文件名太长,我可以添加省略号)。

    finished version of listview with proper colors, spacing, etc. http://www.updike.org/images/listview-great.png

    我尝试使用带有largeicon(default.view)的ListView,结果令人失望:

    screenshot showing tiny icons in LargeIcon view 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++;
            }
    

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

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

    我发现 this tutorial about OwnerDraw 但是,从这一点开始的工作基本上相当于上面的数字3或4,因为这个演示仅仅展示了如何在细节视图中增加行的趣味性。

    更新

    添加线

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

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

    large icons, finally http://www.updike.org/images/listview-poor2.png

    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属性),但我很高兴能够驯服它,最终:

    alt text 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();
    }
    
    5 回复  |  直到 17 年前
        1
  •  13
  •   arbiter    17 年前

    更新:

    1. 设置图像列表颜色深度以及图像大小(ilist.color depth=color depth.depth24bit)
    2. WinForms ListView不可能更改图标间距,但是可以使用Win32轻松完成。你需要发送 LVM_SETICONSPACING 到您的ListView(有很多教程如何在.NET中使用sendmessage win32函数,所以我认为这个方向对您来说已经足够了)。
        2
  •  5
  •   jvanderh    17 年前

    您可以使用flowlayoutpanel并在其中放置图片框。将PictureBox的大小设置为128x128,将SizeMode设置为“缩放”(这样可以在不丢失纵横比的情况下调整图像的大小)。您甚至可以通过编程添加图片框。

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

    因为您需要在PictureBox下有一个标签,所以您可以创建一个用户控件,就像Pastor所说的那样,它只有一个PictureBox和一个标签。然后,这将是您将添加到FlowlayOutpanel中的控制实例。

        3
  •  5
  •   Grammarian    17 年前

    ObjectListView (围绕.NET ListView的开放源代码包装)使自定义绘制平铺视图变得容易。查看演示中的复杂视图,启用自定义绘图后切换到平铺视图: owner drawn tile view http://objectlistview.sourceforge.net/cs/_images/tileview-ownerdrawn.png

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

        4
  •  2
  •   Lou Franco    17 年前

    免责声明:我为Atalasoft工作

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

        5
  •  1
  •   Pastor    17 年前

    制作一个自定义控件不会太糟糕。我将从面板或用户控件继承,因为我相信这两者都会自动为内容添加滚动条。

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

    推荐文章