2010-05-15 15 views
32

मैंने देखा है कि कुछ ऐप्स (शायद नहीं नेट क्षुधा) से बाईं तरफ एक अतिरिक्त बटन है कि कम से कम फार्म का शीर्षक पट्टी पर बटन? मैं इसे सी # में कैसे प्राप्त कर सकता हूं?विंडो के शीर्षक पट्टी में अतिरिक्त बटन कैसे जोड़ें?

+2

ध्यान दें कि आपको यह नहीं करना चाहिए: http://msdn.microsoft.com/en-us/library/aa974173(v=MSDN.10).aspx - »विंडो फ्रेम में नियंत्रण न जोड़ें। इसके बजाय विंडो को नियंत्रण में रखें। « – Joey

+3

@ जोहान्स, मैं कभी-कभी ऐसे ऐप्स स्वीकार करता हूं जो ऐसा करते हैं जो परेशान हो सकते हैं लेकिन कुछ ऐप्स इसे बहुत अच्छी तरह से करते हैं। Ultramon की तरह जो फ्रेम पर मॉनीटर स्वैप करने के लिए एक बटन डालता है जो विंडोज 7 में बहुत मूल दिखता है। ऐसे में ऐसे अनुप्रयोग हैं जो इसे स्वाद से करते हैं। – Josh

+3

@ जोश: ऑफिस 2007 ने यह भी किया (लेकिन यह किसी भी विंडोज यूएक्स दिशानिर्देशों को अनदेखा करने वाली ऑफिस टीम की पहली घटना नहीं है)। फिर भी, यह दस्तावेज़ यूएक्स पेशेवरों द्वारा लिखा गया है और केवल डेवलपर्स (या कोड बंदर) उन्हें अनदेखा करने के लिए कड़ी मेहनत कर रहे हैं। और उपयोगकर्ताओं के लिए मुझे लगता है कि उन्हें सिर्फ साथ ही पालन करना चाहिए, जब तक वे अनुभव और ज्ञान के साथ लोगों को नहीं ला सकते हैं - और सबसे महत्वपूर्ण बात - प्रयोज्यता परीक्षण, अन्यथा साबित करने के लिए। – Joey

उत्तर

32

अद्यतन: एक समाधान है कि एयरो के साथ काम करेंगे विंडोज विस्टा और विंडोज 7 के लिए सक्षम


गैर एयरो समाधान

एक खिड़की बातचीत के गैर क्लाइंट क्षेत्र जोड़ा गया गैर क्लाइंट specfic संदेशों की एक श्रृंखला द्वारा प्रबंधित किया जाता है। उदाहरण के लिए गैर-क्लाइंट क्षेत्र को पेंट करने के लिए WM_NCPAINT संदेश विंडो प्रक्रिया में भेजा जाता है।

मैं इस नेट से कभी नहीं किया है, लेकिन मुझे लगता है आप WndProc overide और प्राप्त करने के लिए आप क्या चाहते हैं WM_NC * संदेशों संभाल कर सकते हैं।

अद्यतन: जब से मैं कभी नहीं नेट से करने की कोशिश की मैं कुछ ही मिनटों हो गया और सोचा था कि मैं यह एक त्वरित आजमाइए होगा।

विंडोज 7 पर इस कोशिश कर रहा है, मैंने पाया कि मैं खिड़की के लिए विषय-वस्तु को निष्क्रिय करने के लिए आवश्यक है कि अगर मैं गैर क्लाइंट क्षेत्र के आधार प्रतिपादन करने के लिए ओएस करना चाहता था। तो यहां एक छोटा परीक्षण है। मैं नहीं बल्कि GetDCEx से पूरी विंडो के डीसी पाने के लिए GetWindowDC प्रयोग किया जाता है, कि था सिर्फ इसलिए कि मैं स्मृति से कि Interop सकता है और GetDcEx लिए सब झंडा स्थिरांक देखने नहीं था। और निश्चित रूप से कोड अधिक त्रुटि जांच के साथ कर सकता है।

using System; 
using System.Drawing; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

namespace WindowsFormsApplication1 
{ 
    public partial class CustomBorderForm : Form 
    { 
    const int WM_NCPAINT = 0x85; 

