繁体   English   中英

如何为 ListBox 制作透明背景?

[英]How to make transparent background to ListBox?

我有一个 c# WinForms 应用程序,背景中有一张图片。 我在 window 上放了一个 ListBox,我想将BackColor更改为对我的 ListBox 透明。 但 ListBox 不支持透明BackColor 我能为它做些什么?

你可以做的应该是这样的:

假设我们要创建一个名为TansparentListBox的透明列表框。 所以我们需要从ListBox控件中衍生出一个新的class,设置一些控件styles使其双缓冲,防止绘制背景,并且说我们自己来绘制:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.ComponentModel;

[ToolboxBitmap(typeof(ListBox)),
    DesignerCategory("")]
public class TransparentListBox : ListBox
{

    public TransparentListBox() : base()
    {
        SetStyle(
            ControlStyles.Opaque |
            ControlStyles.AllPaintingInWmPaint |
            ControlStyles.ResizeRedraw |
            ControlStyles.UserPaint |
            ControlStyles.OptimizedDoubleBuffer, true);
        DrawMode = DrawMode.OwnerDrawFixed;
    }
    //...

现在我们需要重写OnPaintOnDrawItem事件来进行绘图。 DrawThemeParentBackground function 是复制父级背景所必需的,也就是我们控制的区域。 此外,我们还有一个新成员, SelectionBackColor属性,即所选项目的背景颜色:

    //...
    public Color SelectionBackColor { get; set; } = Color.DarkOrange;

    [DllImport("uxtheme", ExactSpelling = true)]
    private extern static int DrawThemeParentBackground(
        IntPtr hWnd, 
        IntPtr hdc, 
        ref Rectangle pRect
        );

    protected override void OnPaint(PaintEventArgs e)
    {
        var g = e.Graphics;
        var rec = ClientRectangle;

        IntPtr hdc = g.GetHdc();
        DrawThemeParentBackground(this.Handle, hdc, ref rec);
        g.ReleaseHdc(hdc);

        using (Region reg = new Region(e.ClipRectangle))
        {
            if (Items.Count > 0)
            {
                for (int i = 0; i < Items.Count; i++)
                {
                    rec = GetItemRectangle(i);

                    if (e.ClipRectangle.IntersectsWith(rec))
                    {
                        if ((SelectionMode == SelectionMode.One && SelectedIndex == i) ||
                            (SelectionMode == SelectionMode.MultiSimple && SelectedIndices.Contains(i)) ||
                            (SelectionMode == SelectionMode.MultiExtended && SelectedIndices.Contains(i)))
                            OnDrawItem(new DrawItemEventArgs(g, Font, rec, i, DrawItemState.Selected, ForeColor, BackColor));
                        else
                            OnDrawItem(new DrawItemEventArgs(g, Font, rec, i, DrawItemState.Default, ForeColor, BackColor));

                        reg.Complement(rec);
                    }
                }
            }
        }            
    }

    protected override void OnDrawItem(DrawItemEventArgs e)
    {
        if (e.Index < 0) return;

        var rec = e.Bounds;
        var g = e.Graphics;

        g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

        if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            using (SolidBrush sb = new SolidBrush(SelectionBackColor))
                g.FillRectangle(sb, rec);

        using (SolidBrush sb = new SolidBrush(ForeColor))
        using (StringFormat sf = new StringFormat { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center })
            g.DrawString(GetItemText(Items[e.Index]), Font, sb, rec, sf);
    }
    //...

困难的部分已经完成。 最后,绘图应该在某些事件发生时刷新,否则会出现视觉混乱:

    //...
    protected override void OnSelectedIndexChanged(EventArgs e)
    {
        base.OnSelectedIndexChanged(e);
        Invalidate();
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        Invalidate();
    }

    protected override void OnMouseWheel(MouseEventArgs e)
    {
        base.OnMouseWheel(e);
        Invalidate();
    }
    //...

此外,同时使用垂直和水平滚动条时需要刷新。 通过重写WndProc可以做到这一点,因为 ListBox 控件没有任何滚动事件。

    //...
    private const int WM_KILLFOCUS  = 0x8;
    private const int WM_VSCROLL    = 0x115;
    private const int WM_HSCROLL    = 0x114;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg != WM_KILLFOCUS && 
            (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL))
            Invalidate();
        base.WndProc(ref m);
    }
}

而已。 拼图,重建并尝试。

透明列表框

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM