2008-09-16 14 views
24

एक सिस्टम के लिए। Windows.Forms.TextBox Multiline = True के साथ, मैं केवल स्क्रॉलबार को दिखाना चाहता हूं जब टेक्स्ट फिट नहीं होता है।मैं System.indows.Forms.TextBox पर केवल स्क्रॉलबार कैसे दिखा सकता हूं जब टेक्स्ट फिट नहीं होता है?

यह केवल पढ़ने के लिए उपयोग किया जाने वाला एक पाठक टेक्स्टबॉक्स है। यह एक टेक्स्टबॉक्स है ताकि उपयोगकर्ता टेक्स्ट कॉपी कर सकें। क्या स्क्रॉलबार के ऑटो शो का समर्थन करने के लिए कुछ भी अंतर्निहित है? यदि नहीं, तो क्या मुझे एक अलग नियंत्रण का उपयोग करना चाहिए? या


WordWrap और स्क्रॉलबार सेटिंग्स के विभिन्न संयोजनों के साथ किसी भी भाग्य के न होने का मैं TextChanged हुक करने और मैन्युअल रूप से अतिप्रवाह के लिए जाँच की आवश्यकता है (यदि हां, तो कैसे करता है, तो पाठ फिट बैठता है बताने के लिए?)। मैं शुरुआत में कोई स्क्रॉलबार नहीं लेना चाहता हूं और प्रत्येक गतिशील रूप से केवल तभी दिखता है जब पाठ दिए गए दिशा में फिट न हो।


@nobugz, धन्यवाद, वर्डवाप अक्षम होने पर यह काम करता है। मैं वर्डव्रैप को अक्षम नहीं करना चाहता, लेकिन यह दो बुराइयों में से कम है।


@ एंड्रे नेव्स, अच्छा बिंदु, और यदि मैं उपयोगकर्ता-संपादन योग्य था तो मैं उस तरह से जाऊंगा। मैं मानता हूं कि यूआई अंतर्ज्ञान के लिए स्थिरता कार्डिनल नियम है।

उत्तर

13

अपनी परियोजना में एक नई कक्षा जोड़ें और नीचे दिखाए गए कोड को पेस्ट करें। संकलित करें। टूलबॉक्स के शीर्ष से अपने फॉर्म पर नया नियंत्रण ड्रॉप करें। यह बिल्कुल सही नहीं है लेकिन आपके लिए काम करना चाहिए।

using System; 
using System.Drawing; 
using System.Windows.Forms; 

public class MyTextBox : TextBox { 
    private bool mScrollbars; 
    public MyTextBox() { 
    this.Multiline = true; 
    this.ReadOnly = true; 
    } 
    private void checkForScrollbars() { 
    bool scroll = false; 
    int cnt = this.Lines.Length; 
    if (cnt > 1) { 
     int pos0 = this.GetPositionFromCharIndex(this.GetFirstCharIndexFromLine(0)).Y; 
     if (pos0 >= 32768) pos0 -= 65536; 
     int pos1 = this.GetPositionFromCharIndex(this.GetFirstCharIndexFromLine(1)).Y; 
     if (pos1 >= 32768) pos1 -= 65536; 
     int h = pos1 - pos0; 
     scroll = cnt * h > (this.ClientSize.Height - 6); // 6 = padding 
    } 
    if (scroll != mScrollbars) { 
     mScrollbars = scroll; 
     this.ScrollBars = scroll ? ScrollBars.Vertical : ScrollBars.None; 
    } 
    } 

    protected override void OnTextChanged(EventArgs e) { 
    checkForScrollbars(); 
    base.OnTextChanged(e); 
    } 

    protected override void OnClientSizeChanged(EventArgs e) { 
    checkForScrollbars(); 
    base.OnClientSizeChanged(e); 
    } 
} 
+4

यह केवल तभी काम करता है जब आप स्पष्ट रूप से टेक्स्ट में न्यूलाइन जोड़ रहे हों। यदि आप वर्ड रैप के साथ टेक्स्ट की एक लंबी लाइन दिखाना चाहते हैं, तो यह दृष्टिकोण काम नहीं करता है, क्योंकि टेक्स्टबॉक्स। लाइन हमेशा रहेगी 1. बस सोचा कि मैं इसे वहां फेंक दूंगा, क्योंकि यही वह मामला था जिसे मैं ढूंढ रहा था और इसने समस्या को हल नहीं किया। – Tim

+0

ओपी में पहले से ही उल्लेख किया गया है। सहायता खोजने के लिए प्रश्न पूछें बटन पर क्लिक करें। –

7

