Проблема с производительностью при вычислении длины японского текста в событии TextChange RichTextBox - PullRequest
1 голос
/ 05 мая 2011

У меня есть собственный richtextbox, написанный на C # 2.0. Пользователь будет вводить японский текст в этом текстовом поле. Когда пользователь печатает, если размер текста превышает 300, дополнительные символы выделяются желтым цветом. Японский текст может содержать символы половинной ширины и полной ширины, и я хочу считать символ половинной ширины как размер «0.5» и символ полной ширины как размер «1».

Вот мой код ...

Dictionary<int, float> charSizes = new Dictionary<int, float>();

void HighlightingTextBox_TextChanged(object sender, EventArgs e)
{
    int index = this.SelectionStart;

    // Reset highlighting and font.
    HighlightText(0, this.BackColor, true);

    // Highlight Text

    float charCount = 0;
    int highlightIndex = 0;

    string currentText = this.Text;

    for (int k = 0; k < currentText.Length; k++)
    {
        int c = currentText[k];

        if (charCount <= CharacterLimit)
        {
            if (charSizes.ContainsKey(c)) // Use already calculated Size
                charCount = charCount + charSizes[c];
            else
            {
                // Check if character is Half width or Full Width
                string charString = currentText[k].ToString();
                string fullChar = Microsoft.VisualBasic.Strings.StrConv(charString, Microsoft.VisualBasic.VbStrConv.Wide, 1041);

                if (c == (int)fullChar[0])
                {
                    // Ascci value matches after converting to full width. So its Full width char.
                    charCount++;
                    charSizes[c] = 1;
                }
                else
                {
                    charCount = charCount + 0.5f;
                    charSizes[c] = 0.5f;
                }
            }

            highlightIndex++;
        }

        // Enforce "Arial" font for English characters in Japanese text
        this.Select(k, 1);
        this.SelectionFont = (c < 128) ? new Font("Arial", 9.5f) : this.Font;
        this.SelectionLength = 0;
    }

    if (charCount > CharacterLimit)        
        HighlightText(highlightIndex, HighlightColor, false);

    this.SelectionStart = index;
}


private void HighlightText(int selectionStart, Color highlightColor, bool enforceFont)
{
    this.Select(selectionStart, this.Text.Length);
    this.SelectionBackColor = highlightColor;

    if (enforceFont)
        this.SelectionFont = this.Font;

    this.SelectionLength = 0;
}

В чем проблема?

Этот код работает нормально для первых 8-10 символов. Но после этого он работает очень медленно (занимает много времени, так как проходит через «КАЖДЫЙ» символ текста). Если пользователь печатает быстро, для отображения новых символов в пользовательском интерфейсе требуется несколько секунд.

Как улучшить производительность в этом случае? Есть ли другой способ для этого расчета?

1 Ответ

1 голос
/ 05 мая 2011

Самый простой способ получить производительность в такой рутине: вычислять только то, что изменилось.

Просто сравните старый и новый текст, посмотрите, какие символы были добавлены или удалены, и измените итоговую сумму, основываясь только на них.

Вы никогда не рассчитываете больше одного за один раз таким образом.

- Кроме того, кэшируйте свой шрифт Arial 9.5 вместо того, чтобы каждый раз создавать новый.


Чтобы свести к минимуму обработку, мешающую вводу пользователя - обновляйте его только тогда, когда они приостанавливают заданный интервал.

    private Timer _timer = new System.Windows.Forms.Timer();
    private bool _processingText;
    public MyRichTextBox()
    {
        _timer = new Timer();
        _timer.Interval = 1000;
        _timer.Tick += new EventHandler(ProcessText);
    }


    protected override void OnTextChanged(EventArgs e)
    {
        if (_processingText == false)
        {
            _timer.Stop();
            _timer.Start();
        }
    }

    private void ProcessText(object sender, EventArgs e)
    {
        _processingText = true;
        _timer.Stop();

        // Insert your processing logic here

        _processingText = false;
    }
...