Windows Develop Bookmark and Share   
 index > Windows Forms Designer > How Do I: show TextBox.ScrollBars only when needed
 

How Do I: show TextBox.ScrollBars only when needed

I want to create a method that maked the scrollbars of a textbox control visible only if needed.

I tried to use the following method but it doesn't always work, because some times is the control's width much bigger than the Height (I am talking when the WordWrap is set to False):

Code Snippet
Private Sub TextBox1_TextChanged(ByVal sender As TextBox, ByVal e As System.EventArgs) _
Handles TextBox1.TextChanged, TextBox1.Resize, TextBox1.FontChanged

Dim fS As Size = TextRenderer.MeasureText(sender.Text, sender.Font)
Dim cS As Integer = fS.Height * fS.Width
Dim dS As Integer = sender.Size.Height * sender.Size.Width
If dS < cS Then
sender.ScrollBars = ScrollBars.Both
Else
sender.ScrollBars = ScrollBars.None
End If
End Sub


so here is some findings about the text box's control behaviour, maybe it's gonna be useful:

	these numbers just bellow (123456) charachterize th number of lines
1 2 3 4 5 6

10 6 22 38 54 70 86 16^
11 6 24 42 60 78 96 18^
12 6 26 46 66 86 106 20^
13 6 28 50 72 94 126 22^
0 2 4 6 8 10 ^the numbers in this col. are the control's increment per font against line
^this column is the textbox's font's size

the numbers within the table (6,22,38~72,94,126) are the Size.Height of the control, corresponding to font size and line numbers.


also notice that the default Hscrollbar's Height is 57.


well I don't want to waste your time,
does any body have any solution?

thanks for your time.

Shimmy Weitzhandler  Sunday, April 13, 2008 2:13 AM

Well, this did the trick for me:

VB:

