C# how to use NM_CUSTOMDRAW to native trackBar control

218 Views Asked by At

I use the code below to modify native trackbar.

My questions are:

  1. How to detect if mouse is over thumb and change its color?
  2. How to change the shape of thumb? (How to keep the original shape?)

public class TrackBarCustom : TrackBar
    {
        private Color tbarColor;
        private Color tbarBorder;
        private Color thumbColor;
        private Color thumbBorder;

        public TrackBarCustom()
        {
        }

        // custom draw item specs
        private const int TBCD_TICS = 0x1;
        private const int TBCD_THUMB = 0x2;
        private const int TBCD_CHANNEL = 0x3;

        [StructLayout(LayoutKind.Sequential)]
        public struct NMHDR
        {
            public IntPtr hwndFrom;
            public IntPtr idFrom;
            public int code;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct NMCUSTOMDRAW
        {
            public NMHDR hdr;
            public int dwDrawStage;
            public IntPtr hdc;
            public RECT rc;
            public IntPtr dwItemSpec;
            public uint uItemState;
            public IntPtr lItemlParam;
        }

        [Flags]
        public enum CDRF
        {
            CDRF_DODEFAULT = 0x0,
            CDRF_NEWFONT = 0x2,
            CDRF_SKIPDEFAULT = 0x4,
            CDRF_DOERASE = 0x8,
            CDRF_SKIPPOSTPAINT = 0x100,
            CDRF_NOTIFYPOSTPAINT = 0x10,
            CDRF_NOTIFYITEMDRAW = 0x20,
            CDRF_NOTIFYSUBITEMDRAW = 0x20,
            CDRF_NOTIFYPOSTERASE = 0x40
        }


        [Flags]
        public enum CDDS
        {
            CDDS_PREPAINT = 0x1,
            CDDS_POSTPAINT = 0x2,
            CDDS_PREERASE = 0x3,
            CDDS_POSTERASE = 0x4,
            CDDS_ITEM = 0x10000,
            CDDS_ITEMPREPAINT = (CDDS.CDDS_ITEM | CDDS.CDDS_PREPAINT),
            CDDS_ITEMPOSTPAINT = (CDDS.CDDS_ITEM | CDDS.CDDS_POSTPAINT),
            CDDS_ITEMPREERASE = (CDDS.CDDS_ITEM | CDDS.CDDS_PREERASE),
            CDDS_ITEMPOSTERASE = (CDDS.CDDS_ITEM | CDDS.CDDS_POSTERASE),
            CDDS_SUBITEM = 0x20000
        }

        [DllImport("User32.dll", SetLastError = true)]
        public static extern int FillRect(IntPtr hDC, ref RECT lpRect, IntPtr hBR);

        [DllImport("User32.dll", SetLastError = true)]
        public static extern int FrameRect(IntPtr hDC, ref RECT lpRect, IntPtr hPN);

        [DllImport("gdi32")]
        public static extern IntPtr CreatePen(int penStyle, int width, int color);

        [DllImport("Gdi32.dll", SetLastError = true)]
        public static extern IntPtr CreateSolidBrush(int crColor);

        [DllImport("Gdi32.dll", SetLastError = true)]
        public static extern bool DeleteObject(IntPtr hObject);


        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_REFLECT + WM_NOFITY)
            {
                var pnmhdr = (NMHDR)m.GetLParam(typeof(NMHDR));
                if (pnmhdr.code == NM_CUSTOMDRAW)
                {
                    var pnmlv = (NMCUSTOMDRAW)m.GetLParam(typeof(NMCUSTOMDRAW));
                    switch (pnmlv.dwDrawStage)
                    {
                        case (int)CDDS.CDDS_PREPAINT:
                            {
                                m.Result = new IntPtr((int)CDRF.CDRF_NOTIFYITEMDRAW);
                                break;
                            }

                        case (int)CDDS.CDDS_ITEMPREPAINT:
                            {
                                if (((int)pnmlv.dwItemSpec == TBCD_THUMB))
                                {
                                    IntPtr hBrush = CreateSolidBrush(ColorTranslator.ToWin32(Enabled ? ThumbColor : Color.Silver));
                                    IntPtr hPen = CreatePen(0, 1, ColorTranslator.ToWin32(Enabled ? ThumbBorder : Color.DarkGray));

                                    FillRect(pnmlv.hdc, ref pnmlv.rc, hBrush);
                                    FrameRect(pnmlv.hdc, ref pnmlv.rc, hPen);
                                    DeleteObject(hBrush);
                                    DeleteObject(hPen);
                                    m.Result = new IntPtr((int)CDRF.CDRF_SKIPDEFAULT);
                                }

                                else if (((int)pnmlv.dwItemSpec == TBCD_CHANNEL))
                                {
                                    IntPtr hBarBrush = CreateSolidBrush(ColorTranslator.ToWin32(Enabled ? TbarColor : Color.Silver));
                                    IntPtr hBarPen = CreatePen(0, 1, ColorTranslator.ToWin32(Enabled ? TbarBorder : Color.DarkGray));
                                    FillRect(pnmlv.hdc, ref pnmlv.rc, hBarBrush);
                                    FrameRect(pnmlv.hdc, ref pnmlv.rc, hBarPen);
                                    DeleteObject(hBarBrush);
                                    DeleteObject(hBarPen);
                                    m.Result = new IntPtr((int)CDRF.CDRF_SKIPDEFAULT);
                                }

                                else
                                    m.Result = new IntPtr((int)CDRF.CDRF_NOTIFYPOSTPAINT);
                                break;
                            }

                        case (int)CDDS.CDDS_ITEMPOSTPAINT:
                            {
                                m.Result = new IntPtr((int)CDRF.CDRF_DODEFAULT);
                                break;
                            }

                    }
                }
                return;
            }
            else
                base.WndProc(ref m);
        }

        private const int NM_FIRST = 0;
        private const int NM_CLICK = NM_FIRST - 2;
        private const int NM_CUSTOMDRAW = NM_FIRST - 12;
        private const int WM_REFLECT = 0x2000;
        private const int WM_NOFITY = 0x4E;

        public Color ThumbColor
        {
            get
            {
                return thumbColor;
            }

            set
            {
                thumbColor = value;
                Update();
                Refresh();
                Invalidate();
            }
        }

        public Color ThumbBorder
        {
            get
            {
                return thumbBorder;
            }

            set
            {
                thumbBorder = value;
                Update();
                Refresh();
                Invalidate();
            }
        }

        public Color TbarColor
        {
            get
            {
                return tbarColor;
            }

            set
            {
                tbarColor = value;
                Update();
                Refresh();
                Invalidate();
            }
        }

        public Color TbarBorder
        {
            get
            {
                return tbarBorder;
            }

            set
            {
                tbarBorder = value;
                Update();
                Refresh();
                Invalidate();
            }
        }
    }
0

There are 0 best solutions below