    [DllImport("user32.dll", SetLastError = true)] 
    public static extern IntPtr GetWindowDC(IntPtr hwnd); 

    [DllImport("user32.dll", SetLastError = true)] 
    public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc); 

    [DllImport("user32.dll", SetLastError = true)] 
    public static extern void DisableProcessWindowsGhosting(); 

    [DllImport("UxTheme.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    public static extern IntPtr SetWindowTheme(IntPtr hwnd, string pszSubAppName, string pszSubIdList); 

    public CustomBorderForm() 
    { 
     // This could be called from main. 
     DisableProcessWindowsGhosting(); 

     InitializeComponent(); 
    } 

    protected override void OnHandleCreated(EventArgs e) 
    { 
     SetWindowTheme(this.Handle, "", ""); 
     base.OnHandleCreated(e); 
    } 

    protected override void WndProc(ref Message m) 
    { 
     base.WndProc(ref m); 

     switch (m.Msg) 
     { 
     case WM_NCPAINT: 
      { 
      IntPtr hdc = GetWindowDC(m.HWnd); 
      using (Graphics g = Graphics.FromHdc(hdc)) 
      { 
       g.FillEllipse(Brushes.Red, new Rectangle((Width-20)/2, 8, 20, 20)); 
      } 
      int r = ReleaseDC(m.HWnd, hdc); 
      } 
      break; 
     } 
    } 
    } 
} 

बीटीडब्ल्यू। मैंने DisableProcessWindowsGhosting कहा, यह ओएस को गैर-क्लाइंट क्षेत्र को खींचने से रोक देगा यदि एप्लिकेशन को विंडोज संदेशों का जवाब देने में बहुत लंबा समय लगता है। यदि आप ऐसा नहीं करते हैं, तो कुछ स्थितियों में सीमा को प्रस्तुत किया जाएगा लेकिन आपके सजावट नहीं दिखाए जाएंगे। तो यह आपकी आवश्यकताओं पर निर्भर करता है जो आपके लिए सही है या नहीं।


एयरो समर्थित समाधान

@TheCodeKing से टिप्पणी से प्रेरित होकर, मैंने सोचा कि मैं इस पर फिर से विचार करेंगे। यह पता चला है कि यह एरो का समर्थन करते हुए पूरी तरह से प्रलेखित तरीके से किया जा सकता है। लेकिन यह दिल की बेहोशी के लिए नहीं है। मैं यहां एक पूरा समाधान नहीं प्रदान करूंगा, अभी भी कसरत के लिए कुछ कंक हैं, लेकिन यह मूल बातें करता है।

इस कोड/समाधान Win32 उदाहरण निम्न स्थान http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx

प्रिंसिपल आप निम्नलिखित है क्या करने की जरूरत में पाया जा सकता है जो बंद आधारित है।