मैंने कुछ प्रयोग भी किए, और पाया कि वर्टिकल बार हमेशा दिखाएगा यदि आप इसे सक्षम करते हैं, और क्षैतिज बार हमेशा तब तक दिखाता है जब तक यह सक्षम हो और WordWrap == false

मुझे लगता है कि आप जो भी चाहते हैं उसे पाने के लिए नहीं जा रहे हैं। हालांकि, मेरा मानना ​​है कि उपयोगकर्ता जो आप मजबूर करने की कोशिश कर रहे हैं उससे बेहतर विंडोज़ का डिफ़ॉल्ट व्यवहार पसंद करेंगे। अगर मैं आपके ऐप का उपयोग कर रहा था, तो शायद मुझे परेशान किया जाएगा यदि मेरी टेक्स्टबॉक्स रीयल-एस्टेट अचानक ही कम हो गई है क्योंकि इसे एक अप्रत्याशित स्क्रॉलबार को समायोजित करने की आवश्यकता है क्योंकि मैंने इसे बहुत अधिक टेक्स्ट दिया है!

शायद यह आपके विचार को विंडोज़ के स्वरूप और अनुभव का पालन करने के लिए एक अच्छा विचार होगा।

31

मैं इस प्रश्न पर आया जब मैं एक ही समस्या को हल करना चाहता था।

ऐसा करने का सबसे आसान तरीका System.Windows.Forms.RichTextBox में बदलना है। इस मामले में स्क्रॉलबार संपत्ति को RichTextBoxScrollBars.Both के डिफ़ॉल्ट मान पर छोड़ा जा सकता है, जो इंगित करता है "आवश्यकता होने पर एक क्षैतिज और लंबवत स्क्रॉल बार दोनों प्रदर्शित करें।" यह अच्छा होगा अगर यह कार्यक्षमता टेक्स्टबॉक्स पर प्रदान की गई हो।

+2

+1: सरल, इसके बजाय RichTextBox का उपयोग करें। मेरे लिए काम किया धन्यवाद लक्स – MattH

+6

दिमाग में ध्यान रखें RichTextBox आरटीएफ पाठ के लिए बनाया गया है और एक मल्टीलाइन टेक्स्टबॉक्स की तुलना में एक भारी प्रतिपादन और प्रसंस्करण लागत भालू है। जब तक आप समृद्ध टेक्स्ट प्रदर्शित नहीं करना चाहते हैं, तब तक मैं इसका उपयोग करने के खिलाफ सलाह दूंगा। – Camille

+2

मैंने इस रिचटेक्स्टबॉक्स समाधान का उपयोग किया है, बिना नकारात्मक साइड इफेक्ट्स। मेरा मानना ​​है कि ज्यादातर मामलों में केमिली की चिंता जरूरी नहीं है। धन्यवाद उपयोगकर्ता 738 9 2। –

6

नोबगज़ के समाधान में एक बेहद सूक्ष्म बग है जिसके परिणामस्वरूप ढेर भ्रष्टाचार होता है, लेकिन केवल तभी आप टेक्स्टबॉक्स को अपडेट करने के लिए AppendText() का उपयोग कर रहे हैं।

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

तो कहानी का नैतिक है: यदि आप nobugz के समाधान का उपयोग करने जा रहे हैं तो AppendText() का उपयोग न करें।

+0

