Calculate Windows Form Width for Displayed Text

2019-08-03 04:26发布

I need to calculate Windows Form Width for displayed text. The form width is obviously in pixels so you would just want to obtain the width of the text in pixels but this doesn't work:

animationForm.Width = TextRenderer.MeasureText(_caption, animationForm.Font).Width;

The calculated form width is way too small (cuts off text) - what is going on here? MeasureText uses pixels, form width is in pixels.

This works better but I don't think is right:

animationForm.Width = (int)(_caption.Length * animationForm.Font.Size);

Help would be appreciated.

AnimationPic - PictureBox, Caption is set on a Label

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace PrlSystems.MaimInvoicing.Forms
{
    public partial class ProgressIndicatorForm : Form
    {
        private volatile bool _animating = false;
        private Form _parent;
        private string _caption = "";

        private object _mutex = new object();

        public ProgressIndicatorForm(Form parent)
        {
            InitializeComponent();
            _parent = parent;
        }

        public string Caption
        {
            set { _caption = value; }
            get { return _caption; }
        }

        public void StartAnimation()
        {
            lock (_mutex)
            {
                if (!_animating)
                {
                    if (_parent != null)
                    {
                        _parent.Cursor = Cursors.WaitCursor;
                        _parent.Enabled = false;
                    }

                    _animating = true;
                    _SpawnAnimationThread();
                }
            }
        }

        public void StopAnimation()
        {
            lock (_mutex)
            {
                if (_animating)
                {
                    _animating = false; // stop animation thread

                    if (_parent != null)
                    {
                        // restore parent form UI
                        _parent.Cursor = Cursors.Default;
                        _parent.Enabled = true;
                        _parent.Activate();
                    }
                }
            }
        }

        private void _SpawnAnimationThread()
        {
            Thread animationThread = new Thread(new ThreadStart(_Animate));
            animationThread.Priority = ThreadPriority.Normal;
            animationThread.IsBackground = true;    // should terminate when application ends
            animationThread.Start();
        }

        private void _Animate()
        {
            ProgressIndicatorForm animationForm = new ProgressIndicatorForm(_parent);
            animationForm.CaptionLabel.Text = _caption;
            animationForm.StartPosition = FormStartPosition.CenterScreen;
            animationForm.TopMost = true;
            animationForm.Width = _CalculateFormWidth(animationForm);

            animationForm.Show();

            while (_animating)
            {
                animationForm.CaptionLabel.Text = _caption;
                animationForm.Width = _CalculateFormWidth(animationForm);

                animationForm.BringToFront();
                animationForm.Refresh();
            }
            animationForm.Close();
            animationForm.Dispose();
        }

        private int _CalculateFormWidth(ProgressIndicatorForm animationForm)
        {
            int width = AnimationPic.Location.X + AnimationPic.Width +
                TextRenderer.MeasureText(_caption, animationForm.Font).Width;


            return width;
        }
    }
}

Image in the designer:

This is how it looks in the designer, the progress dialog

3条回答
祖国的老花朵
2楼-- · 2019-08-03 04:56

You also need to take account the extra sizes such as width of the form. Space around the label(if you are using label?)

查看更多
祖国的老花朵
3楼-- · 2019-08-03 05:13

Rather than Form.Width, you need to use Form.ClientSize.Width.

The latter will return the actual width of the form's client area; i.e., the place where you can draw stuff. From the Remarks section in the documentation:

The size of the client area of the form is the size of the form excluding the borders and the title bar. The client area of a form is the area within a form where controls can be placed. You can use this property to get the proper dimensions when performing graphics operations or when sizing and positioning controls on the form. To get the size of the entire form, use the Size property or use the individual properties Height and Width.

Contrast that with Form.Width (or Form.Size.Width), which returns the entire width of the form as it appears on the screen, including superfluous stuff in the non-client area, like window borders. Definitely don't waste any time trying to calculate and remove the dimensions for these items manually; it's already been done for you.


Using the following code:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    string longStringOfText = "This is a really long string of text we're using for testing purposes.";

    // Resize the form's client area, keeping the same height, but
    // changing the width to match that needed to draw the text.
    this.ClientSize = new Size(TextRenderer.MeasureText(longStringOfText,
                                                        this.Font).Width,
                               ClientSize.Height);

    // Then draw in the text.
    TextRenderer.DrawText(e.Graphics,
                          longStringOfText,
                          this.Font,
                          Point.Empty,
                          Color.Purple);
}

I get this:

Form, with text string correctly fit across it

Looks pretty good to me...

查看更多
霸刀☆藐视天下
4楼-- · 2019-08-03 05:20

Have you tried specifying device context? Try this method overload MeasureText(IDeviceContext, String, Font, Size).

When you use Form.Width, the width contains also width of the window border. Try this:

animationForm.ClientSize.Width = TextRenderer.MeasureText(_caption, animationForm.Font).Width;
查看更多
登录 后发表回答