How to draw custom button in Window Titlebar with Windows Forms?

前端 未结 3 1952
礼貌的吻别
礼貌的吻别 2020-11-30 06:28

How do you draw a custom button next to the minimize, maximize and close buttons within the Titlebar of the Form?

I know you need to use Win32 API calls and override

3条回答
  •  感情败类
    2020-11-30 06:47

    I know it's been long since the last answer but this really helped me recently and I like to update the code provided by Chris with my comments and modifications. The version runs perfectly on Win XP and Win 2003. On Win 2008 ot has a small bug that I was not able to identify, when resizing windows. Works on Vista too (no-Aero) but note that the title bar buttons are not square and button dimensions should take that into account.

     switch (m.Msg)
                {
                    // WM_NCPAINT / WM_PAINT        
                    case 0x85:
                    case 0x0A:
                        //Call base method
                        base.WndProc(ref m);
                        //we have 3 buttons in the corner of the window. So first's new button left coord is offseted by 4 widths
                        int crt = 4;
                        //navigate trough all titlebar buttons on the form
                        foreach (TitleBarImageButton crtBtn in titleBarButtons.Values)
                        {
                            //Calculate button coordinates
                            p.X = (Bounds.Width - crt * crtBtn.Size.Width);
                            p.Y = (Bounds.Height - ClientRectangle.Height - crtBtn.Size.Height) / 2;
                            //Initialize button and draw
                            crtBtn.Location = p;
                            crtBtn.ButtonState = ImageButtonState.NORMAL;
                            crtBtn.DrawButton(m.HWnd);
                            //increment button left coord location offset
                            crt++;
                        }
                        m.Result = IntPtr.Zero;
                        break;
                    // WM_ACTIVATE      
                    case 0x86:
                        //Call base method
                        base.WndProc(ref m);
                        //Draw each button
                        foreach (TitleBarImageButton crtBtn in titleBarButtons.Values)
                        {
                            crtBtn.ButtonState = ImageButtonState.NORMAL;
                            crtBtn.DrawButton(m.HWnd);
                        }
                        break;
                    // WM_NCMOUSEMOVE        
                    case 0xA0:
                        //Get current mouse position
                        p.X = ((int)m.LParam << 16) >> 16;// Extract the least significant 16 bits            
                        p.Y = (int)m.LParam >> 16;        // Extract the most significant 16 bits          
                        p.X -= windowRect.Left;
                        p.Y -= windowRect.Top;
    
                        //Call base method
                        base.WndProc(ref m);
    
                        ImageButtonState newButtonState;
                        foreach (TitleBarImageButton crtBtn in titleBarButtons.Values)
                        {
                            if (crtBtn.HitTest(p))
                            {//mouse is over the current button
                                if (crtBtn.MouseButtonState == MouseButtonState.PRESSED)
                                    //button is pressed - set pressed state
                                    newButtonState = ImageButtonState.PRESSED;
                                else
                                    //button not pressed - set hoover state
                                    newButtonState = ImageButtonState.HOOVER;
                            }
                            else
                            {
                                //mouse not over the current button - set normal state
                                newButtonState = ImageButtonState.NORMAL;
                            }
    
                            //if button state not modified, do not repaint it.
                            if (newButtonState != crtBtn.ButtonState)
                            {
                                crtBtn.ButtonState = newButtonState;
                                crtBtn.DrawButton(m.HWnd);
                            }
                        }
                        break;
                    // WM_NCLBUTTONDOWN     
                    case 0xA1:
                        //Get current mouse position
                        p.X = ((int)m.LParam << 16) >> 16;// Extract the least significant 16 bits
                        p.Y = (int)m.LParam >> 16;        // Extract the most significant 16 bits      
                        p.X -= windowRect.Left;
                        p.Y -= windowRect.Top;
    
                        //Call base method
                        base.WndProc(ref m);
    
                        foreach (TitleBarImageButton crtBtn in titleBarButtons.Values)
                        {
                            if (crtBtn.HitTest(p))
                            {
                                crtBtn.MouseButtonState = MouseButtonState.PRESSED;
                                crtBtn.ButtonState = ImageButtonState.PRESSED;
                                crtBtn.DrawButton(m.HWnd);
                            }
                        }
                        break;
                    // WM_NCLBUTTONUP   
                    case 0xA2:
                    case 0x202:
                        //Get current mouse position
                        p.X = ((int)m.LParam << 16) >> 16;// Extract the least significant 16 bits   
                        p.Y = (int)m.LParam >> 16;        // Extract the most significant 16 bits 
                        p.X -= windowRect.Left;
                        p.Y -= windowRect.Top;
    
                        //Call base method
                        base.WndProc(ref m);
                        foreach (TitleBarImageButton crtBtn in titleBarButtons.Values)
                        {
                            //if button is press
                            if (crtBtn.ButtonState == ImageButtonState.PRESSED)
                            {
                                //Rasie button's click event
                                crtBtn.OnClick(EventArgs.Empty);
    
                                if (crtBtn.HitTest(p))
                                    crtBtn.ButtonState = ImageButtonState.HOOVER;
                                else
                                    crtBtn.ButtonState = ImageButtonState.NORMAL;
                            }
    
                            crtBtn.MouseButtonState = MouseButtonState.NOTPESSED;
                            crtBtn.DrawButton(m.HWnd);
                        }
                        break;
                    // WM_NCHITTEST    
                    case 0x84:
                        //Get current mouse position
                        p.X = ((int)m.LParam << 16) >> 16;// Extract the least significant 16 bits
                        p.Y = (int)m.LParam >> 16;        // Extract the most significant 16 bits
                        p.X -= windowRect.Left;
                        p.Y -= windowRect.Top;
    
                        bool isAnyButtonHit = false;
                        foreach (TitleBarImageButton crtBtn in titleBarButtons.Values)
                        {
                            //if mouse is over the button, or mouse is pressed 
                            //(do not process messages when mouse was pressed on a button)
                            if (crtBtn.HitTest(p) || crtBtn.MouseButtonState == MouseButtonState.PRESSED)
                            {
                                //return 18 (do not process further)
                                m.Result = (IntPtr)18;
                                //we have a hit
                                isAnyButtonHit = true;
                                //return 
                                break;
                            }
                            else
                            {//mouse is not pressed and not over the button, redraw button if needed  
                                if (crtBtn.ButtonState != ImageButtonState.NORMAL)
                                {
                                    crtBtn.ButtonState = ImageButtonState.NORMAL;
                                    crtBtn.DrawButton(m.HWnd);
                                }
                            }
                        }
                        //if we have a hit, do not process further
                        if (!isAnyButtonHit)
                            //Call base method
                            base.WndProc(ref m);
                        break;
                    default:
                        //Call base method
                        base.WndProc(ref m);
                        //Console.WriteLine(m.Msg + "(0x" + m.Msg.ToString("x") + ")");
                        break;
                }
    

    The code demonstrates the messages that heve to be treated and how to treat them. The code uses a collection of custom TitleBarButton objets. That class is too big to be included here but I can provide it if needed along with an example.

提交回复
热议问题