मेरे पास एक एक्सेस उल्लंघन समस्या है जो टेक्स्टबॉक्स (http://stackoverflow.com/q/7458915/68936) के साथ एक फॉर्म प्रदर्शित करने से संबंधित प्रतीत होता है। आपकी पोस्ट देखने के बाद, मैंने सोचा कि यह AppendText() को कॉल करने के कारण हो सकता है। हालांकि, मैंने केवल टेक्स्टबॉक्स के साथ ऐपेंडटेक्स्ट में कॉल को बदल दिया। टेक्स्ट =, और एक्सेस उल्लंघन अभी भी थोड़ी देर में होता है। आपके उत्तर से, क्या मैं समझ सकता हूं कि TextBox.Text = ठीक होना चाहिए, और AppendText() नहीं? या क्या वे दोनों एक ही मुद्दे से पीड़ित हैं (क्या वे दोनों ऑनटेक्स्ट चेंज नहीं करेंगे?) – Jimmy

2

मुझे नीचे दिए गए कोड के साथ कुछ सफलता मिली थी।

public partial class MyTextBox : TextBox 
    { 
    private bool mShowScrollBar = false; 

    public MyTextBox() 
    { 
     InitializeComponent(); 

     checkForScrollbars(); 
    } 

    private void checkForScrollbars() 
    { 
     bool showScrollBar = false; 
     int padding = (this.BorderStyle == BorderStyle.Fixed3D) ? 14 : 10; 

     using (Graphics g = this.CreateGraphics()) 
     { 
     // Calcualte the size of the text area. 
     SizeF textArea = g.MeasureString(this.Text, 
             this.Font, 
             this.Bounds.Width - padding); 

     if (this.Text.EndsWith(Environment.NewLine)) 
     { 
      // Include the height of a trailing new line in the height calculation   
      textArea.Height += g.MeasureString("A", this.Font).Height; 
     } 

     // Show the vertical ScrollBar if the text area 
     // is taller than the control. 
     showScrollBar = (Math.Ceiling(textArea.Height) >= (this.Bounds.Height - padding)); 

     if (showScrollBar != mShowScrollBar) 
     { 
      mShowScrollBar = showScrollBar; 
      this.ScrollBars = showScrollBar ? ScrollBars.Vertical : ScrollBars.None; 
     } 
     } 
    } 

    protected override void OnTextChanged(EventArgs e) 
    { 
     checkForScrollbars(); 
     base.OnTextChanged(e); 
    } 

    protected override void OnResize(EventArgs e) 
    { 
     checkForScrollbars(); 
     base.OnResize(e); 
    } 
    } 
0

क्या एडन का वर्णन लगभग ठीक यूआई परिदृश्य मैं का सामना करना पड़ रहा है। चूंकि टेक्स्ट बॉक्स केवल पढ़ा जाता है, मुझे टेक्स्ट चेंजड का जवाब देने की आवश्यकता नहीं है। और मैं ऑटो-स्क्रॉल पुनर्मूल्यांकन में देरी करना पसंद करूंगा ताकि खिड़की का आकार बदलते समय प्रति सेकंड दर्जनों बार गोलीबारी न हो।

अधिकांश यूआई के लिए, लंबवत और क्षैतिज स्क्रॉल बार दोनों के साथ टेक्स्ट बॉक्स, अच्छी तरह से, बुराई हैं, इसलिए मुझे केवल लंबवत स्क्रॉल बार में रुचि है।

मैंने यह भी पाया कि MeasureString ने उस ऊंचाई को बनाया जो वास्तव में आवश्यकतानुसार बड़ा था। किसी भी सीमा के साथ टेक्स्ट बॉक्स की पसंदीदा हाइट का उपयोग करके लाइन ऊंचाई बेहतर परिणाम देती है।

निम्नलिखित सीमा के साथ या बिना, बहुत अच्छी तरह से काम करता प्रतीत होता है, और यह वर्डव्रैप पर काम करता है।

बस जब आप इसकी आवश्यकता हो तो ऑटोस्क्रॉल वर्टिकली() को कॉल करें, और वैकल्पिक रूप से recalculateOnResize निर्दिष्ट करें।

public class TextBoxAutoScroll : TextBox 
{ 
    public void AutoScrollVertically(bool recalculateOnResize = false) 
    { 
     SuspendLayout(); 

     if (recalculateOnResize) 
     { 
      Resize -= OnResize; 
      Resize += OnResize; 
     } 

     float linesHeight = 0; 
     var borderStyle = BorderStyle; 

     BorderStyle  = BorderStyle.None; 

     int textHeight = PreferredHeight; 

     try 
     { 
      using (var graphics = CreateGraphics()) 
      { 
       foreach (var text in Lines) 
       { 
        var textArea = graphics.MeasureString(text, Font); 

        if (textArea.Width < Width) 
         linesHeight += textHeight; 
        else 
        { 
         var numLines = (float)Math.Ceiling(textArea.Width/Width); 

         linesHeight += textHeight * numLines; 
        } 
       } 
      } 

      if (linesHeight > Height) 
       ScrollBars = ScrollBars.Vertical; 
      else 
       ScrollBars = ScrollBars.None; 
     } 
     catch (Exception ex) 
     { 
      System.Diagnostics.Debug.WriteLine(ex); 
     } 
     finally 
     { 
      BorderStyle = borderStyle; 

      ResumeLayout(); 
     } 
    } 

    private void OnResize(object sender, EventArgs e) 
    { 
     m_timerResize.Stop(); 

     m_timerResize.Tick -= OnDelayedResize; 
     m_timerResize.Tick += OnDelayedResize; 
     m_timerResize.Interval = 475; 

     m_timerResize.Start(); 
    } 

    Timer m_timerResize = new Timer(); 

    private void OnDelayedResize(object sender, EventArgs e) 
    { 
     m_timerResize.Stop(); 

     Resize -= OnResize; 

     AutoScrollVertically(); 

     Resize += OnResize; 
    } 
} 
संबंधित मुद्दे