Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
353 views
in Technique[技术] by (71.8m points)

c# - Displaying thumbnail icons 128x128 pixels or larger in a grid in ListView

Original Question (see Update below)

I have a WinForms program that needs a decent scrollable icon control with large icons (128x128 or larger thumbnails, really) that can be clicked to hilight or double clicked to perform some action. Preferably there would be minimal wasted space (short filename captions might be needed below each icon; if the filename is too long I can add an ellipsis).

finished version of listview with proper colors, spacing, etc.
(source: updike.org)

I tried using a ListView with LargeIcon (default .View) and the results are disappointing:

screenshot showing tiny icons in LargeIcon view
(source: updike.org)

Perhaps I am populating the control incorrectly? 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++;
        }

I need large icons with little empty space, not large empty space with embarrassingly small icons.

  1. Is there a .NET control that does what I need?
    • Is there a favorite third party control that does this?
    • If not, which control would be best to inherit and tweak to make it work?
    • Should I break down and make a custom Control (which I have plenty of experience with... just don't want to go to that extreme since that is somewhat involved).

I found this tutorial about OwnerDraw but work from that basically amounts to number 3 or 4 above since that demo just shows how to spice up the rows in the details view.

Update

Adding the line

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

before the for loop fixed the size problem but now the images are palette-ized to 8-bit (looks like system colors?) even though the debugger shows that the images are inserted into the ImageList as 24bpp System.Drawing.Bitmap's:

large icons, finally
(source: updike.org)

  1. How do I (can I?) make the images show in full 24 bit color?
    • The spacing around the icons is still rather wasteful... how do I fix that? Can I?

Update 2

Along with adding the line

ilist.ColorDepth = ColorDepth.Depth24Bit;

next after setting ilist.ImageSize, I followed arbiter's advice and changed the spacing:

[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);

The ListView control may not be perfect or have the defaults I'd expect (like a Spacing property) but I'm glad I could tame it, in the end:

alt text
(source: updike.org)

By the way, to maintain the proper aspect ratio for the thumbnails, I had to make my own 128x128 bitmaps, clear the background to match the control, and center those 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();
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For update:

  1. Set image list color depth in addition to image size (ilist.ColorDepth = ColorDepth.Depth24Bit)
  2. WinForms ListView does not have possibility to change icon spacing, however it can be easily done using Win32. You need to send LVM_SETICONSPACING to your ListView (there is a lot of tutorials how to use SendMessage win32 function in .net, so I think this direction must be enough for you).

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...