  • फ़्रेम को कवर करने के लिए विंडो के क्लाइंट क्षेत्र को बढ़ाएं। यह WM_NCCALCSIZE संदेश हैंडलिंग और 0. लौटने यह गैर-क्लाइंट क्षेत्र 0 से आकार देता है और इसलिए ग्राहक क्षेत्र पूरी विंडो को शामिल किया गया द्वारा किया जाता है।
  • DwmExtendFrameIntoClientArea का उपयोग कर क्लाइंट क्षेत्र में फ्रेम बढ़ाएं। यह ओएस को क्लाइंट क्षेत्र पर फ्रेम प्रस्तुत करने के लिए मिलता है।

उपर्युक्त चरण आपको सिस्टम मेनू (विंडो आइकन) और शीर्षक को छोड़कर मानक ग्लास फ्रेम के साथ एक विंडो देगा।न्यूनतम, अधिकतम और बंद बटन अभी भी खींचे जाएंगे और काम करेंगे। आप जो करने में सक्षम नहीं होंगे वह खिड़की को खींचें या आकार बदलें, ऐसा इसलिए है क्योंकि फ्रेम वास्तव में वहां नहीं है, याद रखें कि ग्राहक क्षेत्र पूरी विंडो को कवर करता है, हमने अभी ओएस से क्लाइंट क्षेत्र पर फ्रेम खींचने के लिए कहा है।

अब आप फ्रेम के शीर्ष पर भी खिड़की पर सामान्य रूप से आकर्षित कर सकते हैं। आप कैप्शन एरिया में भी नियंत्रण डाल सकते हैं।

अंतिम चरण WM_NCHITTEST संदेश को संभालना है, जहां आप माउस कर्सर की स्थिति की जांच करेंगे और एक संकेतक लौटाएंगे जो विंडो को विंडो के उस क्षेत्र के विंडो को बताता है। उदाहरण के लिए यदि आप HT_CAPTION वापस करते हैं, तो विंडो कार्य करेगी जैसे माउस कैप्शन पर है, और आपको विंडो को खींचने की अनुमति देगा। यह वह फ़ंक्शन है जिसे कस्टम फ्रेम के साथ पूरी तरह कार्यात्मक विंडो रखने के लिए पूर्ण कार्यान्वयन की आवश्यकता होगी ।

+0

यह तकनीक दुर्भाग्य से एयरो ग्लास के साथ काम नहीं करती है। अगर कोई ग्लास पर काम करने के लिए आवश्यक वूडू जानता है तो मुझे दिलचस्पी होगी। अब तक मुझे कोई कामकाजी उदाहरण नहीं मिला है। – TheCodeKing

+0

@TheCodeKing, मैंने आपके प्रश्न को कवर करने के लिए उत्तर अपडेट किया है। मैंने यह भी पुष्टि करने के लिए .NET में प्रोटोटाइप किया है कि इसे काम करने के लिए बनाया जा सकता है। यहां एमएसडीएन आलेख है जिसका मैंने संदर्भ दिया है http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx –

+0

दरअसल जो मुझे याद दिलाता है मुझे पता है कि यह कैसे करना है, मेरे पास कुछ कोड है , यह सिर्फ डिजाइन मोड में प्रस्तुत नहीं किया गया था कि यह रनटाइम पर कैसे देखा।क्या आपके पास वर्णित तकनीक का सी # उदाहरण है, मैंने सबसे अधिक कोशिश की है और वे काम नहीं करते हैं? – TheCodeKing

4

मुझे लगता है कि ऐसा करने का एक तरीका बटन खींचने के लिए WM_NCPAINT संदेश (गैर-क्लाइंट पेंट) को संभालना होगा, और किसी बटन को "बटन" पर क्लिक करने के लिए गैर क्लाइंट माउस क्लिक को संभालना होगा। (अपने कस्टम शीर्षक पट्टी इस हो जाएगा) एक Windows फ़ॉर्म बनाएं

-Set Form Border Style to None 
-Add whatever controls you would like to this 
-I will name this custom form "TitleBarButtons" 

चरण 2. में से है कि आप ऐड में इस कस्टम नियंत्रण का उपयोग करना चाहते:

3

सरल समाधान:

चरण 1

titleBarBtn = new TitleBarButtons(); 
titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5); 
titleBarBtn.Show(); 
titleBarBtn.Owner = this; 
अपने निर्माता के लिए

... आप ऑफसेट के साथ गड़बड़ यह सिर्फ मेरे ऐप के लिए एक अच्छी स्थिति में फिट कर सकते हैं

+०१२३५१६४१०

चरण 3. अपने मुख्य फार्म के लिए कदम घटना जोड़ें

private void Form14_Move(object sender, EventArgs e) 
{ 
    titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5); 
} 

कृपया मुझे बताएं कि आप ऊपर कोड के किसी भी का एक बेहतर स्पष्टीकरण चाहते हैं।

+0

टाइटलबारबटन क्या है? ऐसा लगता है कि इस वर्ग के किसी भी संदर्भ को नहीं मिला है। – Borik

+0

मुझे खेद है कि मुझे एहसास हुआ कि मुझे स्पष्ट नहीं था कि मेरा मानना ​​है कि "टाइटलबार्बटन" एक कदम में बनाया गया कस्टम फॉर्म था। मैं इसे और अधिक स्पष्ट करने के लिए अपने उत्तर को संशोधित करता हूं। – hrh

+0

@hrh सुंदर पुराना धागा हालांकि यह wpf में भी संभव है, wpf विंडो में फ़ॉर्म जोड़ना – murmansk

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