2008-09-20 28 views

回答

6

以下将在XP中工作,我没有Vista机器方便测试它,但我认为你的问题源于不正确的HWND。无论如何,与评论不好的代码。

// The state of our little button 
ButtonState _buttState = ButtonState.Normal; 
Rectangle _buttPosition = new Rectangle(); 

[DllImport("user32.dll")] 
private static extern IntPtr GetWindowDC(IntPtr hWnd); 
[DllImport("user32.dll")] 
private static extern int GetWindowRect(IntPtr hWnd, 
             ref Rectangle lpRect); 
[DllImport("user32.dll")] 
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); 
protected override void WndProc(ref Message m) 
{ 
    int x, y; 
    Rectangle windowRect = new Rectangle(); 
    GetWindowRect(m.HWnd, ref windowRect); 

    switch (m.Msg) 
    { 
     // WM_NCPAINT 
     case 0x85: 
     // WM_PAINT 
     case 0x0A: 
      base.WndProc(ref m); 

      DrawButton(m.HWnd); 

      m.Result = IntPtr.Zero; 

      break; 

     // WM_ACTIVATE 
     case 0x86: 
      base.WndProc(ref m); 
      DrawButton(m.HWnd); 

      break; 

     // WM_NCMOUSEMOVE 
     case 0xA0: 
      // Extract the least significant 16 bits 
      x = ((int)m.LParam << 16) >> 16; 
      // Extract the most significant 16 bits 
      y = (int)m.LParam >> 16; 

      x -= windowRect.Left; 
      y -= windowRect.Top; 

      base.WndProc(ref m); 

      if (!_buttPosition.Contains(new Point(x, y)) && 
       _buttState == ButtonState.Pushed) 
      { 
       _buttState = ButtonState.Normal; 
       DrawButton(m.HWnd); 
      } 

      break; 

     // WM_NCLBUTTONDOWN 
     case 0xA1: 
      // Extract the least significant 16 bits 
      x = ((int)m.LParam << 16) >> 16; 
      // Extract the most significant 16 bits 
      y = (int)m.LParam >> 16; 

      x -= windowRect.Left; 
      y -= windowRect.Top; 

      if (_buttPosition.Contains(new Point(x, y))) 
      { 
       _buttState = ButtonState.Pushed; 
       DrawButton(m.HWnd); 
      } 
      else 
       base.WndProc(ref m); 

      break; 

     // WM_NCLBUTTONUP 
     case 0xA2: 
      // Extract the least significant 16 bits 
      x = ((int)m.LParam << 16) >> 16; 
      // Extract the most significant 16 bits 
      y = (int)m.LParam >> 16; 

      x -= windowRect.Left; 
      y -= windowRect.Top; 

      if (_buttPosition.Contains(new Point(x, y)) && 
       _buttState == ButtonState.Pushed) 
      { 
       _buttState = ButtonState.Normal; 
       // [[TODO]]: Fire a click event for your button 
       //   however you want to do it. 
       DrawButton(m.HWnd); 
      } 
      else 
       base.WndProc(ref m); 

      break; 

     // WM_NCHITTEST 
     case 0x84: 
      // Extract the least significant 16 bits 
      x = ((int)m.LParam << 16) >> 16; 
      // Extract the most significant 16 bits 
      y = (int)m.LParam >> 16; 

      x -= windowRect.Left; 
      y -= windowRect.Top; 

      if (_buttPosition.Contains(new Point(x, y))) 
       m.Result = (IntPtr)18; // HTBORDER 
      else 
       base.WndProc(ref m); 

      break; 

     default: 
      base.WndProc(ref m); 
      break; 
    } 
} 

private void DrawButton(IntPtr hwnd) 
{ 
    IntPtr hDC = GetWindowDC(hwnd); 
    int x, y; 

    using (Graphics g = Graphics.FromHdc(hDC)) 
    { 
     // Work out size and positioning 
     int CaptionHeight = Bounds.Height - ClientRectangle.Height; 
     Size ButtonSize = SystemInformation.CaptionButtonSize; 
     x = Bounds.Width - 4 * ButtonSize.Width; 
     y = (CaptionHeight - ButtonSize.Height)/2; 
     _buttPosition.Location = new Point(x, y); 

     // Work out color 
     Brush color; 
     if (_buttState == ButtonState.Pushed) 
      color = Brushes.LightGreen; 
     else 
      color = Brushes.Red; 

     // Draw our "button" 
     g.FillRectangle(color, x, y, ButtonSize.Width, ButtonSize.Height); 
    } 

    ReleaseDC(hwnd, hDC); 
} 

private void Form1_Load(object sender, EventArgs e) 
{ 
    _buttPosition.Size = SystemInformation.CaptionButtonSize; 
} 
1

绘画似乎是比较容易的部分,下面将做到这一点:

[编辑:代码删除,请参阅我的其他答案]

真正的问题是不断变化的状态,按钮上检测点击...因为你需要钩入程序的全局消息处理程序,.NET似乎隐藏了表单的鼠标事件,而不是在实际的容器区域(即鼠标移动并点击标题栏) 。我正在寻找有关这方面的信息,现在发现它,我正在研究它,不应该太难......如果我们能够弄清楚这些信息实际上传递了什么。

+0

此代码在Vista中似乎不起作用。 – 2008-09-20 05:21:56

+0

你能定义“不起作用”吗?它不识别这些信息,它不是在绘制?它甚至不会编译? – 2008-09-20 05:47:23

+0

对不起,它运行但绘制的矩形不显示。 – 2008-09-20 05:54:43

2

我知道它已经很长时间以来的最后一个答案,但这真的帮了我最近,我喜欢更新克里斯提供的代码与我的意见和修改。 该版本在Win XP和Win 2003上完美运行。在Win 2008上,有一个小错误,在调整窗口大小时我无法识别。也适用于Vista(无Aero),但请注意,标题栏按钮不是正方形,并且按钮尺寸应考虑到这一点。

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; 
      } 

该代码演示了要处理的消息以及如何处理它们。 该代码使用自定义TitleBarButton对象的集合。这个班级太大而不能包含在这里,但是如果需要的话,我可以提供这个班级和一个例子。

相关问题