Search code examples
c#winformstexttabsmultiline

Two line Tab Text


I've seen this done in Visual Basic (though I haven't seen the code, or how it is done in design view, if that is possible). Is there way to create a two-line tab name in WinForms? Please see attached picture, I've circled it for emphasis. Surely, there must be a way to do it. In fact the attached picture is done in VB6, which unfortunately I have no access to the code.

Note: If this is a bad idea or not a good practice, please let me know. Also if the solution is too complicated and not worth exploring, I am open to abandoning it, but if it is simple enough, that would help me a lot.

I'm running out of prime real estate on the screen, as some of our forms have 12 tabs on them (it can't be helped), and our screens are limited to a maximum of 1280 x 720. Any help is greatly appreciated.

Unfortunately I am not allowed to post a picture, i.e. this is my first post. If that helps, I will post them somewhere else where it is possible.

Maybe this edit will help for the moment, (sorry for the poor illustration, it's the best I can do given the (posting) editor limitations):


| Tab | Tab | Tab |
|No.1 | No.2| No.3|


The above tab labels (text) should have two lines on the tab names, e.g. Tab 1 No. 1, Tab 2 No. 2, etc. where Tab 1 is on the first line, and No. 1 is on the second line...etc.

Here's the image link: https://i.sstatic.net/yRPQ2.jpg


Solution

  • The full solution is spread over the TabControl and its TabPages.

    To enforce a NewLine you insert a \n in the TabPage's Text.

    tabPage1.Text = "Line one\nLine two";
    

    Note that you need code to set the Text. Setting it in the Designer won't work! (It takes the Backslash literally instead of as an escape sequence and since it only offers a single line field you can't use Shift-Enter either..)

    You still can use the designer, but will have to enforce the newline in code, maybe like this:

    tabPage1.Text = tabPage1.Text.Replace("\\n", "\n");
    

    Or, bettter, in a loop:

    foreach (TabPage tp in tabControl1.TabPages) tp.Text = tp.Text.Replace("\\n", "\n");
    

    To make enough room you enlarge the Tab's ItemSize.Height to say 40 to 48 pixels, of course depending also on the Font!:

    tabControl1.ItemSize = new Size(tabControl1.ItemSize.Width,  42);
    

    Result:

    enter image description here

    Note that the inactive TabPage's Texts' descenders tend to be cut off at the Bottom unless you make the height really large. If that's a problem, I guess you would have to 'owner-draw' the TabControl.Sounds harder than it is..:

    Set the Tabcontrol to owner draw:

    tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
    

    and add this piece of code to the DrawItem event:

    private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
    {
        if ( e.Index == tabControl1.SelectedIndex)
            e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
        else
            e.Graphics.FillRectangle(SystemBrushes.Control, e.Bounds);
    
        TabPage tp = tabControl1.TabPages[e.Index];
    
        Point pt = new Point(e.Bounds.X + 2, e.Bounds.Y + 4);
        e.Graphics.DrawString(tp.Text, tabControl1.Font, SystemBrushes.ControlText, pt);
        e.DrawFocusRectangle();
    }
    

    This is a real space saver; the height is down to 34 pixels resulting in this:

    enter image description here

    One of the nice things is that now you could show the the active page with its backcolor in the tab, too, that is if you have different backcolors for your pages..

    Note however, that since the System doesn't know what you will do in the DrawItem code, it will reserve enough room for the whole, unsplit text, resulting in too broad tabs. You can fix this, if you want to, by storing the real Text in the Tag of each page and making the Text only as long as needed for the longest line:

    if (tp.Tag == null)
    {
       tp.Tag = tp.Text;
       tp.Text = "_____________";  // make large enough!!
    }
    string s = tp.Tag.ToString();
    

    and use string s in the DrawString call!

    If you want to make it perfect you can write a function to measure each TabPage Text and its line break position to find out the necessary width..

    enter image description here