Avatar of CodeWrangler
CodeWrangler
 asked on

Need to add a 'Ruler' to a .Net textbox (windows forms application)

Hello,

I need to add a ruler to a textbox in my windows forms project in Visual Studio 2008. The textbox will not accept anything more than 125 characters, hence the ruler above it should go from 0 to 125 with the 10's highlighted.

                     10                  20
|||||||||||||||||||||||||

thats a rather awkward representation of what I want, but you get the idea. I imagine that this ruler will depend somewhat on the font the textbox will use as well.

Thanks in advance.
.NET ProgrammingVisual C++.NETC#

Avatar of undefined
Last Comment
kaufmed

8/22/2022 - Mon
kaufmed

Would it be simpler to have a label next to the box whose text updated with the number of characters remaining (or consumed), like you typically see on the web?
CodeWrangler

ASKER
Hi Kaufmed.

Yes, I agree that it would, however, design requirements are design requirements and I need a ruler on top of the textbox :)
kaufmed

Are you restricting your available font's to monospaced fonts? I don't know that you can guarantee a proportional scale for non-monspaced fonts. A "w" in a non-monspaced font is going to be much wider than an "i" in that same font.
Your help has saved me hundreds of hours of internet surfing.
fblack61
kaufmed

...or does the ruler just need to span the width of the TB, disregarding the actual width of the text within the TB?
CodeWrangler

ASKER
Yes, monospaced fonts only. The ruler needs to match the text as closely as possible.
Mike Tomlinson

With the Font set to "Courier New" at a mere 8 Points, the TextBox needs to be about 885 pixels wide to accommodate 125 characters!  Is that acceptable?...
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
CodeWrangler

ASKER
Yes it is. If need be I can have 2 textboxes, and hence 2 rulers. However, at the moment all I need to know is how to create a ruler above a textbox.
kaufmed

For simplicity (I think), you could create a UserControl that contained a TextBox and a Label. The Label would be used to draw the actual ruler, and it would be positioned just above the TextBox. I started playing around with this code, but it is nowhere near perfect. You will need to play with the math a bit, but I think it would give you a start.

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

namespace _27639257
{
    public partial class RulerBox : UserControl
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="RulerBox"/> class.
        /// </summary>
        public RulerBox()
        {
            InitializeComponent();
            this.label1.Left = this.textBox1.ClientRectangle.Left;
        }

        /// <summary>
        /// Handles the FontChanged event of the RulerBox control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void RulerBox_FontChanged(object sender, EventArgs e)
        {
            this.textBox1.Font = this.label1.Font = this.Font;
        }

        /// <summary>
        /// Handles the Paint event of the label1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        private void label1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            SizeF sizeofW = g.MeasureString("W", this.Font, 0, StringFormat.GenericTypographic);
            float halfWidth = (sizeofW.Width / 2F);
            float halfHeight = (sizeofW.Height / 2F);

            for (float i = (halfWidth + (this.textBox1.Bounds.Left - this.textBox1.ClientRectangle.Left)), x = 1; i < this.ClientRectangle.Width; i += sizeofW.Width, x++)
            {
                if (x % 10 == 0)
                {
                    g.DrawString(x.ToString(), this.Font, Brushes.Black, (i - halfWidth), 1);
                    g.DrawLine(Pens.Black, i, halfHeight + 5, i, this.label1.ClientRectangle.Height);
                }
                else
                {
                    g.DrawLine(Pens.Black, i, halfHeight + 8, i, this.label1.ClientRectangle.Height);
                }
            }
        }

        /// <summary>
        /// Performs the work of setting the specified bounds of this control.
        /// </summary>
        /// <param name="x">The new <see cref="P:System.Windows.Forms.Control.Left"/> property value of the control.</param>
        /// <param name="y">The new <see cref="P:System.Windows.Forms.Control.Top"/> property value of the control.</param>
        /// <param name="width">The new <see cref="P:System.Windows.Forms.Control.Width"/> property value of the control.</param>
        /// <param name="height">The new <see cref="P:System.Windows.Forms.Control.Height"/> property value of the control.</param>
        /// <param name="specified">A bitwise combination of the <see cref="T:System.Windows.Forms.BoundsSpecified"/> values.</param>
        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            base.SetBoundsCore(x, y, width, this.textBox1.Height + this.label1.Height, specified);
        }

        /// <summary>
        /// Handles the Resize event of the RulerBox control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void RulerBox_Resize(object sender, EventArgs e)
        {
            this.label1.Width = this.textBox1.Width = this.Width;
        }
    }
}

Open in new window

kaufmed

Here's what the above looks like in my designer:

Screenshot
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
CodeWrangler

ASKER
Kaufmed, that is a novel idea!!

Can you show me the code where you are actually using the class RulerBox in Form1?
Éric Moreau

kaufmed created a (really nice) user control. if you add it to your project and compile your project, you should see the new control into your toolbox. just drag-and-drop it on your form
CodeWrangler

ASKER
ah yes... my bad. Somewhat of a .Net noob here. I will continue to try this out and report back.

Kaufmed.. again, that is a truly great suggestion!
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
CodeWrangler

ASKER
Kaufmed, may I have the files for the control u created? I cannot seem to get the code to function quite like your screenshot.
kaufmed

It's what I posted above ( http:#questionCommentsViewInlineCode20-37740539-1 ). You need to add a new UserControl (Project->Add New Item->User Control), then add a Label and a TextBox to the UserControl. You can paste the code above into the code-behind for the UserControl. Note:  You need to change the namespace to match your project.
CodeWrangler

ASKER
Appreciate all your help.
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
kaufmed

If you still have problems, I'll attach a complete project so you can compare.
CodeWrangler

ASKER
Thanks, Kaufman. Unfortunately I haven't been able to test the code again. Probably won't get the chance until next week. If it is not too much trouble could you post the project file, it will make things a lot easier for me.
kaufmed

Sure. I can't remember which machine I created it on. If I can't track it down, then I'll recreate it. I'll have something up for you later tonight.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
CodeWrangler

ASKER
No rush whatsoever. Thanks a ton Kaufmed!!
ASKER CERTIFIED SOLUTION
kaufmed

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.