如何在打印字符串之前预先测量它的长度?

6

这是一份纸质表格的草图 你好,我正在学习使用C# VS 2010 EE进行编程,并制作一个填写预印表格的应用程序。该表格在不同坐标上有几个位置。纸张上的三个方框都是多行的,尺寸为5“ W x 2” H。

我已经创建了具有每个纸质表格位置的一个TextBox的窗体。

问题在于,在这些多行TextBoxes中输入信息时,我需要知道纸张上还有多少行可以输入更多文本,以及何时停止输入,因为预印的方框没有更多空间可用。

我已经做了很多搜索,但所有我找到的内容都是关于在屏幕上测量,这与最终结果不符合。

换言之,我需要知道如何找出文本在TextBoxes中被键入时在纸上的字符串尺寸,然后将其与可用于预印表格中的空间进行比较,以便在超过纸上方框的底部边界之前停止。

纸上的第一个方框宽度为5“,高度为2”,从“new RectangleF(60.0F, 200.0F, 560.0F, 200.0F)”开始。我理解这些数字是英寸的百分之一。

所有这些,考虑到我不能通过字符数量限制TextBoxes,因为不是所有字符占用相同的空间,例如H != I;M != l;等等。

提前感谢你的帮助。根据您的评论和建议,在今天的2011年9月5日,我已经更改了代码以使用Graphics.MeasureString。

这是我现在拥有的具有Graphics.MeasureString和一个richTextBox的代码: 从printDocument1_PrintPage事件中工作得很完美。但我不知道如何使它从richTextBox1_TextChanged事件中工作

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;//Needed for the PrintDocument()
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Printing
{
  public partial class Form1 : Form
  {
    private Font printFont1;
    string strPrintText;

    public Form1()
    {
      InitializeComponent();
    }

    private void cmdPrint_Click(object sender, EventArgs e)
    {
      try
      {
        PrintDocument pdocument = new PrintDocument();
        pdocument.PrintPage += new PrintPageEventHandler
        (this.printDocument1_PrintPage);
        pdocument.Print();
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message);
      }
    }

    public void printDocument1_PrintPage (object sender,
      System.Drawing.Printing.PrintPageEventArgs e)
    {
      strPrintText = richTextBox1.Text.ToString();
      printFont1 = new Font("Times New Roman", 10); //I had to remove this line from the btnPrintAnexo1_Click
      Graphics g = e.Graphics;
      StringFormat format1 = new StringFormat();
      RectangleF rectfText;
      int iCharactersFitted, iLinesFitted;

      rectfText = new RectangleF(60.0F, 200.0F, 560.0F, 200.0F);
      // The following e.Graphics.DrawRectangle is
      // just for debuging with printpreview
      e.Graphics.DrawRectangle(new Pen(Color.Black, 1F),
        rectfText.X, rectfText.Y, rectfText.Width, rectfText.Height);

      format1.Trimming = StringTrimming.Word; //Word wrapping

      //The next line of code "StringFormatFlags.LineLimit" was commented so the condition "iLinesFitted > 12" could be taken into account by the MessageBox
// Use next line of code if you don't want to show last line, which will be clipped, in rectangleF
      //format1.FormatFlags = StringFormatFlags.LineLimit;

      //Don't use this next line of code. Some how it gave me a wrong linesFilled
      //g.MeasureString(strPrintText, font, rectfFull.Size, 
      //StringFormat.GenericTypographic, out iCharactersFitted, out iLinesFilled);

      //Use this one instead:
      //Here is where we get the quantity of characters and lines used 
      g.MeasureString(strPrintText, printFont1, rectfText.Size, format1, out iCharactersFitted, out iLinesFitted);

      if (strPrintText.Length == 0)
      {
        e.Cancel = true;
        return;
      }
      if (iLinesFitted > 12)
      {
        MessageBox.Show("Too many lines in richTextBox1.\nPlease reduce text entered.");
        e.Cancel = true;
        return;
      }

      g.DrawString(strPrintText, printFont1, Brushes.Black, rectfText, format1);
      g.DrawString("iLinesFilled = Lines in the rectangle: " + iLinesFitted.ToString(), printFont1, Brushes.Black,
        rectfText.X, rectfText.Height + rectfText.Y);
      g.DrawString("iCharactersFitted = Characters in the rectangle: " + iCharactersFitted.ToString(), printFont1, Brushes.Black,
        rectfText.X, rectfText.Height + rectfText.Y + printFont1.Height);
    }

    private void richTextBox1_TextChanged(object sender, EventArgs e)
    {
      //***I don’t know what to type here.*** 

        if (iLinesFitted == 13)
        {
            MessageBox.Show("Too many lines in richTextBox1.\nPlease erase some characters.");
        }
    }

      private void cmdPrintPreview_Click(object sender, EventArgs e)
    {
      printPreviewDialog1.ShowDialog();
    }

    private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
    {
//      strPrintText = richTextBox1.Text;
    }
  }
}

