2008-09-20 10 views
7

कैसे आप एक कस्टम बटन फॉर्म की शीर्षकबार भीतर छोटा करना, बड़ा और करीब बटन के बगल में आकर्षित करते हैं?विंडोज फॉर्म के साथ विंडो टाइटलबार में कस्टम बटन कैसे आकर्षित करें?

मैं तुम्हें Win32 API कॉल का उपयोग करें और WndProc प्रक्रिया ओवरराइड करने के लिए की जरूरत है पता है, लेकिन मैं एक समाधान है कि सही काम करता है यह पता लगाने के लिए सक्षम नहीं किया गया है।

क्या कोई यह जानता है कि यह कैसे करें? अधिक विशेष रूप से, क्या किसी को ऐसा करने का तरीका पता है जो Vista में काम करता है?

उत्तर

6

निम्नलिखित XP में काम करेंगे, मुझे कोई Vista मशीन यह परीक्षण करने के लिए काम किया है, लेकिन मुझे लगता है कि अपने मुद्दों को किसी भी तरह कोई गलत hWnd से steming कर रहे हैं। वैसे भी, खराब टिप्पणी कोड के साथ।

// 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; 
} 
+0

यह अभी भी Vista में ग्राफिकल रूप से प्रदर्शित नहीं होता है। फिर भी सहायता के लिए धन्यवाद। –

+0

लाल आयत कि Windows 8 पर और इसके बाद के संस्करण (incl। Win10 तकनीक और अंदरूनी सूत्र पूर्वावलोकन) शीर्षक पट्टी (विंडो फ्रेम के अंदर) के नीचे प्रदर्शित करता है। मैं इसे काम करने की उम्मीद नहीं कर रहा था, लेकिन सोचा कि मैं आपको बताने के लिए वैसे भी टिप्पणी करूंगा। – NDEIGU

1

आहरण आसान हिस्सा प्रतीत हो रहा है, निम्नलिखित है कि क्या करेंगे:

:

[संपादित करें कोड हटा दिया, मेरे अन्य उत्तर देखें] वास्तविक समस्या राज्य बदल रहा है और बटन के क्लिक को पता लगा रहा है ... इसके लिए आपको कार्यक्रम के लिए वैश्विक संदेश हैंडलर में हुक करने की आवश्यकता होगी, .NET वास्तविक कंटेनर क्षेत्रों में नहीं (जबकि माउस चाल और टाइटल बार पर क्लिक) के दौरान माउस ईवेंट को छिपाने के लिए प्रतीत होता है। । मैं उस पर जानकारी ढूंढ रहा हूं, इसे अभी मिला, मैं इस पर काम कर रहा हूं, बहुत कठिन नहीं होना चाहिए ... अगर हम यह पता लगा सकते हैं कि ये संदेश वास्तव में क्या गुजर रहे हैं।

+0

इस कोड Vista में काम करने के लिए प्रतीत नहीं होता। –

+0

क्या आप परिभाषित कर सकते हैं "काम नहीं करता"? यह संदेशों को पहचान नहीं रहा है, यह ड्राइंग नहीं कर रहा है? यह संकलन भी नहीं करेगा? –

+0

क्षमा करें, यह चलता है लेकिन खींचा आयत स्पष्ट रूप से प्रदर्शित नहीं होता है। –

2

मैं जानता हूँ कि यह लंबे समय तक इस सवाल का जवाब के बाद से किया गया है, लेकिन यह वास्तव में मुझे हाल ही में मदद की है और मैं अपने टिप्पणियों और संशोधनों के साथ क्रिस द्वारा प्रदान की कोड को अपडेट करना चाहते। संस्करण विन XP और विन 2003 को पूरी तरह से चलाता है जीत 2008 OT एक छोटे से बग है कि मैं पहचान करने के लिए, जब खिड़कियों का आकार बदलने में सक्षम नहीं था है। Vista पर भी काम करता है (नो-एयरो) लेकिन ध्यान दें कि शीर्षक बार बटन स्क्वायर नहीं हैं और बटन आयामों को ध्यान में रखना चाहिए।

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 objets के संग्रह का उपयोग करता है। उस वर्ग को यहां शामिल करने के लिए बहुत बड़ा है, लेकिन उदाहरण के साथ यदि आवश्यक हो तो मैं इसे प्रदान कर सकता हूं।

+0

मुझे इस पर बहुत दिलचस्पी है। क्या आप प्रदर्शन के लिए उदाहरण प्रदान करेंगे? धन्यवाद। – Gnought

+0

"WM_PAINT" आदि वाली टिप्पणियां स्विच मामलों में संख्यात्मक मानों के साथ सही ढंग से सहसंबंध नहीं करती हैं। उदाहरण के लिए 0x0A WM_ENABLE है, WM_PAINT नहीं। और कुछ अन्य हैं। मुझे लगता है कि संख्यात्मक मान सही हैं, और टिप्पणियां हैं जिन्हें सुधार की आवश्यकता है, लेकिन मैं सुनिश्चित किए बिना संपादन का सुझाव नहीं देना चाहता हूं। –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^