How to split a long text into multiple pieces/pages to fit into a RichTextBox?

给你一囗甜甜゛ 提交于 2020-01-06 14:34:09

问题


While working on a WinForm application, I would like to split a long text (only characters, no images, no special format) into multiple pieces (pages), in order to fit them into a RichTextBox.

The problem is that RichTextBox doesn't support multiple pages.

I have to write my own algorithm (some kind of DP programming) to split the text.

Currently I am using TextRenderer.MeasureText() to check whether a string can fit into the rich textbox, for example:

bool canfit(String str)
{
    Size rbx_size = new Size(rbx.Width, rbx.Height);
    Size sz = TextRenderer.MeasureText(str, rbx.font, rbx_size, TextFormatFlags.WordBreak | TextFormatFlags.GlyOverhangPadding)
    return (sz.Height < rbx_size.Height);
}

It doesn't work very well, because I think the function above is not accurate.

I am wondering if there is an easy way to do it? Thanks.


回答1:


The proposed problem, the way I've interpreted it, is to split the text of a source document in a number of substring (Pages), such as each substring can fit in a RichTextBox client area, without spawning/requiring the scrollbars.

Thus, the first task is to calculate the number of Chuncks/Pages into which a given Document has to be split.

The TextRenderer Class methods are the usual tools.
The class must be instructed, while performing the calculation, to wrap the text (as the RichTextBox control will), exclude any padding and fit the string in a TextBox type control edit area.

The main TextFormatFlags flags will then be:

TextFormatFlags.WordBreak | TextFormatFlags.NoPadding | TextFormatFlags.TextBoxControl;

The next task is to calculate how many letters/symbols will fit in the client area of a RichTextBox control, so that no scroll bars are needed.

The Winforms RichTextBox control doesn't offer any specific tool, but the non-specific ones are enough to perform this calculation.

As a note, the Lines[] property (derived from TextBoxBase) reports only the original text line splitting (intended as line feeds), not the lines generated by the internal word-wrapping.

However, the TextBoxBase GetFirstCharIndexFromLine() and GetLineFromCharIndex() can be used in combination to achieve the same result:
Knowing how many lines can fit in the ClientArea, the first character in the next line will be one character more than the last character of the last visible line in the ClientArea (spaces are not wrapped).
Then, repeated this procedure as far as there are enough lines to fill the ClientArea. The last Page will contain the reminder of [Total Lines] / [Lines per Page].

A visual representation of the results of this procedure:


Sample code that peforms the basic task of calculating the size and splitting the text of a source document. The complete source code used to create sample image: (PasteBin - RTB Reader)

string Document = "[SomeDocumentText]";

List<string> Pages = new List<string>();
TextFormatFlags flags = TextFormatFlags.Top | TextFormatFlags.Left |
                        TextFormatFlags.WordBreak | TextFormatFlags.NoPadding | 
                        TextFormatFlags.TextBoxControl;

Size textSize = TextRenderer.MeasureText(Document, richTextBox1.Font, richTextBox1.ClientSize, flags);
int NumberOfPages = textSize.Height / richTextBox1.ClientSize.Height;

if (textSize.Height > richTextBox1.Height)
{
    richTextBox1.Text = Document;
    richTextBox1.Update();

    //Number of shown lines
    int FirstCharOfLastShownLine = richTextBox1.GetCharIndexFromPosition(new Point(0, richTextBox1.ClientSize.Height));
    int ShownLines = richTextBox1.GetLineFromCharIndex(FirstCharOfLastShownLine);
    int TotalLines = richTextBox1.GetLineFromCharIndex(richTextBox1.Text.Length - 1);

    for (int p = 0; p < NumberOfPages; p++)
    {
        int FirstLineOfPage = (p * ShownLines);
        int FirstCharOfPage = richTextBox1.GetFirstCharIndexFromLine(FirstLineOfPage);

        int FirstLineOfNextPage = (p + 1) * ShownLines;
        FirstLineOfNextPage = (FirstLineOfNextPage > TotalLines) ? TotalLines : FirstLineOfNextPage;
        int LastCharOfPage = (FirstLineOfNextPage < TotalLines)
                           ? richTextBox1.GetFirstCharIndexFromLine(FirstLineOfNextPage) - 1
                           : richTextBox1.Text.Length;
        Pages.Add(richTextBox1.Text.Substring(FirstCharOfPage, LastCharOfPage - FirstCharOfPage));
    }
}
else
{
    Pages.Add(Document);
}
richTextBox1.Text = Pages.First();



回答2:


I am not sure and I did not test the code but I hope it may help you, at least will give you an idea.

Convert your font size pt to px

Float points = 72; // each point in pixels 
Float fontSize = 12; // font size
Float dpi = 96; // find screen dpi (96 is very common I know)
Float px = fontsize * dpi / points; // each lines need px (exp: 16)

Find count of lines in your text (exp: 200 lines)

var lineCount = File.ReadAllLines(@"C:\file.txt").Length;
var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
    while (reader.ReadLine() != null)
    {
        lineCount++;
    }
}

We found line count and how many pixel needs for each line at step 1 and 2, so we can find delimiter positions for mark the text in related line

Float totalTextPixels = lineCount * px;
Float textFieldHeight = 200; // for example
Float eachSplitLine = totalTextPixels / textFieldHeight;

loop lines again

var lineCount = File.ReadAllLines(@"C:\file.txt").Length;
var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
    while (reader.ReadLine() != null)
    { 
        lineCount++;
        if(lineCount == eachSplitLine){
            // Put a deliminiter here (I don't know how)
            // for example | (pipe)
            lineCount = 0;
        }
    }
}

and split your text with |

I know it is not robust and prof. solution, this is only an idea...

Have good days.



来源:https://stackoverflow.com/questions/49942401/how-to-split-a-long-text-into-multiple-pieces-pages-to-fit-into-a-richtextbox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!