2
你尝试使用过 Graphics.MeasureString 吗? - Jalal Said
这不会很顺利,Winforms不支持分辨率无关的文本呈现。TrueType提示将成为你的敌人,使屏幕上的文本与打印机上的文本略有不同。在换行时,这可能产生很大的差异。考虑使用WPF或Adobe产品。 - Hans Passant
那不可能是基于我的评论 :) 避免用消息框向用户发送垃圾邮件。只需通过不在监视器上显示文本来明确表明文本不会被打印即可。 - Hans Passant
嗨,@Hans Passant,我会遵循您在messageBoxes上的建议。关于text_Change事件问题,问题在于我需要在数据存储到数据库之前限制用户。用户可能需要几天时间来输入填充预印表格的所有信息,当用户决定打印它时,行数和/或字符数量必须在rectangleF限制范围内。 - Alex
你过于专注于告诉用户她做错了什么,而不是帮助她改正。 - Hans Passant
显示剩余3条评论
3个回答

6

我认为这是你想要的。

MeasureString(...)

只需确保你的图形对象是一个PrintDocument即可。

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

namespace GraphicsHandler
{
    public partial class Form1 : Form
    {
        public Form1()
        {
           InitializeComponent();
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            // Check the width of the text whenever it is changed.
            if (checkTextWillFit(textBox1.Text) == true)
            {
                 MessageBox.Show("Entered test is too wide, please reduce the number of characters.");
            }
        }

