C# 在 ListView 的网格中显示 128x128 像素或更大的缩略图图标
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1101149/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Displaying thumbnail icons 128x128 pixels or larger in a grid in ListView
提问by Jared Updike
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).
我有一个 WinForms 程序,它需要一个像样的可滚动图标控件,带有大图标(实际上是 128x128 或更大的缩略图),可以单击以突出显示或双击以执行某些操作。最好有最少的空间浪费(每个图标下方可能需要简短的文件名标题;如果文件名太长,我可以添加省略号)。
(source: updike.org)
(来源:updike.org)
I tried using a ListView with LargeIcon (default .View) and the results are disappointing:
我尝试将 ListView 与 LargeIcon(默认 .View)一起使用,但结果令人失望:
(source: updike.org)
(来源: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.
我需要带有很少空白空间的大图标,而不是带有令人尴尬的小图标的大空白空间。
- 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).
- 是否有一个 .NET 控件可以满足我的需求?
- 有没有最喜欢的第三方控件可以做到这一点?
- 如果没有,最好继承和调整哪个控件以使其工作?
- 我应该分解并制作一个自定义控件(我有很多经验......只是不想走到那个极端,因为这有点涉及)。
I found this tutorial about OwnerDrawbut 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.
我发现了这个关于 OwnerDraw 的教程,但是从它开始的工作基本上相当于上面的第 3 或 4 号,因为该演示只展示了如何在详细信息视图中添加行。
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:
在 for 循环修复大小问题之前,但现在图像调色板化为 8 位(看起来像系统颜色?)即使调试器显示图像作为 24bpp System.Drawing.Bitmap 插入到 ImageList 中:
(source: updike.org)
(来源:updike.org)
- 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?
- 我如何(我可以吗?)使图像以全 24 位颜色显示?
- 图标周围的间距仍然相当浪费......我该如何解决?我可以吗?
Update 2
更新 2
Along with adding the line
随着添加行
ilist.ColorDepth = ColorDepth.Depth24Bit;
next after setting ilist.ImageSize, I followed arbiter's advice and changed the spacing:
接下来在设置 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);
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:
ListView 控件可能并不完美,或者具有我期望的默认值(如 Spacing 属性),但我很高兴我最终可以驯服它:
(source: updike.org)
(来源: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:
顺便说一句,为了保持缩略图的适当纵横比,我必须制作自己的 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();
}
采纳答案by arbiter
For update:
更新:
- Set image list color depth in addition to image size (ilist.ColorDepth = ColorDepth.Depth24Bit)
- WinForms ListView does not have possibility to change icon spacing, however it can be easily done using Win32. You need to send LVM_SETICONSPACINGto 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).
- 除了图像大小外,还设置图像列表颜色深度(ilist.ColorDepth = ColorDepth.Depth24Bit)
- WinForms ListView 无法更改图标间距,但是可以使用 Win32 轻松完成。您需要将LVM_SETICONSPACING发送到您的 ListView (如何在 .net 中使用 SendMessage win32 函数的教程很多,所以我认为这个方向对您来说应该足够了)。
回答by Jared Updike
Making a custom control wouldn't be too bad. I would inherit from Panel or a Usercontrol as I believe both automatically add scrollbars for the content.
制作自定义控件不会太糟糕。我会从 Panel 或 Usercontrol 继承,因为我相信两者都会自动为内容添加滚动条。
Dynamically adding containers (like PictureBoxes) and captions for each image, handling the mousedown or mouseclick event for the container and perhaps drawing a red square around it to show that it is selected. The "hardest" part would be resampling the image to 128x128 if they are not already that size and even that can easily be with GDI+.
为每个图像动态添加容器(如图片框)和标题,处理容器的 mousedown 或 mouseclick 事件,并可能在其周围绘制一个红色方块以表明它已被选中。“最难”的部分是将图像重新采样到 128x128,如果它们还不是那么大,甚至可以很容易地使用 GDI+。
回答by jvanderh
You could use the FlowLayoutPanel and drop pictureboxes in it. Set the picturebox to a size of 128x128 and the sizemode to 'zoom' (This takes care of resizing your image without loss of aspect ratio). You can even programatically add the pictureboxes.
您可以使用 FlowLayoutPanel 并将图片框放入其中。将图片框的大小设置为 128x128,将 sizemode 设置为“缩放”(这会在不丢失纵横比的情况下调整图像大小)。您甚至可以以编程方式添加图片框。
PictureBox pb = New Picturebox;
pb.image = gcf.image128;
FlowLayoutPanel1.Controls.Add(pb)
Since you need to have a label under the picturebox, you could create a Usercontrol like Pastor said that all it has is a picturebox and a label under it. Then that would be the control instance you would add to your flowlayoutpanel.
由于您需要在图片框下有一个标签,因此您可以创建一个 Usercontrol 就像 Pastor 所说的那样,它只有一个图片框和一个标签。那么这就是您要添加到 flowlayoutpanel 的控件实例。
回答by Lou Franco
回答by Grammarian
ObjectListView(an open source wrapper around a .NET ListView) makes it easy to custom draw a Tile view. Have a look at the Complex view on the demo, switch to Tile view when custom draw is enabled:
(source: sourceforge.net)
ObjectListView(围绕 .NET ListView 的开源包装器)可以轻松自定义绘制 Tile 视图。查看演示中的 Complex 视图,启用自定义绘制时切换到 Tile 视图:(来源:sourceforge.net)
If you only wanted a 128x128 image plus some text details, you wouldn't even need to owner draw it. You could give it a large imagelist, and then mark which bits of textual information you wanted to show on the Tile, using IsTileViewColumn.
如果你只想要一张 128x128 的图像加上一些文本细节,你甚至不需要所有者绘制它。你可以给它一个大的图像列表,然后使用 IsTileViewColumn 标记你想要在 Tile 上显示的文本信息位。