PublicClassForm1
FriendWithEventstbAsNewTextBox
PrivateSubForm1_Load(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesMyBase.Load
Withtb
.Multiline=True
.Dock=DockStyle.Fill
.ScrollBars=ScrollBars.Both
.WordWrap=False
EndWith
Controls.Add(tb)
EndSub
PrivateSubtbScroll(ByValsenderAsTextBox,ByValeAsEventArgs)Handlestb.ClientSizeChanged,tb.TextChanged
StaticbusyAsBoolean
IfbusyThenExitSub
busy=True
Withsender
DimtS=TextRenderer.MeasureText(.Text,.Font)
DimHsb=.ClientSize.Height<tS.Height+.Font.Size
DimVsb=.ClientSize.Width<tS.Width
IfHsbAndVsbThen
.ScrollBars=ScrollBars.Both
ElseIfNotHsbAndNotVsbThen
.ScrollBars=ScrollBars.None
ElseIfHsbAndNotVsbThen
.ScrollBars=ScrollBars.Vertical
Else
.ScrollBars=ScrollBars.Horizontal
EndIf
EndWith
busy=False
EndSub
EndClass



C#:

usingSystem;
usingSystem.Drawing;
usingSystem.Windows.Forms;
namespaceWindowsFormsApplication1
{
publicpartialclassForm1:Form
{
publicForm1()
{
InitializeComponent();
TextBoxtb=newTextBox(){Multiline=true,Dock=DockStyle.Fill,ScrollBars=ScrollBars.Both,WordWrap=false};
EventHandlereh=newEventHandler(tb_Changed);
tb.TextChanged+=eh;
tb.ClientSizeChanged+=eh;
Controls.Add(tb);
}
privateboolbusy=false;
voidtb_Changed(objectsender,EventArgse)
{
if(busy)return;
busy=true;
TextBoxtb=senderasTextBox;
SizetS=TextRenderer.MeasureText(tb.Text,tb.Font);
boolHsb=tb.ClientSize.Height<tS.Height+Convert.ToInt32(tb.Font.Size);
boolVsb=tb.ClientSize.Width<tS.Width;
if(Hsb&&Vsb)
tb.ScrollBars=ScrollBars.Both;
elseif(!Hsb&&!Vsb)
tb.ScrollBars=ScrollBars.None;
elseif(Hsb&&!Vsb)
tb.ScrollBars=ScrollBars.Vertical;
elseif(!Hsb&&Vsb)
tb.ScrollBars=ScrollBars.Horizontal;
sender=tbasobject;
busy=false;
}
}
}


Enjoy!

Shimmy Weitzhandler  Sunday, April 13, 2008 10:37 AM

Hi,

Here is another solution I wrote which counts the number of displayed lines of text and compute their height.

Then, it is easy to compare this height with the textbox's one.

Code Snippet

/// <summary>

/// Sets or unsets the scrollbars on the lblErrorMessage control upon its size and content

/// </summary>

private void SetErrorMessageScrollbars()

{

// Set or remove the error text box Vertical scrollbar

// according to the text inside:

// Count the number of required displayed lines per line of text in the "Text"

//property:

string[] lines = this.lblErrorMessage.Lines;

int nbDisplayedLines = 0;

Size textSize;

if (lines != null)

{

foreach (string line in lines)

{

textSize = TextRenderer.MeasureText(line, this.lblErrorMessage.Font);

nbDisplayedLines += (int)(Math.Ceiling((decimal)textSize.Width / this.lblErrorMessage.Width));

}

}

// Search the height of one line:

textSize = TextRenderer.MeasureText("Lp", this.lblErrorMessage.Font);

// CAUTION: DON'T USE PreferedHeight HERE. IT DOESN'T WORK.

// CAUTION 2: PreferredSize works only if not resizing the window!

if (nbDisplayedLines * textSize.Height> this.lblErrorMessage.Size.Height)

{

// There are more text than can be displayed:

this.lblErrorMessage.ScrollBars = ScrollBars.Vertical;

}

else

{

// No much text, so remove the vertical scrollbar:

this.lblErrorMessage.ScrollBars = ScrollBars.None;

}

// Need to add a refresh on the error message text box. Sometimes,

// it doesn't refresh its content:

this.lblErrorMessage.Invalidate();

}

Hope this helps.

Haribo007  Wednesday, April 16, 2008 9:52 AM

yes, but this will not work properly if the propety wrap lines is set to true

and also the previouscode works also for the horizontal scrollbar as well as you can freely resize the control.

anyway thanks for sharing us with your ideas.

Shimmy Weitzhandler  Wednesday, April 16, 2008 11:28 AM
Fortunately somebody else in Microsoft racked his headand created this wonderful function that does the jobthat isTextRenderer.MeasureTextfor us, so we don't need to count lines.

I updated my previous code, please take a look.

Thanks
Shimmy Weitzhandler  Saturday, February 28, 2009 10:12 PM

Hi,

Honestly speaking, I have never tried it out, but you can get some clues over here

http://pinvoke.net/default.aspx/user32/ShowScrollBar.html

HTH,
Suprotim Agarwal

Suprotim Agarwal  Sunday, April 13, 2008 2:22 AM

hello dear suprotim and thanks for your quick response.

what I don't understand is, since when has a PictureBox a Font property????

I am using VB.NET and not VB 6

could you help me doing it pls?

Shimmy Weitzhandler  Sunday, April 13, 2008 2:52 AM

Well, this did the trick for me:

VB:

PublicClassForm1
FriendWithEventstbAsNewTextBox
PrivateSubForm1_Load(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesMyBase.Load
Withtb
.Multiline=True
.Dock=DockStyle.Fill
.ScrollBars=ScrollBars.Both
.WordWrap=False
EndWith
Controls.Add(tb)
EndSub
PrivateSubtbScroll(ByValsenderAsTextBox,ByValeAsEventArgs)Handlestb.ClientSizeChanged,tb.TextChanged
StaticbusyAsBoolean
IfbusyThenExitSub
busy=True
Withsender
DimtS=TextRenderer.MeasureText(.Text,.Font)
DimHsb=.ClientSize.Height<tS.Height+.Font.Size
DimVsb=.ClientSize.Width<tS.Width
IfHsbAndVsbThen
.ScrollBars=ScrollBars.Both
ElseIfNotHsbAndNotVsbThen
.ScrollBars=ScrollBars.None
ElseIfHsbAndNotVsbThen
.ScrollBars=ScrollBars.Vertical
Else
.ScrollBars=ScrollBars.Horizontal
EndIf
EndWith
busy=False
EndSub
EndClass



C#:

usingSystem;
usingSystem.Drawing;
usingSystem.Windows.Forms;
namespaceWindowsFormsApplication1
{
publicpartialclassForm1:Form
{
publicForm1()
{
InitializeComponent();
TextBoxtb=newTextBox(){Multiline=true,Dock=DockStyle.Fill,ScrollBars=ScrollBars.Both,WordWrap=false};
EventHandlereh=newEventHandler(tb_Changed);
tb.TextChanged+=eh;
tb.ClientSizeChanged+=eh;
Controls.Add(tb);
}
privateboolbusy=false;
voidtb_Changed(objectsender,EventArgse)
{
if(busy)return;
busy=true;
TextBoxtb=senderasTextBox;
SizetS=TextRenderer.MeasureText(tb.Text,tb.Font);
boolHsb=tb.ClientSize.Height<tS.Height+Convert.ToInt32(tb.Font.Size);
boolVsb=tb.ClientSize.Width<tS.Width;
if(Hsb&&Vsb)
tb.ScrollBars=ScrollBars.Both;
elseif(!Hsb&&!Vsb)
tb.ScrollBars=ScrollBars.None;
elseif(Hsb&&!Vsb)
tb.ScrollBars=ScrollBars.Vertical;
elseif(!Hsb&&Vsb)
tb.ScrollBars=ScrollBars.Horizontal;
sender=tbasobject;
busy=false;
}
}
}


Enjoy!

Shimmy Weitzhandler  Sunday, April 13, 2008 10:37 AM

Hi,

Great. Thanks for sharingthe solutionacross.

HTH,
Suprotim Agarwal

Suprotim Agarwal  Sunday, April 13, 2008 12:04 PM

Hi,

Here is another solution I wrote which counts the number of displayed lines of text and compute their height.

Then, it is easy to compare this height with the textbox's one.

Code Snippet

/// <summary>

/// Sets or unsets the scrollbars on the lblErrorMessage control upon its size and content

/// </summary>

private void SetErrorMessageScrollbars()

{

// Set or remove the error text box Vertical scrollbar

// according to the text inside:

// Count the number of required displayed lines per line of text in the "Text"

//property:

string[] lines = this.lblErrorMessage.Lines;

int nbDisplayedLines = 0;

Size textSize;

if (lines != null)

{

foreach (string line in lines)

{

textSize = TextRenderer.MeasureText(line, this.lblErrorMessage.Font);

nbDisplayedLines += (int)(Math.Ceiling((decimal)textSize.Width / this.lblErrorMessage.Width));

}

}

// Search the height of one line:

textSize = TextRenderer.MeasureText("Lp", this.lblErrorMessage.Font);

// CAUTION: DON'T USE PreferedHeight HERE. IT DOESN'T WORK.

// CAUTION 2: PreferredSize works only if not resizing the window!

if (nbDisplayedLines * textSize.Height> this.lblErrorMessage.Size.Height)

{

// There are more text than can be displayed:

this.lblErrorMessage.ScrollBars = ScrollBars.Vertical;

}

else

{

// No much text, so remove the vertical scrollbar:

this.lblErrorMessage.ScrollBars = ScrollBars.None;

}

// Need to add a refresh on the error message text box. Sometimes,

// it doesn't refresh its content:

this.lblErrorMessage.Invalidate();

}

Hope this helps.

Haribo007  Wednesday, April 16, 2008 9:52 AM

yes, but this will not work properly if the propety wrap lines is set to true

and also the previouscode works also for the horizontal scrollbar as well as you can freely resize the control.

anyway thanks for sharing us with your ideas.

Shimmy Weitzhandler  Wednesday, April 16, 2008 11:28 AM

Hi Shimmy,

can you tell me how your code works when you have a multiline textboxfor whichyou need to display a vertical scrollbar. I've looked at the code and can't see how you can get the height of the text (which would presumably be the height of the font x the number of completely visible lines displayable in the textbox).

Thanks

Ross Watson  Monday, November 03, 2008 5:05 PM
Fortunately somebody else in Microsoft racked his headand created this wonderful function that does the jobthat isTextRenderer.MeasureTextfor us, so we don't need to count lines.

I updated my previous code, please take a look.

Thanks
Shimmy Weitzhandler  Saturday, February 28, 2009 10:12 PM

You can use google to search for other answers

Custom Search

More Threads

• Loading VB.NET Code Into A Designer
• Problem to save collection property [VB.NET]
• similar to horizontal tree view in windows application
• Multiline Attribute used in TextBox.Text property
• problem with the collection control
• I cannot get designer view....
• How can view custom datagrid to windows forms designer?
• using windows controls with unmanaged code
• AutoValidation problem with windows forms
• IE Container in WinForm