        private bool checkTextWillFit(string enteredText)
        {
            // Create a handle to the graphics property of the PrintPage object
            Graphics g = pd.PrinterSettings.CreateMeasurementGraphics();
            // Set up a font to be used in the measurement
            Font myFont = new Font("Arial", 12, FontStyle.Regular, GraphicsUnit.Millimeter);
            // Measure the size of the string using the selected font
            // Return true if it is too large
            if (g.MeasureString(enteredText, myFont).Width > 100)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        PrintDocument pd = null;

        private void Form1_Load(object sender, EventArgs e)
        {
            // Initialise the print documnet used to render the printed page
            pd = new PrintDocument();
            // Create the event handler for when the page is printed
            pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
        }

        void pd_PrintPage(object sender, PrintPageEventArgs e)
        {
            // Page printing logic here            
        }
    } 
}

大家好,感谢你们的评论。 我刚刚上传了一张图片,这是我想用这个应用程序填写的纸质表格的草图。打印将一次只有一页,也不会使用所有框。 我将尝试你们的建议,但我甚至不知道如何实现它们。如果你能给我更多的信息,我将非常感激。谢谢。 @ Jalal Aldeen Saa'd - Alex
根据所有的评论和建议,我已经更改了代码以使用Graphics.MeasureString。现在从printDocument1_PrintPage事件中完美地工作,但我需要并不知道如何使其从richTextBox1_TextChanged事件中工作,以便我可以通过MessageBox停止用户并让他们删除richTextBox中的一些文本。我对编程非常陌生;也许你或其他人可以帮助我解决这个问题。提前感谢您的时间。@tinchou - Alex
你好@Jason James,你的代码帮了我“很多”。我将其应用到我的应用程序中,现在它正在工作,正好做我想要的事情。我将发布目前为止运行良好的代码。正如汉斯昨天建议我的那样,最终代码将避免使用MessageBoxes,我想我会添加一个隐藏的标签,上面有大而粗的闪亮红色字母:D。如果你们中有任何更好的建议,请告诉我。非常感谢。 - Alex

1
文本框中的信息将被存储在数据库中,并在某个时候打印在预印表格上。由于纸张上每个方框的空间有限,我必须确保进入数据库的内容不超过纸质表格上每个单元格所能处理的内容。以下是代码,以避免用户输入超过rectangleF所能容纳的行数:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;//Needed for the PrintDocument()
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Printing
{
    public partial class Form1 : Form
    {
        private Font printFont1;
        string strPrintText;

        public Form1()
        {
            InitializeComponent();
        }
        //PrintDocument printDocument1 = null; In ny case it makes this error: 'Printing.Form1' already contains a definition for 'primtDocument1'
        private void Form1_Load(object sender, EventArgs eP)
        {
            PrintDocument pd = new PrintDocument();
            pd.PrintPage += new PrintPageEventHandler
            (this.printDocument1_PrintPage);
        }
        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            // Check the width of the text whenever it is changed.
            if (checkTextWillFit(richTextBox1.Text) == true)
            {
                MessageBox.Show("\nEntered text pruduces too many lines. \n\nPlease reduce the number of characters.", "Too Many Lines");
            }
        }

        private bool checkTextWillFit(string enteredText)
        {
            StringFormat format1 = new StringFormat();
            format1.Trimming = StringTrimming.Word; //Word wrapping
            RectangleF rectfText;
            int iCharactersFitted, iLinesFitted;

            rectfText = new RectangleF(60.0F, 200.0F, 560.0F, 200.0F);
            // Create a handle to the graphics property of the PrintPage object
            Graphics g = printDocument1.PrinterSettings.CreateMeasurementGraphics();

            // Set up a font to be used in the measurement
            Font myFont = new Font("Times New Roman", 10, FontStyle.Regular);

            // Measure the size of the string using the selected font
            // Return true if it is too large
            g.MeasureString(enteredText, myFont, rectfText.Size, format1, out iCharactersFitted, out iLinesFitted);
            if (iLinesFitted > 12)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        private void cmdPrint_Click(object sender, EventArgs e)
        {
            try
            {
                PrintDocument pdocument = new PrintDocument();
                pdocument.PrintPage += new PrintPageEventHandler
                (this.printDocument1_PrintPage);
                pdocument.Print();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public void printDocument1_PrintPage(object sender,
          System.Drawing.Printing.PrintPageEventArgs e)
        {
            strPrintText = richTextBox1.Text.ToString();
            printFont1 = new Font("Times New Roman", 10); //I had to remove this line fromthe btnPrintAnexo1_Click
            Graphics g = e.Graphics;
            //float cyFont = printFont1.GetHeight(g);
            StringFormat format1 = new StringFormat();
            format1.Trimming = StringTrimming.Word; //Word wrapping
            RectangleF rectfText;
            int iCharactersFitted, iLinesFitted;

            rectfText = new RectangleF(60.0F, 200.0F, 560.0F, 200.0F);
            // The following e.Graphics.DrawRectangle is
            // just for debuging with printpreview
            e.Graphics.DrawRectangle(new Pen(Color.Black, 1F),
              rectfText.X, rectfText.Y, rectfText.Width, rectfText.Height);

            //Here is where we get the quantity of characters and lines used 
            g.MeasureString(strPrintText, printFont1, rectfText.Size, format1, out iCharactersFitted, out iLinesFitted);

            if (strPrintText.Length == 0)
            {
                e.Cancel = true;
                return;
            }
            if (iLinesFitted > 12)
            {
                MessageBox.Show("Too many lines in richTextBox1.\nPlease reduce text entered.");
                e.Cancel = true;
                return;
            }

            g.DrawString(strPrintText, printFont1, Brushes.Black, rectfText, format1);
            g.DrawString("iLinesFilled = Lines in the rectangle: " + iLinesFitted.ToString(), printFont1, Brushes.Black,
              rectfText.X, rectfText.Height + rectfText.Y);
            g.DrawString("iCharactersFitted = Characters in the rectangle: " + iCharactersFitted.ToString(), printFont1, Brushes.Black,
              rectfText.X, rectfText.Height + rectfText.Y + printFont1.Height);
        }



        private void cmdPrintPreview_Click(object sender, EventArgs e)
        {
            printPreviewDialog1.ShowDialog();
        }

        private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
        {
            //      strPrintText = richTextBox1.Text;
        }

    }
}

0

你好@tinchou,感谢您的评论。 我刚刚上传了一张图片,这是我想要用这个应用程序填写的纸质表格的草图。打印每次只会有一页,而且并不是所有的框都会被使用。 我会看一下那个链接。问题是我没有使用WPF,我使用的是Windows窗体应用程序。您认为这会有影响吗?谢谢。 - Alex
不幸的是,WPF和WinForms中的打印方式有很大不同。几乎所有WPF元素都是视觉元素,这些元素是基于矢量图形的,可以轻松打印。我从未在WinForms中进行过打印,但我找到了一个链接,其中包含有关WPF的FormattedText和WinForms的DrawText相似之处的信息。http://msdn.microsoft.com/en-us/library/ms752098.aspx#win32_migration。希望这有所帮助。 - Martín Coll
你还应该查看DrawText文档,它可能会为您提供测量格式化文本的简单方法。 - Martín Coll

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接