简体   繁体   English

如何为 ListBox 制作透明背景?

[英]How to make transparent background to ListBox?

I have a c# WinForms application with a picture in the background.我有一个 c# WinForms 应用程序,背景中有一张图片。 I put a ListBox to the window and I would like to change the BackColor to transparent to my ListBox.我在 window 上放了一个 ListBox,我想将BackColor更改为对我的 ListBox 透明。 But the ListBox doesn't support transparent BackColor .但 ListBox 不支持透明BackColor What can I do for it?我能为它做些什么?

What you can do should be something like:你可以做的应该是这样的:

Say, we want to create a transparent list box named TansparentListBox .假设我们要创建一个名为TansparentListBox的透明列表框。 So we need to derive a new class from the ListBox control, set some control styles to make it double buffered, prevent painting the background, and to say that we will do the painting ourselves:所以我们需要从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;
    }
    //...

Now we need to override both the OnPaint and OnDrawItem events to do the drawing.现在我们需要重写OnPaintOnDrawItem事件来进行绘图。 The DrawThemeParentBackground function is required to copy the parent's background, just the region of our control. DrawThemeParentBackground function 是复制父级背景所必需的,也就是我们控制的区域。 Also we have a new member, the SelectionBackColor property, the background color of the selected items:此外,我们还有一个新成员, 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);
    }
    //...

The hard part is done.困难的部分已经完成。 To finish up, the drawing should be refreshed on occurrence of certain events, otherwise it will be a visual chaos:最后,绘图应该在某些事件发生时刷新,否则会出现视觉混乱:

    //...
    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();
    }
    //...

Also, a refresh is required when using both, the vertical and horizontal scroll bars.此外,同时使用垂直和水平滚动条时需要刷新。 Doing that is possible by overriding the WndProc since the ListBox control does not have any scroll events.通过重写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);
    }
}

That's it.而已。 Puzzle up, rebuild and try.拼图,重建并尝试。

透明列表框

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

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