【问题标题】:Images In ListView Don't Match BackColor PropertyListView 中的图像与 BackColor 属性不匹配
【发布时间】:2018-06-04 16:25:34
【问题描述】:

概述

我目前正在为我的应用程序开发一个主题系统,允许用户选择浅色和深色主题(类似于 Visual Studio)。整个过程非常简单,这就是我当前更改ListView 控件的BackColor 属性的方式(尽管我尝试了一些失败的内联解决方案,例如仅设置ListViewBackColorListViewItem)。

细分

我有一个ImageList,有 6 张图片;所有这些都有透明的背景。每个图像都是一个不同颜色的玻璃球和一个投影。根据我从数据库中提取的状态,我将这六个图像中的一个分配给我的ListView(设置为Details 视图)控件中的每个ListViewItem

只要分配图像的ListViewListViewItem 将其BackColor 属性设置为Color.Control,一切都很好。如果它变成任何其他颜色(绿色、灰色、蓝色、红色等);那么图像的背面颜色不匹配。它继续保留默认的Color.Control 颜色。

主题代码

public static void ApplyTheme(Form f) {
    foreach (Control c in f.Controls) {
        if (c is MenuStrip)
            ThemeMenu((MenuStrip)c);
        else {
            ApplyStyles(c);
            if (c.Controls != null || c.Controls.Count > 0)
                RecurseChildControls(c);
        }
    }
}
public static void RecurseChildControls(Control parent) {
    foreach (Control child in parent.Controls) {
        ApplyStyles(child)

        if (child.Controls != null || child.Controls.Count > 0)
            RecurseChildControls(child);
    }
}
public static void ApplyStyles(Control c) {
    if (c is Button) {
        Button b = (Button)c;
        b.FlatStyle = FlatStyle.Flat;
        b.FlatAppearance.BorderSize = 0;
    }
    if (c is RoundedPanel || c is PictureBox) {
        // Do nothing.
    } else {
        if (c is Label) {
            if (c.Parent is RoundedPanel) {
                // Do nothing.
            } else {
                c.BackColor = BackColor;
                c.ForeColor = ForeColor;
            }
        } else {
            c.BackColor = BackColor;
            c.ForeColor = ForeColor;
        }

        if (c is ListView) {
            ListView lv = (ListView)c;
            if (Style = Themes.Dark)
                lv.GridLines = false;

            foreach (ListViewItem lvi in lv.Items) {
                lvi.BackColor = BackColor;
                lvi.ForeColor = ForeColor;
            }
        }
    }
}

我尝试添加一个方法来更新ListView 控件的BackColor 属性及其所有ListViewItem 对象,然后我在DrawItemDrawSubItem 事件上调用了这个方法(两者都没有)工作);调用此方法代替ListViewInvalidate 方法,在更改ListViewItemImageIndex 属性后立即调用此方法;我什至尝试在表单本身上调用Invalidate 并重新绘制所有内容。

我真的可以在这方面使用一些指导,因为到目前为止一切都很好;这是唯一让我绕圈子的问题。我已经通过谷歌浏览了好几次,但从来没有找到任何与图像相关的结果,它与包含ListViewListViewItem 的图像不具有相同的BackColor。也许我没有使用正确的术语进行搜索,或者我是第一个抱怨这个问题的人;谁知道。任何帮助表示赞赏。

注意

如果您觉得我遗漏了任何需要的信息,或者如果我应该对某些事情更清楚,请随时发表评论并告诉我,以便我可以为未来的读者更新帖子的清晰度。

新尝试(失败)

  • 尝试在设置ImageIndex 属性之前(和之后)更改ListView 对象的背景颜色。
  • 尝试使用OwnerDrawDrawItem 事件来绘制图像。
  • 尝试使用如下指定的背景颜色创建原始图像的Bitmap

尝试代码

// Bullet 2
e.Graphics.DrawImage(Image, Rectangle);

// Bullet 3
Rectangle r = new Rectangle(0, e.Bounds.Y, 16, 16);
Image I = imageList1.Images[e.Item.ImageIndex];
Bitmap b = new Bitmap(i.Width, i.Height);
using (Graphics g = Graphics.FromImage(b)) {
    g.Clear(Theme.BackColor);
    g.DrawImageUnscaledAndClipped(i, new Rectangle(Point.Empty, i.Size));
}
e.Graphics.DrawImage(b, r);

图片

Desired Result

Current Result,其中绿点是图片,红点是背景问题,蓝框是ListViewItem

【问题讨论】:

  • 欢迎您!这是一个写得很好的问题! - 我相信具有透明度的图像下方显示的背景颜色始终是 lv 背景色,无论 lvitems 有什么,除非您拥有它。然后通过调用 e.DrawBackground 将 lvi.backcolor 绘制在整个宽度上,包括空间图片..:e.DrawBackground(); e.DrawText(); Rectangle rect = new Rectangle(0, e.Bounds.Y, 16, 16); e.Graphics.DrawImage(imageList1.Images[e.Item.ImageIndex],rect );
  • @TaW Hrmmm...所以我对您刚才所说的背景颜色理论进行了快速测试,但没有效果。现在要查看OwnerDraw,我会发布更新。我认为具有透明度的图像不会像 PictureBox 控件那样反映底层容器控件的背景颜色。
  • @TaW 所以OwnerDraw 也是失败的。图片仍然保留着那可怕的Color.Control 外观。
  • @TaW 我希望我可以,一切都在一台无法访问互联网的封闭机器上。我可以偶然查看一下 Google 图片上是否有任何内容。您是否使用DrawItem 事件来执行该绘制或其他操作?
  • @TaW 似乎比它真正的价值要付出更多的努力;我想在这一点上它会归结为该方法的效率。我会四处寻找一些文章并尝试一下。

标签: c# winforms listview themes


【解决方案1】:

要在您需要owner-draw的图像下显示个人ListViewItem.BackColors,否则ListView.BackColor 将改为显示。但是您注意到图像的半透明部分中有丑陋的伪影。

经过多次测试,我相信ImageList 是罪魁祸首。

它似乎在应该是半透明像素的地方插入了灰色像素。完全透明的像素不受影响。

这与其属性无关。

以下是所有者使用ImageList 中的图像绘制ListView 并绘制相同图像但直接从磁盘加载的结果..:

你肯定能看出哪个是哪个..

图像是透明背景上的黄色斑点,带有半透明光晕和两个半透明孔。

ListView.DrawItem事件中的绘制代码相同:

e.DrawBackground();
e.DrawText();
Rectangle rect = new Rectangle(0, e.Bounds.Y, 32, 16);

Bitmap bmp1 = (Bitmap)imageList1.Images[e.Item.ImageIndex];
Bitmap bmp2 = (Bitmap)Bitmap.FromFile("filepath.png");

e.Graphics.DrawImage(bmp1_OR_bmp2, rect);

因此,如果您需要半透明图像,则无法将它们真正存储在 ImageList 中。

【讨论】:

  • 很大程度上取决于图像的质量和 ImageList 的初始设置。如果您将其ColorDepth 设置为Depth32Bit 并且仅在添加图像之后,将保留质量(即使您修改了ImageList ImageSize 属性)。如果在加载图片后修改此设置,并且初始设置为默认的Depth8Bit,则图像质量会很差。具体来说,半透明像素不会被保留(毕竟没办法)。
  • ...并且,在第二种情况下,半透明像素将与使用 ImageList 作为源的控件的当前背景颜色合并(不确定是什么逻辑)。
  • 如果这是真的,那该多好。但事实并非如此。 Imagelist 在我添加图像之前有 Depth32Bit 并且效果仍然存在。刚刚仔细检查。
  • 我也查过了。我使用了相对(对于 32x32 目标)带有一些阴影的大 .png 图像(500x500)(如果你谷歌“软件图标透明”,你可以找到其中的一些)。结果与我之前描述的设置非常(明显)不同。带有红色背景的 ListView 控件在使用默认设置插入时显示带有 gray-ish 抗锯齿的图像。如果加载了Depth32Bit,“阴影”只会与红色背景混合,无论最终大小如何。我将使用质量较低的图像对其进行测试。
  • 当使用ColorDepth 添加到 ImageList 时,我可以使用低质量的 .png 图像(从 shell32.dll 中提取并转换为 .png 的图标)和相同的图标(.ico 文件)重现此问题这不允许 Alpha 通道。对于 .png 图像,阴影必须是假透明度(简单的色阶/混合模拟)。
猜你喜欢
  • 1970-01-01
  • 2014-09-17
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 2013-11-13
相关资源
最近更新 更多